Reputation: 1001
I am still dabbling with the stacked frames set up for a tkinter app and fairly new to OOP and Tkinter. I have copied below code from another SO question and amended it slightly. What I do not get done: I want to update the label2 on the StartPage based on the click on Button2 on PageTwo from "Hello" to "5". But the update does not take place. What do I have to do differently to accomplish my task? Many thanks in advance
import tkinter as tk
TITLE_FONT = ("Helvetica", 18, "bold")
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.var = tk.StringVar()
self.var.set('Hello')
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 (StartPage, PageTwo):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
label2 = tk.Label(self, textvariable=self.controller.var, font=TITLE_FONT)
label2.pack(side="top", fill="x", pady=10)
label2.config(text=self.controller.var)
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button2.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
button2 = tk.Button(self, text="Change X",
command=lambda: self.calculate())
button2.pack()
def calculate(self):
self.controller.var = 5
return self.controller.var
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Upvotes: 0
Views: 145
Reputation: 386010
There are many ways to accomplish what you want. Since you are using a StringVar
for the label you want to change, the simplest solution is to update that variable with the new value:
def calculate(self):
self.controller.var.set(5)
This solution tightly couples the controller and the other class. That is, your PageTwo
must know that the controller associates a StringVar
with that label. If you modify the controller to use some other mechanism, you will have to change every other class that tries to set that variable.
A way to provide loose coupling is to have the controller provide an API for changing the value. In a sense, this is why controllers exist -- to control the flow of information between pages. The details of exactly how that value is stored and displayed is hidden from the other classes.
For example:
class SampleApp(...):
...
def set_label(self, value):
self.var.set(value)
class PageTwo(...):
...
def calculate(self):
self.controller.set_label(5)
The advantage to the above is that it provides loose coupling between the two classes. The other pages don't need to know that the label is implemented with a StringVar
or a Label
widget. The controller simply provides and interface that says "when you need to change variable X, call this function". As long as the controller maintains that function, you can change the implementation without having to modify every other class that may need to change that label.
See What is the difference between loose coupling and tight coupling in the object oriented paradigm? for more information about the difference between loose coupling and tight coupling.
Upvotes: 1