I’m currently making a GUI for a python program, and am using TKinter in an OOP fashion. I have a root class which creates a window and creates an array of all frames in the program, where each frame is a child class, and a method ‘show_frame’ which when called will update the window to show the frame passed as an argument. However I am having issues calling the show_frame method within methods of child classes, I was wondering if this is possible?
The root class:
from tkinter import *
from tkinter import ttk
class rootClass(Tk):
def __init__(self):
Tk.__init__(self)
window = Frame(self)
self.title("Application")
window.pack(side="top", fill="both", expand=True)
window.grid_rowconfigure(0, weight = 1)
window.grid_columnconfigure(0, weight = 1)
self.frames = {}
pagesTuple = (firstPage, secondPage, thirdPage)
for F in pagesTuple:
frame = F(window, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky ="NSEW")
self.show_frame(firstPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
The first child class:
class firstPage(Frame):
def newPageMethod(self, controller, newPage):
print("newPageMethod executed")
controller.show_frame(newPage)
def __init__(self, parent, controller):
super().__init__(parent)
titleLabel = Label(self, text ="firstPage")
titleLabel.grid(row = 0, column = 1, padx = 10, pady = 10)
loginButton = Button(self, text ="go to second page", command = self.newPageMethod(controller, secondPage))
loginButton.grid(row = 1, column = 1, padx = 10, pady = 10)
Second child class:
class secondPage(Frame):
def newPageMethod(self, controller, newPage):
print("newPageMethod executed")
controller.show_frame(newPage)
def __init__(self, parent, controller):
super().__init__(parent)
titleLabel = Label(self, text ="secondPage")
titleLabel.grid(row = 0, column = 1, padx = 10, pady = 10)
loginButton = Button(self, text ="go to third page", command = self.newPageMethod(controller, thirdPage))
loginButton.grid(row = 1, column = 1, padx = 10, pady = 10)
And so on. The error being returned is:
frame = self.frames[cont]
KeyError: <class '__main__.firstPage'>
>Solution :
The error comes from:
loginButton = Button(self, text ="go to second page", command = self.newPageMethod(controller, secondPage))
When creating the button, instead of passing self.newPageMethod as argument to Button you are calling the function.
Then the show_frame function is called and it tries to get the value from cont key before the key is even assigned:
for F in pagesTuple:
frame = F(window, self) # calls 'show_frame' before assigning the key
self.frames[F] = frame # assigning the key
frame.grid(row = 0, column = 0, sticky ="NSEW")
def show_frame(self, cont):
frame = self.frames[cont] # ---> error here
frame.tkraise()
That can be fixed using the lambda function:
loginButton = Button(self, text ="go to second page", command = lambda: self.newPageMethod(controller, secondPage))
And also here:
loginButton = Button(self, text ="go to third page", command = lambda: self.newPageMethod(controller, thirdPage))
And I am guessing that it should also be fixed in your other classes as well.