15
votes

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.

4
Here is an example of how to do it with a treeview: stackoverflow.com/questions/27747172/…tobias47n9e

4 Answers

2
votes

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.)

2
votes

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)
0
votes

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 ,

-1
votes

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).