Reputation: 189
How to make tkinter execution in function fix()
wait till label's
text get chnaged and then print end
.
Current working: When I click the sub
button, new thread gets created and for
loop gets executed. After 10000000 loops, my label would change to 9999999
. But before my label changes, tkinter prints end
.
I tried t.join()
, but it freezes the GUI.
import tkinter as tk
from tkinter import ttk
import threading
root = tk.Tk()
label = tk.Label(text='vinoth')
label.pack()
def fix():
a=0
t = threading.Thread(target=count, args=(a,))
t.start()
#t.join()
print('end')
def count(a):
for i in range(0,10000000):
a=i
label['text'] = a
button = tk.Button(text='sub', command=fix)
button.pack()
dropdown = ttk.Combobox()
dropdown.pack()
root.mainloop()
Upvotes: 3
Views: 4678
Reputation: 123423
You have to be careful multithreading tkinter
applications because the interface to tcl/tk doesn't doesn't support it. That means only the main thread can make calls to tkinter
and its widgets.
That said, you can workaround the limitation by using the universal after()
method to schedule a function to run periodically and communicate with the thread, either through thread-safe mechanisms like a Queue
or via global variables coupled with a Lock
to control concurrent access to it or them.
Here's an example of using the latter to do what you're trying to accomplish:
import tkinter as tk
from tkinter import ttk
import threading
POLLING_DELAY = 250 # ms
lock = threading.Lock() # Lock for shared resources.
finished = False
root = tk.Tk()
label = tk.Label(text='vinoth')
label.pack()
def fix():
global finished
with lock:
finished = False
t = threading.Thread(target=count)
t.daemon = True
root.after(POLLING_DELAY, check_status) # Start polling.
t.start()
def check_status():
with lock:
if not finished:
root.after(POLLING_DELAY, check_status) # Keep polling.
else:
print('end')
def count():
global finished
for i in range(10000000):
a = i
with lock:
finished = True
label['text'] = a
button = tk.Button(text='sub', command=fix)
button.pack()
dropdown = ttk.Combobox()
dropdown.pack()
root.mainloop()
Upvotes: 5
Reputation: 491
I gave this a try by using root.update()
function in a while loop. Not sure if this is a right away to do things! But posting the code anyway:
import tkinter as tk
from tkinter import ttk
import threading
root = tk.Tk()
class test():
def __init__(self):
self.label = tk.Label(text='vicks')
self.label.pack()
button = tk.Button(text='sub', command=self.fix)
button.pack()
dropdown = ttk.Combobox()
dropdown.pack()
def fix(self):
self.finished = False
t = threading.Thread(target=self.count)
t.daemon = True
t.start()
self.check_status()
print('end')
def check_status(self):
while self.finished is False: #keeps running until the variable finished becomes True
root.update()
def count(self):
a=0
for i in range(100000000):
a = i
self.label['text'] = a
self.finished = True
c = test()
root.mainloop()
Upvotes: 2