[英]tkinter: How to update Treeview item from another thread using queue?
I'm trying to learn about object oriented python and using tkinter with threading.我正在尝试了解面向 object 的 python 并使用 tkinter 和线程。 I've read a ton of SO questions and other various resources online.
我已经在线阅读了大量的 SO 问题和其他各种资源。 I've been able to work out most of it, but I'm a little lost on how to update a Treeview item from another thread.
我已经能够解决大部分问题,但我对如何从另一个线程更新 Treeview 项目有点迷茫。 I have not been able to find something that illustrates this in a way I could understand.
我无法找到以我能理解的方式说明这一点的东西。
I've read that tkinter must run in the main thread and you cannot update it from another thread, so I need to use a queue to pass things to it.我读过 tkinter 必须在主线程中运行,并且您不能从另一个线程更新它,所以我需要使用队列将内容传递给它。
The following code works, although it's probably not the best way to do things.以下代码有效,尽管它可能不是最好的方法。 Any improvements are definitely welcomed, but the main thing I'm posting for is the Treeview question.
任何改进都绝对受欢迎,但我要发布的主要内容是 Treeview 问题。
In the examples I see, people usually just use a random number generator or something to pass ints via the queue to demonstrate something simple.在我看到的示例中,人们通常只是使用随机数生成器或其他东西通过队列传递整数来演示一些简单的东西。 I understand this, but how can I use the queue to pass and run an actual command or otherwise update the Treeview item that sits in the main thread?
我明白这一点,但是我如何使用队列来传递和运行实际命令或以其他方式更新位于主线程中的 Treeview 项目?
If not for being in another thread, I would use something like: tv_files.item('File1', values=('tst1', 'tst2'))
如果不是在另一个线程中,我会使用类似的东西:
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()
You seem to have the basics down.你似乎已经掌握了基础知识。 Just add items to the queue that you can unpack and insert into the tree.
只需将项目添加到您可以解包并插入树的队列中。
For example, you can add a dictionary onto the queue:例如,您可以将字典添加到队列中:
def work():
time.sleep(3)
message = {
"id": "File1",
"values": ('tst1', 'tst2')
}
tk_thread.send_message_to_ui(message)
In the event handler, you can pull the data out of the message and insert it into the tree:在事件处理程序中,您可以从消息中提取数据并将其插入树中:
def process_message_queue(self, event):
while self.message_queue.empty() is False:
message = self.message_queue.get(block=False)
self.tv_files.insert(message['id'], "end", values=message['values'])
If you want to get really fancy, you could pass the name of the function, args, and kwargs so that your thread can do just about anything in the GUI:如果你想变得非常花哨,你可以传递 function、args 和 kwargs 的名称,这样你的线程就可以在 GUI 中做任何事情:
Sending the message:发送消息:
def work():
time.sleep(3)
message = {
"attr": "tv_files",
"method": "insert",
"args": ("File1", "end"),
"kwargs": {
"values": ['tst1', 'tst2']
},
}
tk_thread.send_message_to_ui(message)
Processing the message:处理消息:
def process_message_queue(self, event):
while self.message_queue.empty() is False:
message = self.message_queue.get(block=False)
attr = getattr(self, message['attr'])
method = getattr(attr, message['method'])
method(*message['args'], **message['kwargs'])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.