I’ve a subclassed Gtk.Box
and want to add an additional property children
to hold the children added to that Gtk.Box
. Is there any method to get the current list of children?
Since a GtkBox
is a GtkWidget
I think you should be able to:
export class MyBox extends Gtk.Box {
get children () {
let child = this.get_first_child();
while(child) {
yield child;
child = child.get_next_sibling();
}
}
}
GObject.registerClass(MyBox);
But it’s soon 10 years ago that I worked with Gtk and JavaScript so it’s likely that I’m wrong. But you could test the above while waiting for replies from more knowledgeable people.
Iterating the children of a scaffolding widget like GtkBox is usually a code smell. The only time you should be iterating widgets is if you’re implementing a custom widget. There’s little to no reason why you should want to do it on a box.
What are you actually trying to achieve?
Instead of appending a widget everytime, I’m trying to add a children
property to Gtk.Box
. Anytime if I want to list all the children I can use <instance>.children
or set the children with <instance>.children = [new Gtk.Label(), new Gtk.Label]
.
But why would you do that? It’s incredibly inefficient to get the list of children and then append or replace it, compared to using the GtkBox
API.
Why would you get the list of children (a linear operation), then append a child to it, instead of just appending the child to the box?
# compare this
box.append(new_child)
# to this
children = box.children
children.push(new_child);
Why would you replace the list of children instead removing the box and replacing it?
new_box = new Gtk.Box();
new_box.append(new Gtk.Label());
new_box.append(new Gtk.Label());
parent.set_child(new_box);
Also, GtkBox
is a scaffolding widget. If you keep adding/replacing widgets to it, then you’re probably using the wrong widget. You probably want to switch to a Gtk.ListBox
or a Gtk.FlowBox
, and bind a model to them.
Yeah, I think I was using the wrong widget. What my intuition is,
#widgets to add
widgets = [<child_1>, <child_2>, <child_3>]
#to add to a Gtk.Box
box = new Gtk.Box()
widgets.forEach(child => box.append(child))
#later
box.remove(widgets[1])
Now Instead if I do,
box = new Gtk.Box()
#add widgets
box.append(<child_1>)
box.append(<child_2>)
box.append(<child_3>)
How am I supposed to remove <child_2>
from box
now?
So I thought if there was a way to get list of children and add getter, setter for this (i.e. children
property) then I can do box.remove(box.children[1])
There is still the question of what you want to actually achieve. Like mentioned before, Gtk.Box
is for UI layout, not for dynamic content.
So, depending on your goal I see two options:
Number 1: You have a set of UI elements which are visible depending on context. Like, you have an element with multiple buttons for actions, and you want to hide actions that are not possible.
In this case, you could just hide the element in question by setting Gtk.Widget::visible
to false
. Though, then it would make sense to consider Gtk.Widget::sensitive
to just make it non-interactable instead.
Number 2: You have some content which is dynamically shown on the UI. So, you want one UI element for one content element.
Well, in this case, you want to look at using Gtk.ListBox
or Gtk.ListView
. These widgets are designed for dynamic content. Ideally, you would crate a list model for your content (which you can easily implement). There, you can use your method for sorting/adding/removing content. And then, you bind the ListBox
or ListView
to said list, and when your list model is updated, the widgets will update their content for you.
This is highly recommended. Not only separates this your business logic and the UI code better. When dealing with large amount of content, Gtk.ListView
will be far more performant than a Gtk.Box
.
I hope this helps you.
If there are still things unclear, it might help if you were to tell what use-case you want to implement, so we can find the best solution for it.
I wasn’t sure about Gtk.ListBox
but i.g. it’s the right option for what I was trying to do. Basically if I do this :
const box = new Gtk.Box()
box.append(new Gtk.Label())
Now I can’t delete the child inside box
because I’ve no name reference (i.e. const or let) on this child. So I thought if there was a way to get a list of children, then I can easily do:
box.remove(<child_name>)
.
My plan is to make a notification center and I think Gtk.ListBox
or Gtk.ListView
is the right widget.
Also if I want to make something similar with horizontal packing what should I use. Afaik Gtk.ListView
only shows items vertically.
Well, for something like a notification center, where you might have a lot of content, Gtk.ListView
is likely the right choice.
Well, this sounds like a atypical design pattern, so its not that surprising Gtk does not support that out of the box.