python - 如何从不同线程的事件更新 Gtk.TextView?

标签 python user-interface queue gtk3 python-multithreading

在一个单独的线程中,我检查 pySerial 缓冲区(无限循环)中的信息。如果有新信息可用,我想在 Gtk.TextView 中显示该输入。在对这个主题进行谷歌搜索后,发现在线程中执行 Gtk -Stuff 是一个 killer 。会出现随机错误等等,这也是我遇到的问题。

我决定使用队列来使线程与 GUI 同步。将信息放入队列非常简单,但是如果队列中有任何条目,我该如何检查主循环呢?

某种事件会很好,如果有任何新信息可用,它就会触发。

有这样的吗?也许存在将自定义 python 代码实现到 GTK3+ 主循环中的函数?

最佳答案

要通过线程中的事件成功地定期更新 GUI,我们不能简单地使用 threading 来启动第二个进程。正如您提到的,这会导致冲突。

这是 GObject 出现的地方,因为它被放在 this (slightly outdated) link 中。 :

call gobject.threads_init() at applicaiton initialization. Then you launch your threads normally, but make sure the threads never do any GUI tasks directly. Instead, you use gobject.idle_add to schedule GUI task to executed in the main thread

当我们将 gobject.threads_init() 替换为 GObject.threads_init() 并将 gobject.idle_add 替换为 GObject.idle_add( ),我们几乎已经有了关于如何在 Gtk 应用程序中运行线程的更新版本。一个简化的示例,在您的文本字段中显示越来越多的猴子。看代码中的注释:

例如,计算 TextView 中猴子的更新数量:

enter image description here ... enter image description here ... enter image description here

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
import time
from threading import Thread

class InterFace(Gtk.Window):

    def __init__(self):

        Gtk.Window.__init__(self, title="Test 123")

        maingrid = Gtk.Grid()
        maingrid.set_border_width(10)
        self.add(maingrid)

        scrolledwindow = Gtk.ScrolledWindow()
        scrolledwindow.set_hexpand(True)
        scrolledwindow.set_vexpand(True)
        scrolledwindow.set_min_content_height(50)
        scrolledwindow.set_min_content_width(150)
        maingrid.attach(scrolledwindow, 0,0,1,1)

        self.textfield = Gtk.TextView()
        self.textbuffer = self.textfield.get_buffer()
        self.textbuffer.set_text("Let's count monkeys")
        self.textfield.set_wrap_mode(Gtk.WrapMode.WORD)
        scrolledwindow.add(self.textfield)
        
        # 1. define the tread, updating your text
        self.update = Thread(target=self.counting_monkeys)
        # 2. Deamonize the thread to make it stop with the GUI
        self.update.setDaemon(True)
        # 3. Start the thread
        self.update.start()

    def counting_monkeys(self):
        # replace this with your thread to update the text
        n = 1
        while True:
            time.sleep(2)
            newtext = str(n)+" monkey" if n == 1 else str(n)+" monkeys"
            GObject.idle_add(
                self.textbuffer.set_text, newtext,
                priority=GObject.PRIORITY_DEFAULT
                )
            n += 1
        
def run_gui():
    window = InterFace()
    # 4. this is where we call GObject.threads_init()
    GObject.threads_init()
    window.show_all()
    Gtk.main()

run_gui()

关于python - 如何从不同线程的事件更新 Gtk.TextView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39556006/

相关文章:

python - Django上传视频并自动生成缩略图

python - 如果 None != 0 那么这个条件是如何通过的

jsf - p :message Not displaying in p:dialog

python - 检查是否在 PySpark 数据框中的组内找到值

javascript - Karate UI 中的 ShadowRoot dom 元素访问问题

javascript - 在哪里可以找到允许我禁用某些日期的 javascript 日历?

kubernetes - Kubernetes RabbitMQ队列镜像

php - 按日期订购特定 ID - 只取出一个(队列系统)

multithreading - 优先级队列的现实示例是什么?

python - 使用 gevent-socketio 和 Socket.IO.js 的 Python 瓶微框架的最小示例