Gtk 在添加和删除列表框行时崩溃

问题描述

我想创建一个 Gtk 程序,它需要不断更新 ListBox,即添加删除行。我正在尝试这种方法。它可能更简洁,但这里的长度足以解释问题。

gi.require_version('Gtk','3.0')
from gi.repository import Gtk
from time import sleep
from threading import Thread

def add_widgets(listBox):

    # add 5 rows
    for _ in range(5):
        for _ in range(5):
            add_row(listBox)
        window.show_all()  # make the changes visible
        sleep(1)  # to make the change stay

        # remove all the rows
        for row in listBox.get_children():
            listBox.remove(row)
        window.show_all()
        sleep(1)
    
    # all the addition and removal done
    print('finished')

def add_row(listBox):
    listBoxrow = Gtk.ListBoxRow()
    label = Gtk.Label()
    label.set_text("hey There")
    listBoxrow.add(label)
    listBox.add(listBoxrow)

window = Gtk.Window()
window.connect('destroy',Gtk.main_quit)
listBox = Gtk.ListBox()
window.add(listBox)
window.show_all()

# Thread to add and remove rows
update_thread = Thread(target=add_widgets,args=(listBox,))
update_thread.start()

Gtk.main()

这段代码在 50% 的时间内运行良好。其余的,它给了我 3 种类型的错误,所有这些都是随机的。

  1. SegFault 中父循环的 2 或 3 次迭代后的旧 add_widgets
  2. 以下内容
**
Gtk:ERROR:../gtk/gtk/gtkcssnode.c:319:lookup_in_global_parent_cache: assertion Failed: (node->cache == NULL)
Bail out! Gtk:ERROR:../gtk/gtk/gtkcssnode.c:319:lookup_in_global_parent_cache: assertion Failed: (node->cache == NULL)
Aborted
  1. 最后一个不会使程序崩溃,而是添加随机行数。即它添加了 3(随机)行而不是 5 行,如指定的那样,或者可能根本没有行。

我尝试在适当的地方添加更多睡眠语句,因为最初,我想,这可能是因为更新小部件时窗口没有准备好。

我想知道它为什么会发生,我该如何解决

编辑:这可能与 UI 和线程同步有关,因为在与窗口交互时它(崩溃)发生得更频繁。例如,当您拖动它时,它更有可能崩溃。

解决方法

您不得从其他线程调用 GTK+ 代码。所有交互都必须在主线程中完成。这记录在 https://developer.gnome.org/gdk3/stable/gdk3-Threads.html 中。

如果您想对您的小部件进行一些“后台”更新,您可以使用 td (https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-idle-add)、g_idle_add() (https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-timeout-add) 等函数进行模拟及其他相关功能。