15

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.

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
  • Here is an example of how to do it with a treeview: http://stackoverflow.com/questions/27747172/remove-widget-from-gtk-viewport-scrolled-window-in-dynamic-gui – tobias47n9e Feb 20 '15 at 10:03

4 Answers4

2

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

ptomato
  • 56,175
  • 13
  • 112
  • 165
  • I have posted the working code [as an answer](https://stackoverflow.com/a/50522344/1222951), but we could add it to your answer instead if you prefer? – Aran-Fey May 25 '18 at 08:20
  • 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! – ptomato May 26 '18 at 03:58
2

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)
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
0

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 ,

younes zeboudj
  • 856
  • 12
  • 22
-1

You can try reparent() method of Gtk.Widget. You can check docs at this gtkwidget/reparent link in archive.org. 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).

  • Please do not just post links here. Please copy the method you are referencing. – JSK NS Dec 18 '14 at 10:01
  • Sry, i'm a little bit confused. Why is linking allowed if it is not desirable? The method name is reparent() – cyberbrain Dec 18 '14 at 10:07
  • Linking is for additional information. You should do something like: Try this method: `reparent()` please see this link for more information. – JSK NS Dec 18 '14 at 10:08
  • @JSK NS My apologies. Thanks for suggestion. I'll edit post and this comments can be removed. – cyberbrain Dec 18 '14 at 10:14
  • This will not add the new widget in the old widget's place. It's basically the same thing YouzKing suggested. – Aran-Fey Dec 18 '14 at 11:48
  • Deprecated since version 3.14: Use Gtk.Container.remove() and Gtk.Container.add(). – oxidworks Feb 23 '18 at 14:18