[*]
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:
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.
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.
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.