如何设置tkinter文本变量在单独的线程上运行?



尝试更新在带有'main'函数变量的线程上运行的tkinter 'textvariable'。我实现了一个基于线程的解决方案,因此tkinter主循环后面的代码可以运行:https://stackoverflow.com/a/1835036/15409926.

请分享我如何解决这个错误。如果这不是更新'textvariable'最简单的方法,请分享其他方法。

代码:

from tkinter import *
from threading import Thread
class GUI(Thread):
def __init__(self):
Thread.__init__(self)
self.start()
def run(self):
self.root = Tk()
self.var = StringVar()
self.var.set("Initiated")
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
width = screen_width*.12
height = screen_height
x = screen_width - width
y = screen_height*.025
self.root.geometry('%dx%d+%d+%d' % (width, height, x, y))
label = Label(self.root, textvariable= self.var)
label.pack()
self.root.mainloop()
gui = GUI()
def main():
for i in range(1000):
gui.var.set(f'Current Iteration: {i}')
if __name__ == '__main__':
main()

窗口没有更新:Tkinter窗口显示初始'textvariable'

错误:

Traceback (most recent call last):
File "test.py", line 36, in <module>
main()
File "test.py", line 33, in main
gui.var.set(f'Current Iteration: {i}')
AttributeError: 'GUI' object has no attribute 'var'

大多数gui不喜欢在单独的线程中更改小部件的值。

你应该使用queue向线程发送值,并且应该使用root.after(time, function)定期运行从队列获取值并在GUI中更新值的功能。

import tkinter as tk  # PEP8: `import *` is not preferred
from threading import Thread
import queue
import time  # simulate show program
class GUI(Thread):

def __init__(self, queue):
super().__init__()
self.queue = queue
self.start()
def run(self):
self.root = tk.Tk()
self.var = tk.StringVar()
self.var.set("Initiated")
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
width = int(screen_width*.12)
height = int(screen_height)
x = int(screen_width - width)
y = int(screen_height*.025)
self.root.geometry(f'{width}x{height}+{x}+{y}')
label = tk.Label(self.root, textvariable=self.var)
label.pack()

# run first time after 100ms (0.1 second)
self.root.after(100, self.check_queue)
self.root.mainloop()
def check_queue(self):
#if not self.queue.empty():
while not self.queue.empty():
i = self.queue.get()
self.var.set(f'Current Iteration: {i}')
# run again after 100ms (0.1 second)
self.root.after(100, self.check_queue)

def main():
q = queue.Queue()
gui = GUI(q)
for i in range(1000):
q.put(i)
# simulate show program
time.sleep(0.5)

if __name__ == '__main__':
main()

PEP 8——Python代码风格指南

最新更新