【发布时间】:2021-12-30 21:33:01
【问题描述】:
我正在尝试学习面向对象的 python 并使用带有线程的 tkinter。我已经在线阅读了大量的 SO 问题和其他各种资源。我已经能够解决大部分问题,但是我对如何从另一个线程更新 Treeview 项目有点迷茫。我一直找不到能以我能理解的方式说明这一点的东西。
我读过 tkinter 必须在主线程中运行,你不能从另一个线程更新它,所以我需要使用一个队列来传递东西给它。
以下代码有效,尽管它可能不是最好的方法。任何改进都绝对受欢迎,但我要发布的主要内容是 Treeview 问题。
在我看到的示例中,人们通常只是使用随机数生成器或其他东西通过队列传递整数来演示一些简单的东西。我明白这一点,但是如何使用队列来传递和运行实际命令或以其他方式更新位于主线程中的 Treeview 项?
如果不是在另一个线程中,我会使用类似的东西:
tv_files.item('File1', values=('tst1', 'tst2'))
import tkinter as tk
from tkinter import ttk
from threading import Thread
from queue import Queue
import time
class TkThread:
def __init__(self):
self.tk = tk.Tk()
self.message_queue = Queue()
self.message_event = '<<message>>'
self.tk.bind(self.message_event, self.process_message_queue)
def run_tk(self):
self.tk.title('My Window')
self.tv_files = ttk.Treeview(
self.tk,
columns=('Filename', 'Status'),
show='headings')
self.tv_files.pack(
side='top',
padx=10,
pady=10)
# Set up columns
self.tv_files.heading('#1', anchor='w', text='Filename')
self.tv_files.column('#1', anchor='w', width=150)
self.tv_files.heading('#2', anchor='w', text='Status')
self.tv_files.column('#2', anchor='w', width=150)
self.tv_files.insert('', 'end', id='File1', values=('File1', 'Status1'))
self.btn_run = ttk.Button(
self.tk,
text= 'Run',
compound='top',
command = run_thread)
self.btn_run.pack(
side='top',
padx=10,
pady=10)
self.tk.lift(); self.tk.mainloop()
def send_message_to_ui(self, message):
self.message_queue.put(message)
self.tk.event_generate(self.message_event, when='tail')
def process_message_queue(self, event):
while self.message_queue.empty() is False:
message = self.message_queue.get(block=False)
# process the message here
print(message)
def work():
time.sleep(3)
tk_thread.send_message_to_ui('Test Message')
def run_thread():
thread = Thread(target=work)
thread.start()
if __name__ == '__main__':
tk_thread = TkThread()
tk_thread.run_tk()
【问题讨论】:
标签: python tkinter python-multithreading