在工作线程完成后,从主线程更新Tkinter小部件

时间:2017-10-17 11:12:59

标签: python multithreading python-2.7 tkinter

我需要在线程完成后更新GUI并从主线程调用此update_ui函数(可能是软件中断?)。工作线程如何在主线程中调用函数?

示例代码:

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()

我尝试使用Queue或两个线程都可访问的任何标志,但我必须等待/轮询以检查该值是否已更新,然后调用该函数 - 此等待使UI无响应。 e.g。

flag = True

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

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

1 个答案:

答案 0 :(得分: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()