2017-10-17 35 views
1

線程完成後我需要更新GUI並從主線程調用此update_ui函數(如軟件中斷也許?)。工作線程如何在主線程中調用一個函數?在工作線程完成後從主線程更新Tkinter小部件

示例代碼:

def thread(): 
    ...some long task 
    update_ui() #But call this in main thread somehow 

def main(): 
    start_new_thread(thread) 
    ...other functionality 

def update_ui(): 
    Tkinter_widget.update() 

我試圖用隊列或兩個線程訪問的任何標誌,但我必須不斷等待/民意調查,以檢查是否值已更新,然後調用函數 - 此等待使UI無響應。例如

flag = True 

def thread(): 
    ...some long task 
    flag = False 

def main(): 
    start_new_thread(thread) 
    while(flag): sleep(1) 
    update_ui() 
    ...other functionality 

回答

1

您的代碼似乎有些假設。這裏有一些完成了你所描述的事情。它創建三個標籤並初始化他們的文本。然後它啓動三個線程。每個線程在一段時間後更新與主線程中創建的標籤相關的tkinter變量。現在如果主線程真的需要更新,排隊確實有效,但是必須修改程序來完成更新。

import threading 
import time 
from tkinter import * 
import queue 
import sys 

def createGUI(master, widget_var): 
    for i in range(3): 
     Label(master, textvariable=widget_var[i]).grid(row=i, column=0) 
     widget_var[i].set("Thread " + str(i) + " started") 

def sometask(thread_id, delay, queue): 
    print("Delaying", delay) 
    time.sleep(delay) 
    tdict = {'id': thread_id, 'message': 'success'} 
    # You can put simple strings/ints, whatever in the queue instead 
    queue.put(tdict) 
    return 

def updateGUI(master, q, widget_var, td): 
    if not q.empty(): 
     tdict = q.get() 
     widget_var[tdict['id']].set("Thread " + str(tdict['id']) + " completed with status: " + tdict['message']) 
     td.append(1) 
    if len(td) == 3: 
     print("All threads completed") 
     master.after(1000, timedExit) 
    else: 
     master.after(100, lambda w=master,que=q,v=widget_var, tcount=td: updateGUI(w,que,v,td)) 

def timedExit(): 
    sys.exit() 

root = Tk() 
message_q = queue.Queue() 

widget_var = [] 
threads_done = [] 
for i in range(3): 
    v = StringVar() 
    widget_var.append(v) 
    t = threading.Thread(target=sometask, args=(i, 3 + i * 3, message_q)) 
    t.start() 

createGUI(root, widget_var) 
updateGUI(root,message_q, widget_var, threads_done) 
root.mainloop()