简体   繁体   English

tkinter:如何使用队列从另一个线程更新 Treeview 项目?

[英]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.

相关问题 从另一个线程更新 Tkinter UI - Update Tkinter UI from another thread Tkinter - 使用单击而不是双击从 Treeview 中选择一个项目(回调 Treeview 项目选择) - Tkinter - Selecting an item from a Treeview using single click instead of double click (Callback on Treeview item selection) 如何将从一个树视图中选择的项目插入到另一个树视图 - How to insert item selected from one treeview to another treeview 如何仅从Tkinter TreeView更新选定的sqlite3记录 - How to update only selected sqlite3 record from tkinter treeview 使用其ID获取Treeview项目的文本-Treeview Tkinter - Get the text of a treeview item using it's Id - Treeview Tkinter 使用另一个队列作为ADT从队列中删除第二项 - Removing 2nd item from a queue, using another queue as an ADT 如何从另一个线程中的 Flask 应用程序更新 tkinter window 中的进度条值? - How to update the progress bar value in a tkinter window from a Flask application which is in another thread? 如何根据在另一个线程中运行的代码的结果更新 tkinter gui? - How to get tkinter gui to update based off of results from code running in another thread? 如何使用 Python 从 TKinter 的 Treeview 的列中获取所有值 - How to get all values from a column in Treeview in TKinter using Python Python Tkinter,如何在Tkinter ZD8A2ACE034EBEA5A81184EBA8B78919F51A600DZ中获取项目的子项? - Python Tkinter, How do I get the subitems of an Item in Tkinter TreeView?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM