我想我修正了这个错误,但我想确定我是以正确的方式做到的。 我也不确定为什么会这样。
修复前的代码:
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}}
答案 0 :(得分:1)
有几点:
Gtk.Container::remove
,但是从不通过调用base.remove()
来链接父类的实现,从长远来看会导致问题。MyContainer::remove
中,您正在调用widget.unparent()
,这可能会导致MyContainer::remove
的某种辅助调用。如果是这样,widget in menuButtons
测试的两次计算结果为true,但是当原始调用尝试从列表中删除小部件时,它已经消失,因此断言失败。 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);
}
}