Vala. How do you delete all the children of a GTK container?
Asked Answered
C

1

9

Solved. See the reply for examples.

I have a container with children. I need to delete all the children. This is easy in C. Vala does not work.

The following code produces an error missing type argument for collection.

var a_box = new Box (Orientation.VERTICAL, 0);
// Add some children
List children = a_box.get_children();
foreach (Widget element in children) { }

I tested over twenty variations of this code plus with many data types. When I do not get the missing type complaint, I end up with a data type that cannot be used as a widget which means I cannot destroy it.

Using Vala, not C or Python or any of the many languages where this is easy, how do you remove all the children of a container?

From what I can see, the only way to get the children is as a List but in Vala a List entry cannot be used to remove or destroy widgets.

Both remove and destroy work in C. I have several C based applications doing both. The Vala 0.30 compiler rejected every translation from C to Vala and refused to compile examples from Valadocs etc.

Christychristye answered 25/3, 2016 at 6:56 Comment(2)
Re: examples from valadoc, can you provide any specific examples? I'm sure Florian would like to know about any broken examples…Parenteau
@nemequ, I expanded the bit about Valadocs and other sources. Valadocs needs something like the PHP comments where people can provide and discuss examples of usage.Christychristye
P
12

To correct the error about missing type arguments, just provide the type arguments. The signature for Gtk.Container.get_children() says the type is List<weak Widget>, so let's use that:

GLib.List<weak Gtk.Widget> children = container.get_children ();
foreach (Gtk.Widget element in children)
  container.remove (element);

Of course, you could also just use type inferencing:

var children = container.get_children ();
foreach (Gtk.Widget element in children)
  container.remove (element);

Or even just avoid the temporary variable altogether:

foreach (Gtk.Widget element in container.get_children ())
  container.remove (element);

But the easiest way I can think of would be:

container.foreach ((element) => container.remove (element));
Parenteau answered 25/3, 2016 at 9:4 Comment(4)
Originall I tried variations on "var children =" but the compiler or the execution complained about type incompatibilities. I did not keep copies of the failed examples. I added printf in an attempt to find out what was available in the loop. Again there were type incompatibilities. I will go back and test again. For a later development of this code, I will need to know if it is a box or grid, etc, to report on what is deleted.Christychristye
The .forall description says it deletes things internal to the container object. This suggests that for some container types .forall will delete too much. .forall works for a box. I expect grid and similar containers may fail after .forall. I did not find documentation of which containers will fail. I will stick with the versions using .get_children.Christychristye
Actually, I think it will work as expected for a grid. I believe what it is referring to are widgets which add intermediaries between your widget and themselves; for example, Gtk.ListBox will automatically create a Gtk.ListBoxRow to hold your widget. forall will invoke the callback on the Gtk.ListBoxRow, but get_children will also return the Gtk.ListBoxRow, so it doesn't really matter… you just need to be aware of what is going on in both cases.Parenteau
End-users should not use .forall() as they should only manipulate their own widgets, and let the Container delete any of its internal, implementation-detail widgets. The correct way to loop over widgets in non-implementation code is .foreach(). Unless you know you need .forall(), it should not be used, and usually as a user of the widget you don't really need it (and if you think you need it, you probably have a larger problem and/or a bad design).Feminine

© 2022 - 2024 — McMap. All rights reserved.