在tkinter中,你可以使用event_generate从后台线程向GUI线程提交事件。这允许你更新小部件而不会出现线程错误。
1.在主线程中创建tkinter对象。
2.将root绑定到虚拟事件(即<>),指定一个事件处理程序。事件名称中需要使用尖括号。
3.启动后台线程。
4.在后台线程中使用event_generate触发主线程中的事件。使用state属性传递数据(数字)到事件。
5.在事件处理程序中处理事件。
以下是一个示例:
from tkinter import *
import datetime
import threading
import time
root = Tk()
root.title("Thread Test")
print('Main Thread', threading.get_ident())
def timecnt():
print('Timer Thread',threading.get_ident())
for x in range(10):
root.event_generate("<<event1>>", when="tail", state=123)
txtvar.set(' '*15 + str(x))
time.sleep(1)
def eventhandler(evt):
print('Event Thread',threading.get_ident())
print(evt.state)
string = datetime.datetime.now().strftime('%I:%M:%S %p')
lbl.config(text=string)
lbl = Label(root, text='Start')
lbl.place(x=0, y=0, relwidth=1, relheight=.5)
txtvar = StringVar()
txt = Entry(root, textvariable=txtvar)
txt.place(relx = 0.5, rely = 0.75, relwidth=.5, anchor = CENTER)
thd = threading.Thread(target=timecnt)
thd.daemon = True
thd.start()
root.bind("<<event1>>", eventhandler)
root.mainloop()
thd.join()
输出(注意主线程和事件线程是相同的)
Main Thread 5348
Timer Thread 33016
Event Thread 5348
......
我添加了一个Entry部件来测试能否从后台线程更新StringVar
。对我来说,这起作用了,但如果您喜欢,可以在事件处理程序中更新字符串。请注意,从多个后台线程更新字符串可能会成为问题,因此应该使用线程锁。
请注意,如果后台线程自行退出,则没有错误。如果在其退出之前关闭应用程序,则会看到“主线程”错误。