如何从不同线程的事件更新 Gtk.TextView?
How can I update a Gtk.TextView from events from a different thread?
在一个单独的线程中,我检查 pySerial 缓冲区(无限循环)中的信息。如果有新信息可用,我想在 Gtk.TextView
中显示该输入。在对这个主题进行谷歌搜索后,发现在线程中执行 Gtk -Stuff 是一个杀手。会出现随机错误等等,这也是我运行遇到的问题。
我决定使用队列将线程与 GUI 同步。将信息放入队列非常简单,但是如果队列中有任何条目,我该如何检查主循环呢?
某种事件会很好,如果有任何新信息可用就会触发。
有这样的吗?也许存在将自定义 python 代码实现到 GTK3+ 主循环中的函数?
找到解决方案:
GObject.timeout_add
http://www.pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--timeout-add
此 GObject 函数每 X 毫秒执行一次对自己函数的回调。在这里找到了一个简单的解释:
https://gist.github.com/jampola/473e963cff3d4ae96707
所以我可以每 X 毫秒处理从队列中收集的所有信息。处理线程的好方法!
要通过线程中的事件成功地定期更新 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 中猴子的更新数量:
......
#!/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()
在一个单独的线程中,我检查 pySerial 缓冲区(无限循环)中的信息。如果有新信息可用,我想在 Gtk.TextView
中显示该输入。在对这个主题进行谷歌搜索后,发现在线程中执行 Gtk -Stuff 是一个杀手。会出现随机错误等等,这也是我运行遇到的问题。
我决定使用队列将线程与 GUI 同步。将信息放入队列非常简单,但是如果队列中有任何条目,我该如何检查主循环呢?
某种事件会很好,如果有任何新信息可用就会触发。
有这样的吗?也许存在将自定义 python 代码实现到 GTK3+ 主循环中的函数?
找到解决方案:
GObject.timeout_add
http://www.pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--timeout-add
此 GObject 函数每 X 毫秒执行一次对自己函数的回调。在这里找到了一个简单的解释:
https://gist.github.com/jampola/473e963cff3d4ae96707
所以我可以每 X 毫秒处理从队列中收集的所有信息。处理线程的好方法!
要通过线程中的事件成功地定期更新 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 中猴子的更新数量:
#!/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()