断言在方法失败:gee_array_list_real_get

时间:2017-03-24 23:32:35

标签: gtk runtime-error gtk3 vala gee

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

修复前的代码:

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
            }
        }
    }

现在它可以工作,我不确定但是它可能与异步调用remove方法有关,是吗?

有什么好的解释吗? 这是问题的正确解决方法吗?

@After再次检查代码我肯定这不是我的问题的正确解决方法因为menuButtons.remove(widget);从来没有在我的情况下被调用。小部件保留在列表中,这是不受欢迎的行为。

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);
  }

}

编译:{{1​​}}

2 个答案:

答案 0 :(得分:1)

有几点:

  1. 您正在覆盖Gtk.Container::remove,但是从不通过调用base.remove()来链接父类的实现,从长远来看会导致问题。
  2. MyContainer::remove中,您正在调用widget.unparent(),这可能会导致MyContainer::remove的某种辅助调用。如果是这样,widget in menuButtons测试的两次计算结果为true,但是当原始调用尝试从列表中删除小部件时,它已经消失,因此断言失败。
  3. TL; DR:将来自widget.unparent()的来电替换为base.remove(widget)

    PS:如果你需要明确的this.queue_resize_no_redraw()电话,我会非常惊讶,GTK +真的应该为你管理。

答案 1 :(得分:1)

正如迈克尔所写,你正在做很多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);
  }
}