我想我修复了这个错误,但我想确定我以正确的方式做了。我也不确定为什么会这样。
修复前的代码:
private Gee.ArrayList<Gtk.Widget> menuButtons;
// Some other code here
public override void remove (Gtk.Widget widget) {
if (widget in menuButtons) {
widget.unparent ();
menuButtons.remove ( widget ); // Look at this method call
if (this.get_visible () && widget.get_visible ()) {
this.queue_resize_no_redraw ();
}
}
}
该代码导致:
ERROR:arraylist.c:957:gee_array_list_real_get: assertion failed: (index < _size)
./run: line 3: 11054 Aborted (core dumped) ./bin
修复后的代码:
private Gee.ArrayList<Gtk.Widget> menuButtons;
// Some other code here
public override void remove (Gtk.Widget widget) {
if (widget in menuButtons) {
widget.unparent ();
if (this.get_visible () && widget.get_visible ()) {
this.queue_resize_no_redraw ();
menuButtons.remove ( widget ); // Moved method call here
}
}
}
现在它可以工作了,我不确定,但这可能与异步调用的删除方法有关,是吗?
有什么好的解释吗?这是问题的正确解决方法吗?
@After再次检查代码,我确信这不是我问题的正确解决方案,因为menuButtons.move(小部件(;在我的情况下永远不会被调用。小部件保留在列表中,这是不需要的行为。
MVCE:
MyContainer.vala
public class MyContainer : Gtk.Container {
// ArrayList for storing menu buttons
private Gee.ArrayList<Gtk.Widget> menuButtons;
public MyContainer () {
base.set_has_window (false);
menuButtons = new Gee.ArrayList<Gtk.Widget> ();
}
public override void add (Gtk.Widget widget) {
widget.set_parent (this);
menuButtons.add (widget);
}
public override void remove (Gtk.Widget widget) {
if (widget in menuButtons) {
widget.unparent ();
menuButtons.remove ( widget ); // After removing the widget from the List I get "assertion failed error"
if (this.get_visible () && widget.get_visible ()) {
this.queue_resize_no_redraw ();
}
}
}
public override void forall_internal (bool include_internals, Gtk.Callback callback) {
foreach (var widget in menuButtons) {
callback (widget);
}
}
}
SimpleGtkApplication.vala
public class SimpleGtkApplication : Gtk.Application {
public SimpleGtkApplication () {
Object (application_id: "simple.gtk.application", flags: ApplicationFlags.FLAGS_NONE);
}
protected override void activate () {
Gtk.ApplicationWindow window = new Gtk.ApplicationWindow (this);
window.set_default_size (800, 600);
window.title = "SimpleGtkApplication";
Gtk.Container container = new MyContainer ();
container.add ( new Gtk.Button.with_label ("Button 1") );
container.add ( new Gtk.Button.with_label ("Button 2") );
window.add ( container );
window.show_all ();
}
public static int main (string[] args) {
SimpleGtkApplication app = new SimpleGtkApplication ();
return app.run (args);
}
}
编译方式:--pkg=gtk+-3.0 --pkg=gee-0.8
几点:
- 你正在覆盖
Gtk.Container::remove
,但永远不会通过调用base.remove()
链接到父类的实现,从长远来看,这会给你带来问题。 - 在
MyContainer::remove
中,您正在调用widget.unparent()
,这可能会导致某种二次调用MyContainer::remove
。如果是这样,两次widget in menuButtons
测试的计算结果都为 true,但是当原始调用尝试从列表中删除小部件时,它已经消失了,因此断言失败。
DR:将调用widget.unparent()
替换为base.remove(widget)
。
PS:如果你也需要明确的this.queue_resize_no_redraw()
调用,我会感到非常惊讶,GTK+真的应该为你管理它。
正如Michael所写,你正在做很多Gtk可以为你自己做的事情。您也不会在重写中调用基方法。
您直接从Gtk.Container
派生,我已经调整了您的MVCE以使用Gtk.Box
代替,并且没有收到警告,也没有断言以下代码:
public class MyContainer : Gtk.Box {
private Gee.ArrayList<Gtk.Widget> menuButtons;
public MyContainer () {
menuButtons = new Gee.ArrayList<Gtk.Widget> ();
}
public override void add (Gtk.Widget widget) {
base.add (widget);
menuButtons.add (widget);
}
public override void remove (Gtk.Widget widget) {
if (widget in menuButtons) {
menuButtons.remove (widget);
}
base.remove (widget);
}
}