Home > Software engineering >  Tkinter Click Button in One Window and Update Value in Another
Tkinter Click Button in One Window and Update Value in Another

Time:02-02

Python noob here. I'm building a basic sports scoreboard application that has two windows: one for the scoring console (contains all of the buttons needed to update the scoreboard's values) and one for the scoreboard itself.

I am able to open both windows from the main window with the click of the "Open System" button. Both of these are tk.TopLevel windows and I was under the impression that if both were TopLevel, I should be able to click the buttons to increment/decrement in one window and see the changes reflected in the other.

However, while I am able to click the buttons, I don't see the changes to the home and visitor values until I reload the TopLevel windows from the main window. How do I fix this?

import tkinter as tk

home: int = 0
visitor: int = 0


class ScoreViewer(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        global home, visitor
        self.geometry('800x800')
        self.title('Scoreboard')

        self.homeScoreLabel = tk.Label(self, text=home)
        self.visitorScoreLabel = tk.Label(self, text=visitor)

        self.homeScoreLabel.pack()
        self.visitorScoreLabel.pack()

        tk.Button(self, text='Close', command=self.destroy).pack(expand=True)


class ScoreConsole(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        global home, visitor
        self.geometry('800x800')
        self.title('Scoreboard')
        self.homeScorePlus = tk.Button(self, text="Home Score  ", command=lambda: self.changehomescore(1))
        self.homeScoreMinus = tk.Button(self, text="Home Score -", command=lambda: self.changehomescore(-1))
        self.visitorScorePlus = tk.Button(self, text="Visitor Score  ", command=lambda: self.changevisitorscore(1))
        self.visitorScoreMinus = tk.Button(self, text="Visitor Score -", command=lambda: self.changevisitorscore(-1))

        self.homeScorePlus.pack()
        self.homeScoreMinus.pack()
        self.visitorScorePlus.pack()
        self.visitorScoreMinus.pack()

        self.mainloop()

    def changehomescore(self, amount):
        global home, visitor
        if not (amount == -1 and home == 0):
            home = home   amount

    def changevisitorscore(self, amount):
        global home, visitor
        if not (amount == -1 and visitor == 0):
            visitor = visitor   amount


class ScoreSystem(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Console")
        self.geometry('500x500')

        tk.Button(self, text='Open System', command=self.opensystem).pack(expand=True)

    def opensystem(self):
        viewer = ScoreViewer(self)
        viewer.grab_set()
        console = ScoreConsole(self)
        console.grab_set()


if __name__ == "__main__":
    app = ScoreSystem()
    app.mainloop()

CodePudding user response:

You're just changing variable. For the new values to appear in a window you must reconfigure the window. You also are calling mainloop twice. You should only call it once for the entire program.

First, you need to save references to the windows so each window can interact with the other:

class ScoreSystem(tk.Tk):
    ...
    def opensystem(self):
        self.viewer = ScoreViewer(self)
        self.viewer.grab_set()
        self.console = ScoreConsole(self)
        self.console.grab_set()

Next, you need to save the self parameter that is passed to the two windows, so you can use them later on.

class ScoreConsole(tk.Toplevel):
    def __init__(self, parent):
        ...
        self.parent = parent
        ...

Finally, you need to directly update the score by referencing the other window via the parent attribute, and from there you can reference the label

class ScoreConsole(tk.Toplevel):
    ...
    def changehomescore(self, amount):
        global home, visitor
        if not (amount == -1 and home == 0):
            home = home   amount
            self.parent.viewer.homeScoreLabel.configure(text=home)

There are arguably better solutions, but this change requires the fewest lines of code. The takeaway here is that:

  • you have to give the console a way to access the viewer. In this case we know that "parent" refers to the main window and the main window has references to the other windows. You could also just pass the instance of the viewer to the console at some point.

  • you have to reconfigure the widget, you can't just update a normal python variable and expect a widget to know that it changed.

  •  Tags:  
  • Related