0

I am creating a password manager for my computer science coursework. I am using tkinter for the user interface and was wondering how to swap frames when a condition is met. self.logbtn = tk.Button(self,fg="red",command=self._login_btn_clicked) this is used to run the login btn module which checks the hashed value of the entered password and compared it to the stored hashed value in the text value.

def _login_btn_clicked(self):    #function to check the loging
    username = self.entry_username.get()        #get the values from the username entry
    password = self.entry_password.get()        #get the values from the password entry

    files = [f for f in os.listdir('.') if os.path.isfile(f)]       #lists all the files in the directory
    for f in files:         #iterates through the files
        if f==("%s.txt")%(username):        #checks for a file with the same name as the username since thats how it was stored
            hashedpassword = open(("%s.txt")%(username),"r").readlines()[4]     #open the file and reads line 4 which is where the hashed password is stored
            if hashedpassword ==(hashlib.md5(password.encode('utf-8')).hexdigest()):        #checks if the entered password is the same as the hashed password
                controller.show_frame(MainPage)
            else:   
                tm.showinfo("Error","Make sure you have entered the right credentials")

Where controller.show_frame(MainPage) it should show the new frame written in the class MainPage.

For switching inbetween the frame i am stacking the frames used in the method presented in. Switch between two frames in tkinter

the whole class goes as follow(including the class that handles the frame switching)

class PasswordManager(tk.Tk):
def __init__(self,*args, **kwargs):     #initialization class constantly running. Args= pass through variables kwargs=pass through libaries/dictionaries

    tk.Tk.__init__(self, *args, **kwargs)
    container=tk.Frame(self)

    container.pack(side="top", fill="both", expand=True)
    container.grid_rowconfigure(0,weight=1)
    container.grid_columnconfigure(0,weight=1)

    self.frames={}

    for F in (LoginPage, SignUpPage, MainPage):
        frame=F(container, self)
        self.frames[F]=frame
        frame.grid(row=0, column=0, sticky="nsew") 

    self.show_frame(LoginPage)

def show_frame(self, cont):

    frame=self.frames[cont]
    frame.tkraise()

class LoginPage(tk.Frame):      #The log in page
def __init__(self, parent, controller):    #__init__ makes sure that this class is accesibly to the whole program whenever
    tk.Frame.__init__(self,parent)
    self.controller=controller


    self.label_username = tk.Label(self, text="Username")       #label for the login page
    self.label_password = tk.Label(self, text="Password")

    self.entry_username = tk.Entry(self)                        #entrries for the login page
    self.entry_password = tk.Entry(self, show="*")              #show="*" is used to show that the entry only shows "*" instead of the password

    self.label_username.grid(row=0, sticky="e")                 #to place the labels and the entries i used the .grid module in tkinter
    self.label_password.grid(row=1, sticky="e")
    self.entry_username.grid(row=0, column=1)
    self.entry_password.grid(row=1, column=1)

    self.checkbox = tk.Checkbutton(self, text="Keep me logged in")   #tick box used to save the credentials/
    self.checkbox.grid(columnspan=2)

    self.logbtn = tk.Button(self, text="Login", fg="red",command=self._login_btn_clicked)    #when button pressed it runs the rountine _login_btn_clicked
    self.signbtn = tk.Button(self, text="Sign Up",fg="red",command=lambda: controller.show_frame(SignUpPage))     # controller is used to swap the frames 
    self.logbtn.grid(row=3, column=0)
    self.signbtn.grid(row=3, column=1)


def _login_btn_clicked(self):    #function to check the loging credentials
    username = self.entry_username.get()        #get the values from the username entry
    password = self.entry_password.get()        #get the values from the password entry

    files = [f for f in os.listdir('.') if os.path.isfile(f)]       #lists all the files in the directory
    for f in files:         #iterates through the files
        if f==("%s.txt")%(username):        #checks for a file with the same name as the username since thats how it was stored
            hashedpassword = open(("%s.txt")%(username),"r").readlines()[4]     #open the file and reads line 4 which is where the hashed password is stored
            if hashedpassword ==(hashlib.md5(password.encode('utf-8')).hexdigest()):        #checks if the entered password is the same as the hashed password
                print("Cheese")
                controller.show_frame(MainPage)
            else:   
                tm.showinfo("Error","Make sure you have entered the right credentials")
  • 1
    Going off what I can see in your example I think `controller` is the problem here. Without seeing more you probably need to use `self.controller` instead as your method will not be able to access `controller` without it being a class attribute or it being passed to the method. – Mike - SMT Nov 07 '18 at 17:20
  • Ill be sure to add more code – Murat Saglam Nov 07 '18 at 20:11
  • Please fix the indention on your code. Your `LoginPage` is missing the `__init__` method as well. – Mike - SMT Nov 07 '18 at 20:14
  • I couldnt get the classes to indent properly i hope this is enough though. – Murat Saglam Nov 07 '18 at 20:43
  • The easy way is to copy your code from your IDE and paste it directly into the editor. Then highlight all the code you just pasted in and click the code format button in the editor that looks like this: `{ }`. I have updated my answer let me know if you have any questions. – Mike - SMT Nov 07 '18 at 20:47

1 Answers1

0

Based on your updated question there are several things we need to fix.

First please be sure to use proper indention defined by the PEP8 style guidelines. This will make it much easier for others to read your code.

Next when you are defining a class that inherits from a widget you must define the __init__ method and the super.

Next because you need to interact with the method that raises frames we need to pass the main tkiner class to all of our frame classes. This way we can call the controller and show_frame method.

Here is a cleaned up version of your example. Let me know if you have any questions. Note I removed the password checking portion as I do not have hashlib.

import tkinter as tk

class PasswordManager(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        container = tk.Frame(self)
        container.grid(row=0, column=0, sticky="nsew")
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames={}
        for F in (LoginPage, SignUpPage, MainPage, MainPage):
            frame=F(container, self)
            self.frames[F]=frame
            frame.grid(row=0, column=0, sticky="nsew") 
        self.show_frame(LoginPage)

    def show_frame(self, cont):
        print("test")
        frame=self.frames[cont]
        frame.tkraise()

class LoginPage(tk.Frame):
    def __init__(self, container, controller):
        tk.Frame.__init__(self)
        self.controller = controller
        tk.Label(self, text="Username").grid(row=0, sticky="e")
        tk.Label(self, text="Password").grid(row=1, sticky="e")
        self.entry_username = tk.Entry(self)
        self.entry_password = tk.Entry(self, show="*")
        self.entry_username.grid(row=0, column=1)
        self.entry_password.grid(row=1, column=1)

        self.checkbox = tk.Checkbutton(self, text="Keep me logged in")
        self.checkbox.grid(columnspan=2)

        tk.Button(self, text="Login", fg="red", command=lambda: self.show_frame(MainPage)).grid(row=3, column=0)
        tk.Button(self, text="Sign Up", fg="red", command=lambda: self.show_frame(SignUpPage)).grid(row=3, column=1)

    def show_frame(self, frame):
        self.controller.show_frame(frame)

class SignUpPage(tk.Frame):
    def __init__(self, container, controller):
        tk.Frame.__init__(self)
        tk.Label(self, text="Sign Up Page").pack()

class MainPage(tk.Frame):
    def __init__(self, container, controller):
        tk.Frame.__init__(self)
        tk.Label(self, text="Main Page").pack()


PasswordManager().mainloop()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79