Python Forum
changing tkinter label from thread
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
changing tkinter label from thread
#1
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()
Reply
#2
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
Reply
#3
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()
Reply
#4
Ok I knew I was missing a few fundamentals. I put in those changes and it's working! Thanks Yoriz!

Appreciated as well menator01!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  tkinter: Image to Label Maryan 10 482 Oct-29-2020, 01:48 PM
Last Post: joe_momma
  Tkinter - How can I extend a label widget? TurboC 2 309 Oct-13-2020, 12:15 PM
Last Post: zazas321
  Tkinter: How to assign calculated value to a Label LoneStar 7 480 Sep-03-2020, 08:19 PM
Last Post: LoneStar
  [Tkinter] Tkinter delete values in Entries, when I'm changing the Frame robertoCarlos 11 738 Jul-29-2020, 07:13 PM
Last Post: deanhystad
  [Tkinter] tkinter, dropdowns with changing options Sheepykins 4 5,823 Jul-03-2020, 06:06 AM
Last Post: jdos
  [Tkinter] changing title text to bold in tkinter Kumarkv 2 1,555 May-09-2020, 10:41 PM
Last Post: Larz60+
  [Tkinter] tkinter How to pass label fiilename to another module? johnjh 0 558 Apr-17-2020, 11:34 PM
Last Post: johnjh
  Make Label Text background (default color) transparent using tkinter in python barry76 1 9,847 Nov-28-2019, 10:19 AM
Last Post: Larz60+
  Spacing Between two labels are very far and Top label is not in Center using Tkinter barry76 2 1,951 Jul-30-2019, 10:49 AM
Last Post: wuf
  Unable to update or refresh label text in tkinter jenkins43 3 2,905 Jul-24-2019, 02:09 PM
Last Post: Friend

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020