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()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


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: An image and label are not appearing. emont 7 410 Mar-21-2024, 03:00 PM
Last Post: deanhystad
  tkinter destroy label inside labelFrame Nick_tkinter 3 4,482 Sep-17-2023, 03:38 PM
Last Post: munirashraf9821
  [Tkinter] Updating Tkinter label using multiprocessing Agusms 6 3,054 Aug-15-2022, 07:10 PM
Last Post: menator01
  [Tkinter] The Text in the Label widget Tkinter cuts off the Long text in the view malmustafa 4 4,674 Jun-26-2022, 06:26 PM
Last Post: menator01
  [Tkinter] Trouble changing Font within tkinter frame title AnotherSam 1 4,012 Sep-30-2021, 05:57 PM
Last Post: menator01
  tkinter: Image to Label Maryan 10 5,124 Oct-29-2020, 01:48 PM
Last Post: joe_momma
  Tkinter - How can I extend a label widget? TurboC 2 2,736 Oct-13-2020, 12:15 PM
Last Post: zazas321
  Tkinter: How to assign calculated value to a Label LoneStar 7 3,759 Sep-03-2020, 08:19 PM
Last Post: LoneStar
  [Tkinter] Tkinter delete values in Entries, when I'm changing the Frame robertoCarlos 11 5,651 Jul-29-2020, 07:13 PM
Last Post: deanhystad
  [Tkinter] tkinter, dropdowns with changing options Sheepykins 4 9,705 Jul-03-2020, 06:06 AM
Last Post: jdos

Forum Jump:

User Panel Messages

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