changing tkinter label from thread - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: changing tkinter label from thread (/thread-27417.html) |
changing tkinter label from thread - nanok66 - Jun-06-2020 Hi all, I am getting pretty far with my GUI but I have one major issue I cannot solve. I stripped down my program to the absolute bare minimum of my issue. I think the issue is that I cannot over write my tkinter label using a thread. The code fully runs. Just press "s" on your keyboard to start the thread. Upon opening the script, my tkinter Label correctly shows "initial words". Then I press "s" to start the thread, this prints the words "one" and "two" and calls the function changeState. Even though it prints correctly, changeState does not do it's job (to change the label text to "updated words"). I have no idea why!! import tkinter as tk import time from threading import Thread import keyboard class MainPage(tk.Frame): def __init__(self, *args, **kwargs): super().__init__(**kwargs) self.state_lbl = tk.Label(self, text="initial words") self.state_lbl.grid(row=0, column=0) def changeState(self): self.state_lbl['text'] = "updated words" # this line is not working! class MyFunctions: def one(self): print("one") # this line works fine main_instance = MainPage() # is this wrong? main_instance.changeState() # is this wrong? time.sleep(1) def two(self): print("two") # this line works fine time.sleep(1) class runCycle(Thread): def __init__(self): Thread.__init__(self) my = MyFunctions() self.twoFunctions = [my.one, my.two] def run(self): for func in self.twoFunctions: func() run_instance = runCycle() keyboard.add_hotkey('s', callback=run_instance.run) # keyboard "S" used to start program if __name__ == "__main__": root = tk.Tk() main = MainPage(root) main.grid() root.wm_geometry("600x300") root.mainloop() RE: changing tkinter label from thread - Yoriz - Jun-06-2020 The thread should not be called with the method run, it should be called with the method start. Inside the thread you have created a new instance of MainPage, the thread will need passing a reference to MainPage. When calling the GUI from a thread you need to use the method after or the GUI will lockup. I removed the use of keyboard as I don't have it installed. import tkinter as tk import time from threading import Thread class MainPage(tk.Frame): def __init__(self, *args, **kwargs): super().__init__(**kwargs) self.state_lbl = tk.Label(self, text="initial words") self.state_lbl.grid(row=0, column=0) def changeState(self, text): self.state_lbl['text'] = text class MyFunctions: def __init__(self, gui): self.gui = gui def one(self): time.sleep(5) print("one") self.gui.after(0, self.gui.changeState("updated words")) time.sleep(1) def two(self): print("two") time.sleep(1) self.gui.after(0, self.gui.changeState("updated words again")) class runCycle(Thread): def __init__(self, gui): Thread.__init__(self) my = MyFunctions(gui) self.twoFunctions = [my.one, my.two] def run(self): for func in self.twoFunctions: func() if __name__ == "__main__": root = tk.Tk() main = MainPage(root) main.grid() root.wm_geometry("600x300") run_instance = runCycle(main) run_instance.start() root.mainloop()Take a look at the following [Tkinter] How to deal with code that blocks the mainloop, freezing the gui RE: changing tkinter label from thread - menator01 - Jun-06-2020 Here is my example of changing label text #! /usr/bin/env python3 import tkinter as tk class ChangeText: def __init__(self, parent): self.parent = parent self.label = tk.Label(self.parent) self.label['text'] = 'Start Text' self.label.pack() self.update() def update(self): self.label['text'] = 'Updating in 10' self.i = 10 self.timer() def run_timer(self): if self.i >= 0: self.i -= 1 def timer(self): self.run_timer() if self.i >= 0: self.label.after(1000, self.timer) self.label['text'] = f'Updating in {self.i}' else: self.label['text'] = f'Done!' def main(): root = tk.Tk() root.geometry('400x300+100+100') root.title('Change Text') ChangeText(root) root.mainloop() if __name__ == '__main__': main() RE: changing tkinter label from thread - nanok66 - Jun-07-2020 Ok I knew I was missing a few fundamentals. I put in those changes and it's working! Thanks Yoriz! Appreciated as well menator01! |