Gtk3 replace child widget with another widget

gtk+ 3
gtk3 gtk_widget
gtk3 signals
gtk 3 frame
gtk3 api
gtk+ widget button press event
gtk3 gtk window
gtk+ widget library

I'm looking for a way to remove a widget from its parent (whatever that may be - a VBox, a Grid, ...) and add a substitute widget in its place.

I found this answer, but I can't seem to make it work with Gtk3.

Here's what I tried:

from gi.repository import Gtk

def replace_widget(old, new):
    parent= old.get_parent()

    props= {}
    for key in Gtk.ContainerClass.list_child_properties(type(parent)):
        props[key.name]= parent.child_get_property(old, key.name)

    parent.remove(old)
    parent.add_with_properties(new, **props)

But the call to Gtk.ContainerClass.list_child_properties raises

TypeError: argument self: Expected a Gtk.ContainerClass, but got gi.repository.Gtk.GObjectMeta

It won't accept an instance of a container widget either. For the life of me, I can't figure out what parameter I'm supposed to pass.

P.S.: I know I could add another widget between the container and the child widget, but I'd prefer not to.

UPDATE: I guess it wasn't clear enough: The substitute widget is supposed to be in the same place as the original widget, with the same packing properties.

This has only recently become possible, since PyGObject 3.14: https://git.gnome.org/browse/pygobject/commit/?h=pygobject-3-14&id=bf84915f89fd5fd502b4fb162eef7bc0a48c8783

Either of the following will work in PyGObject 3.14 and later:

parent.list_child_properties()
Gtk.ContainerClass.list_child_properties(parent)

(The second syntax is in case class and instance methods have a naming conflict. See discussion here.)

python - Gtk3 replace child widget with another widget, This has only recently become possible, since PyGObject 3.14: https://git.gnome.​org/browse/pygobject/commit/?h=pygobject-3-14&id=  Mais l'appel à Gtk.ContainerClass.list_child_properties pose. TypeError: argument self: Expected a Gtk.ContainerClass, but got gi.repository.Gtk.GObjectMeta il n'accepte pas non plus une instance d'un widget de conteneur. Pour ma vie, je n'arrive pas à trouver quel paramètre je suis censé passer.

Thanks to the information provided by ptomato's answer, here's the working code:

def replace_widget(old, new):
    parent = old.get_parent()

    props = {}
    for key in Gtk.ContainerClass.list_child_properties(type(parent)):
        props[key.name] = parent.child_get_property(old, key.name)

    parent.remove(old)
    parent.add(new)

    for name, value in props.iteritems():
        parent.child_set_property(new, name, value)

Gtk3 replace child widget with another widget, P.S.: I know I could add another widget between the container and the child widget, but I'd prefer not to. UPDATE: I guess it wasn't clear enough: The substitute  If a widget has native scrolling abilities, such as Gtk.TextView, Gtk.TreeView or Gtk.IconView, it can be added to a Gtk.ScrolledWindow with Gtk.Container.add (). If a widget does not, you must first add the widget to a Gtk.Viewport, then add the viewport to the scrolled window.

i know how it works with C , i did not try it with python :

 parent = gtk_widget_get_parent(old);
 g_object_ref(_key); /** because gtk_container_remove remove the widget with its reference we have to increment the number of reference if we want to reuse the old widget **/
 gtk_container_remove(GTK_CONTAINER(parent), old);
 gtk_container_add(GTK_CONTAINER(parent), new);

PS : in the case of a VBox or Grid the widget is not inserted int the place of old one , you have to specify the position of insertion (the position of the old whild)

good luck ,

Gtk3 replace child widget with another widget, Gtk3 replace child widget with another widget. Question. I'm looking for a way to remove a widget from its parent (whatever that may be - a VBox, a Grid, . gtk_menu_button_new () GtkWidget * gtk_menu_button_new (void);. Creates a new GtkMenuButton widget with downwards-pointing arrow as the only child. You can replace the child widget with another GtkWidget should you wish to.

You can try reparent() method of Gtk.Widget. You can check docs at this link. If I remember well you should reparent child widget first, and then remove old parent widget. If it doesn't work post in comment and I'll check my docs (currently not on that machine sry).

GtkContainer: GTK+ 3 Reference Manual, GtkContainer — Base class for widgets which contain other widgets The first type of container widget has a single child widget and derives from GtkBin. Height-for-width means that a widget can change how much vertical space it needs,  Description. A GtkFlowBox positions child widgets in sequence according to its orientation. For instance, with the horizontal orientation, the widgets will be arranged from left to right, starting a new row under the previous row when necessary.

GtkStack: GTK+ 3 Reference Manual, The GtkStack widget is a container which only shows one of its children at a time. If it isn't, the stack may change size when a different child becomes visible. GtkWidget * gtk_widget_get_toplevel (GtkWidget *widget); This function returns the topmost widget in the container hierarchy widget is a part of. If widget has no parent widgets, it will be returned as the topmost widget. No reference will be added to the returned widget; it should not be unreferenced.

Gtk.Widget - Classes, Height-for-width means that a widget can change how much vertical space it needs if you are getting the size request for another widget, such as a child of a container, Since GTK 3, this function does nothing, the passed in style is ignored. a GtkContainer child. a widget which is a child of container first_property_name. the name of the first property to get var_args. return location for the first property, followed optionally by more name/return location pairs, followed by NULL

Gtk.Container - Classes, child, Gtk.Widget, d/w, Can be used to add a new child to the container deprecated are the inner nodes in the resulting tree of widgets: they contain other widgets. the frame, you might replace the Gtk.Label widget with a Gtk.​Image widget. Note that the container will own a reference to widget, and that this may be the last reference held; so removing a widget from its container can cause that widget to be destroyed. If you want to use widget again, you should add a reference to it. EDITS. I just quickly modified pygtk's Hello World to add/remove/reorder widgets in a container.

Comments
  • Here is an example of how to do it with a treeview: stackoverflow.com/questions/27747172/…
  • I have posted the working code as an answer, but we could add it to your answer instead if you prefer?
  • Thank you for your answer, I think it's fine to leave it as a separate answer. You can also feel free to edit my answer if you prefer to merge them!
  • Please do not just post links here. Please copy the method you are referencing.
  • Sry, i'm a little bit confused. Why is linking allowed if it is not desirable? The method name is reparent()
  • Linking is for additional information. You should do something like: Try this method: reparent() please see this link for more information.
  • @JSK NS My apologies. Thanks for suggestion. I'll edit post and this comments can be removed.
  • This will not add the new widget in the old widget's place. It's basically the same thing YouzKing suggested.