我有一个使用 GtkTextView 和 GtkTextBuffer 的应用程序。 使用以下 python 代码将行添加到缓冲区中,该代码在与主进程不同的线程中运行:
while True:
if aLogQueue.qsize() > 0:
aBuffer = aLogTextView.get_buffer()
try:
newLogMessage = aLogQueue.get_nowait()
ipri = int(newLogMessage[0])
if(ipri>=self.ListenLogMinPr):
aniter = aBuffer.get_iter_at_line(0)
aBuffer.insert(aniter, newLogMessage)
#mark = aBuffer.get_mark('insert')
#aniter = aBuffer.get_iter_at_mark(mark)
#aBuffer.place_cursor(aniter)
pass
except:
print('threw exception in message loop')
self.gui_shutdown()
aLogQueue 是单行 ASCII 文本消息的队列。
应用程序工作了一段时间,但随后总是崩溃并出现以下错误
Gtk:ERROR:gtktextview.c:4328:gtk_text_view_validate_onscreen: 断言失败:(>onscreen_validated)
请注意,我在第 0 行插入,因此迭代器入调用销毁的事实应该没有影响。
它在失败之前写入 20 到 200 行。 它似乎与注销文本缓冲区的边缘无关,并且滚动条在预期时出现。
有什么建议吗?
你不能从单独的线程访问 GtkTextBuffer 或 GTK+ 的任何部分。您必须从 GUI 线程访问它。您需要使用 GLib.idle_add()
在 GUI 线程上对缓冲区更新进行排队。
我为 GLib 找到的文档感到困惑GLib.idle_add因为不接受超时。 http://lazka.github.io/pgi-docs/index.html#GLib-2.0/functions.html#GLib.idle_add
但是没有超时,它使用 Python 2.7.12 和 Gtk 3.20 对我有用
为文本插入创建一个函数:
def set_text(self, text):
textbuffer = self.textview.get_buffer()
textbuffer.set_text(text, len(text))
def append_text(self, text:
oldtext = self.get_text()
newtext = "{}n{}".format(oldtext, text)
self.set_text(newtext)
然后,您可以使用以下内容设置新文本:
GLib.idle_add(self.textbox.append_text, "I am the new text line)
附加信息:
在脚本运行时,我还使用以下命令检查按钮的灵敏度:
def on_search_button_clicked(self, widget)
widget.set_sensitive(False)
thread = Thread(target=self.run_search_script)
thread.start()
GObject.timeout_add(200, self.sensi, thread, widget)
def sensi(self, thread, widget):
return True if thread.is_alive() else widget.set_sensitive(True)