断言失败的方法:gee_array_list_real_get



我想我修复了这个错误,但我想确定我以正确的方式做了。我也不确定为什么会这样。

修复前的代码:

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

几点:

  1. 你正在覆盖Gtk.Container::remove,但永远不会通过调用base.remove()链接到父类的实现,从长远来看,这会给你带来问题。
  2. 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);
  }
}

最新更新