I went through a couple of posts about navigation between tkinter frames but didn't find those useful. I am trying to create an app. I have a LogIn Page and Home Page. I want to navigate between these two frames on the click event of submit button in the LogIn Page. I have used two functions in the event of click of submit button. I have done database connection also.
When the program is executed, it shows the LogIn Page.After entering the details when I click the submit button it shows attribute error.
Following is the code I executed.
import tkinter as tk
from tkinter import ttk
import mysql.connector
from tkinter import messagebox
class App(tk.Tk):
bg_img_path = "images\\bg9.png"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry("1500x750")
main_frame = tk.Frame(self, width=200, height=50, highlightbackground="black", highlightthickness=1,
background="#e6ffe6")
main_frame.pack(side='top', fill='both', expand='True')
main_frame.grid_rowconfigure(0, weight=1)
main_frame.grid_columnconfigure(0, weight=1)
self.bkgr_image = tk.PhotoImage(file=self.bg_img_path)
self.frames = {}
for F in (LoginPage,HomePage):
page_name = F.__name__
frame = F(main_frame, self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(LoginPage)
def show_frame(self, container):
frame = self.frames[container]
frame.tkraise()
class BasePage(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
label_bkgr = tk.Label(self, image=controller.bkgr_image)
label_bkgr.place(x=0, y=0)
class LoginPage(BasePage,tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent, controller)
login_frame = tk.Frame(self, width=200, height=50, highlightbackground="black", highlightthickness=1,
background="#e6ffe6")
login_frame.grid(row=400, column=20, padx=500, pady=250)
self.label_title = tk.Label(login_frame, text="Log In", font=("Helvetica", 40), bg="#e6ffe6")
self.label_title.grid(row=0, column=20, padx=10, pady=10)
self.label_username = tk.Label(login_frame, text="Username", font=("Helvetica", 20), bg="#e6ffe6")
self.label_username.grid(row=50, column=20, padx=10, pady=10)
self.entry_username = tk.Entry(login_frame, width=15, font=("Helvetica", 20))
self.entry_username.grid(row=50, column=30, padx=10, pady=10)
self.label_password = tk.Label(login_frame, text="Password", font=("Helvetica", 20), bg="#e6ffe6")
self.label_password.grid(row=60, column=20, padx=10, pady=10)
self.entry_password = tk.Entry(login_frame, width=15, font=("Helvetica", 20))
self.entry_password.grid(row=60, column=30, padx=10, pady=10)
self.login_button = tk.Button(login_frame, text="Log In", command=lambda: [self.submit,App.show_frame(self,HomePage)], font=("Helvetica", 20),
bg="#e6ffe6")
self.login_button.grid(row=70, column=25, padx=10, pady=10)
def submit(self):
self.u_name = self.entry_username.get()
self.p_word = self.entry_password.get()
employee = mysql.connector.connect(host="localhost", user="root", password="", database="edatabase")
cursor_variable = employee.cursor()
cursor_variable.execute("INSERT INTO login VALUES ('" + self.u_name + "','" + self.p_word + "')")
employee.commit()
employee.close()
messagebox.showinfo("Log In", "Succesfull")
class HomePage(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label1 = ttk.Label(self, text='Home', font=("Helvetica", 20))
label1.pack(padx=10, pady=10)
app = App()
app.mainloop()
The attribute error thrown is as follows:
C:\Users\write\AppData\Local\Programs\Python\Python39\python.exe "C:/Users/write/PycharmProjects/OOP trials/login_bg_img_trial2.py"
Traceback (most recent call last):
File "C:\Users\write\PycharmProjects\OOP trials\login_bg_img_trial2.py", line 97, in <module>
app = App()
File "C:\Users\write\PycharmProjects\OOP trials\login_bg_img_trial2.py", line 30, in __init__
self.show_frame(LoginPage)
File "C:\Users\write\PycharmProjects\OOP trials\login_bg_img_trial2.py", line 33, in show_frame
frame = self.frames[container]
KeyError: <class '__main__.LoginPage'>
Process finished with exit code 1
Any help is appreciated.
In your App.__init__
change:
self.show_frame(LoginPage)
to
self.show_frame("LoginPage")
The dictionary that you have (self.frames
) contains the frame name as the key and the frame instance as the value.
Also add self.controller = controller
to BasePage.__init__
so you can keep a reference to the controller
.
That will allow you to change the
self.login_button = tk.Button(..., command=lambda: [..., App.show_frame(self,HomePage)])
into:
self.login_button = tk.Button(..., command=lambda: [..., self.controller.show_frame("HomePage")])
That should fix all of the problems
Please note that as @Atlas435 said you don't need the tk.Frame
from the class LoginPage(BasePage,tk.Frame)
. Also using a list inside a lambda to execute functions is unpythonic. It's easer to just define a new function.