Al_Iskander
Al_Iskander

Reputation: 1001

Tkinter updating labels in stacked frame windows

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

Answers (1)

Bryan Oakley
Bryan Oakley

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

Related Questions