2017-08-13 86 views
0

我有代碼應該顯示tkinter小部件(注意:尚未實現)和另一個線程之間的通信。由於這兩者之間的溝通,我選擇了Python隊列。要查看實際發生的情況,在控制檯中會顯示print,這不是我所期望的。tkinter線程通信

可以看出在睡眠時間後的控制檯輸出generate_textprocess輸出顯示。我期望的是,因爲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
過程稱爲
過程稱爲
第1個
過程稱爲
第2個
過程稱爲
第3項
過程被稱爲...

希望的輸出: 項0
過程稱爲
過程稱爲
過程稱爲
過程稱爲
過程稱爲
過程稱爲
第1項

+0

不應該'root.after'函數調用(你'process'函數內部)使用'storage',而不是'message'? – Himal

+0

@即使使用'storage'變量而不是'message',日常行爲也是一樣的 – flebas

回答

1

storage.get()是一個阻塞功能。它將不會到達root.after(500, process, message)呼叫,直到有一個項目在隊列中。

您可以使用storage.get_nowait()storage.get(False)來獲得所需的行爲。

​​

3

@雪山的答案是當前問題的正確,但是你可能要修改本使用event_generate消息中生成代碼,並有事件的UI響應時,他們提出,而不是輪詢隊列喜歡這個。您可以在generate_text功能中使用root.event_generate('<<MessageQueued>>')將虛擬事件放置到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()