0

Is it possible to get the GUI to update variable 'a' to update in real time while 'thread2' increments the value?

import tkinter as tk
from threading import Thread
import time


a = 0  # global variable

def thread1(threadname):
    root = tk.Tk()
    w = tk.Label(root, text=a)
    w.pack()
    root.mainloop()


def thread2(threadname):
    global a
    while True:
        a += 1
        time.sleep(1)


thread1 = Thread( target=thread1, args=("Thread-1", ) )
thread2 = Thread( target=thread2, args=("Thread-2", ) )

thread1.start()
thread2.start()

If I create a loop and print 'a' I get the correct result.

def thread1(threadname):
    global a
    while True:
        print(a)
 #   root = tk.Tk()
 #   w = tk.Label(root, text=a)
 #   w.pack()
 #   root.mainloop()

Any help would be appreciated

2 Answers 2

1

When you create your label, that's not a "live" connection. That passes the current value of the variable a. You then enter your main loop, and that thread does nothing else until the application exits. You need to send the new value to a function that executes as part of the main thread, and that function will need access to the label.

This works:

import tkinter as tk
from threading import Thread
import time


class GUI(object):
    def __init__(self):
        self.a = 0 
        self.w = tk.Label(root, text=self.a)
        self.w.pack()
        thread2 = Thread( target=self.thread2, args=("Thread-2", ) )
        thread2.start()

    def thread2(self,threadname):
        while True:
            self.a += 1
            root.after_idle(self.update)
            time.sleep(1)

    def update(self):
        self.w.config(text=self.a)

root = tk.Tk()
gui = GUI()
root.mainloop()

It is possible to make a live connection using textvariable, but then you have to change the type of a to a tkinter.StringVariable. Check here: Update Tkinter Label from variable

Sign up to request clarification or add additional context in comments.

8 Comments

Just a quick question: Is .after_idle thread safe? I read that it's similar to .after but is it safe enough to use from multiple threads without warring about tkinter crashing?
The whole POINT of the after APIs is to force the passed function to be called in the main thread. It basically IS the thread synchronizer.
Well I hadn't seen anyone use after_idle and I assumed after is to avoid the window freezing/becoming unresponsive when using time.sleep
@TimRoberts Sorry, I'm definitely a python noob. Reading through the tkinter docs, I was under the impression that the program loops between the Tk() and the mainloop() indefinitely, updating each iteration. I guess that's what I don't understand is why the print command works, but my method doesn't Trying to use this as a learning experience for the future. When I can get to an IDE I'll try your technique.
@Dan The <tkinter.Tk>.mainloop() updates the window, handles all incomming events to their respective binded functions and handles all .after and .after_idle scripts. So actually inside the mainloop there is code that calls the function that is passed into after_idle in this case and after in my answer.
|
0

Try using a <tkinter.Tk>.after loop like this:

import tkinter as tk

def loop():
    global a
    a += 1
    label.config(text=a)
    # run `loop` again in 1000 ms
    root.after(1000, loop)

a = 0
root = tk.Tk()
label = tk.Label(root, text=a)
label.pack()
loop() # Start the loop
root.mainloop()

I used a .after script because tkinter and threading don't go together very well. Sometimes tkinter can crash without even giving you an error message if you try to call some tkinter commands from the second thread.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.