我的代码应该显示tkinter小部件(注意:尚未实现)和另一个线程之间的通信。由于这两者之间的通信我选择python队列。要查看真正发生的事情,打印机会在控制台中显示,而这并不是我所期望的。
从generate_text
的{{1}}输出中的睡眠时间显示后,可以在控制台输出中看到。我期望的是,process
慢于generate_text
我会看到更多process
然后process is called
,但这种情况不会发生。
Item x
输出:
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()
答案 0 :(得分:3)
@ Himal的答案对于当前的问题是正确的,但是您可能希望修改它以在消息生成代码中使用event_generate
并让UI在事件被提升时响应事件而不是轮询像这样的队列。您可以使用root.event_generate('<<MessageQueued>>')
功能中的generate_text
将虚拟事件放置到Tk的事件队列中。这是线程安全的,直接调用窗口方法不是。如果还在UI代码上添加了对此虚拟事件的绑定,则Tk消息循环在接收到虚拟事件时调用绑定函数。没有更多的民意调查。
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()
答案 1 :(得分:2)
storage.get()
是阻止功能。它不会到达root.after(500, process, message)
来电,直到队列中有一个项目为止。
您可以使用storage.get_nowait()
或storage.get(False)
来获得所需的行为。