I have code that should show communication between tkinter widget (NOTE: not implemented yet) and another thread. As communication between those two I choose python queue. To see what is really happening print is shown in console and it's not what I would expect.
As can be seen in console output after sleep time in generate_text
output from process
is shown. What I expected is that as generate_text
is slower then process
I would see a lot more process is called
then Item x
, but this is not happening.
import tkinter as tk
import threading
import queue
import time
def generate_text(storage):
count = 0
while True:
message = "Item {}".format(count)
storage.put(message)
print(message)
count +=1
time.sleep(3000/1000)
def process(storage):
print("process is called")
try:
storage.get()
except queue.Empty:
print("queue empty")
# register awake function
root.after(500, process, message)
# init variables
message = queue.Queue()
root = tk.Tk()
t = threading.Thread(target=generate_text, args=(message,))
t.setDaemon(True)
t.start()
root.after(500, process, message)
root.mainloop()
Output:
Item 0
process is called
process is called
Item 1
process is called
Item 2
process is called
Item 3
process is called...
Desired output:
Item 0
process is called
process is called
process is called
process is called
process is called
process is called
Item 1
@Himal's answer is correct for the current question however you might want to amend this to use event_generate
in the message generating code and have the UI respond to the events when they are raised rather than polling the queue like this. You can use root.event_generate('<<MessageQueued>>')
in the generate_text
fuction to place a virtual event onto Tk's event queue. This is thread safe where calling window methods directly is not. If you also add a binding to this virtual event on the UI code then the Tk message loop with call the bound function when it receives the virtual event. No more polling.
import tkinter as tk
import threading
import queue
import time
def generate_text(mainwin, storage):
count = 0
while True:
message = "Item {}".format(count)
storage.put(message)
print("Queued {0}".format(message))
count += 1
mainwin.event_generate('<<MessageGenerated>>')
time.sleep(3000/1000)
def process(storage, event):
msg = storage.get()
print("New message: {0}".format(msg))
def main():
message_queue = queue.Queue()
root = tk.Tk()
root.bind('<<MessageGenerated>>', lambda e: process(message_queue, e))
t = threading.Thread(target=generate_text, args=(root, message_queue,))
t.setDaemon(True)
t.start()
root.mainloop()
if __name__ == '__main__':
main()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With