Tkinter GUI, I/O & Threading: When to use queues, when events?
So I did it like this but I do not know if it fits to you or if this is a good way to do this, but it safes you the .after
as stated in the comments, which has the benefit that your function do_stuff
is just called when needed.
import tkinter as tk
import time
import threading
def get_data():
time.sleep(3)
print('sleeped 3')
_check.set(1)
def do_stuff():
try:
root.configure(bg='#'+str(_var.get()))
_var.set(_var.get()+101010)
except:
_var.set(101010)
root = tk.Tk()
_check = tk.IntVar(value=0)
_var = tk.IntVar(value=101010)
def callback(event=None, *args):
t1 = threading.Thread(target=get_data)
t1.start()
do_stuff()
_check.trace_add('write', callback) #kepp track of that variable and trigger callback if changed
callback() # start the loop
root.mainloop()
Some research:
[The Tcl]
interpreter is only valid in the thread that created it, and all Tk activity must happen in this thread, also. That means that the mainloop must be invoked in the thread that created the interpreter. Invoking commands from other threads is possible; _tkinter will queue an event for the interpreter thread, which will then execute the command and pass back the result.
#l1493 var_invoke
The current thread is not the interpreter thread. Marshal
the call to the interpreter thread, then wait for
completion. */
if (!WaitForMainloop(self))
return NULL;
is-it-safe-to-use-a-intvar-doublevar-in-a-python-thread
When you set a variable, it calls the globalsetvar method on the master widget associated with the Variable. The _tk.globalsetvar method is implemented in C, and internally calls var_invoke, which internally calls WaitForMainLoop, which will attempt schedule the command for execution in the main thread, as described in the quote from the _tkinter source I included above.
wiki.tcl
Start
|
|<----------------------------------------------------------+
v ^
Do I have No[*] Calculate how Sleep for at |
work to do? -----> long I may sleep -----> most that much --->|
| time |
| Yes |
| |
v |
Do one callback |
| |
+-----------------------------------------------------------+
Commonsense
from bugtracker:
Tkinter and threads.
If you want to use both tkinter and threads, the safest method is to make all tkinter calls in the main thread. If worker threads generate data needed for tkinter calls, use a queue.Queue to send the data to the main thread. For a clean shutdown, add a method to wait for threads to stop and have it called when the window close button [X] is pressed.
effbot
Just run all UI code in the main thread, and let the writers write to a Queue object; e.g.
Conclusion
The Way you did it and the way I did it dosent seem like the ideal but they seem not wrong at all. It depends on what is needed.