Ошибка подтверждения в методе: 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
}
}
}
И теперь это работает, я не уверен, но это может быть связано с асинхронным вызовом метода удаления, не так ли?
Любое хорошее объяснение? Это правильное решение проблемы?
@ После повторной проверки кода я уверен, что это не является правильным решением моей проблемы, потому что 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);
}
}
Компилировать с: --pkg=gtk+-3.0 --pkg=gee-0.8
2 ответа
Как писал Майкл, вы делаете много вещей, которые 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);
}
}
Пара моментов:
- Вы переопределяете
Gtk.Container::remove
, но никогда не соединяясь в цепочку с реализацией родительского класса, вызываяbase.remove()
, что вызовет у вас проблемы в долгосрочной перспективе. - В
MyContainer::remove
ты звонишьwidget.unparent()
что может быть причиной какого-то вторичного вызоваMyContainer::remove
, Если так, то оба разаwidget in menuButtons
test оценивается как true, но когда исходный вызов пытается удалить виджет из списка, он уже исчез, следовательно, ошибка подтверждения.
TL; DR: заменить вызов на widget.unparent()
с base.remove(widget)
,
PS: я был бы очень удивлен, если вам нужно явное this.queue_resize_no_redraw()
позвоните либо, GTK+ действительно должен управлять этим для вас.