tkinter 线程通信

fle*_*bas 4 multithreading tkinter

我有代码应该显示 tkinter 小部件(注意:尚未实现)和另一个线程之间的通信。作为这两者之间的通信,我选择 python 队列。要查看真正发生的事情,控制台中会显示打印,这不是我所期望的。

如可以在控制台输出可以看出在睡眠时间后generate_text输出从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()
Run Code Online (Sandbox Code Playgroud)

输出:

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()
Run Code Online (Sandbox Code Playgroud)

pat*_*yts 8

@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()
Run Code Online (Sandbox Code Playgroud)


Him*_*mal 4

storage.get()是一个阻塞函数。root.after(500, process, message)在队列中有项目之前,它不会接到呼叫。

您可以使用storage.get_nowait()storage.get(False)来获得所需的行为。

关于队列的更多信息