Gtk.Box doesn't update in subclass of Gtk.Bin (PyGObject)

Minimal reproducible example:

import gi
gi.require_version("Gtk", "3.0")
gi.require_version("GLib", "2.0")
from gi.repository import Gtk, GLib

class Test(Gtk.Bin):
    def __init__(self):
         super().__init__()
         box = Gtk.Box()
         self.add(box)

         GLib.timeout_add(lambda _: box.add(Gtk.Button.new_with_label("you will not see me")), 100)

window = Gtk.Window(title="Hello World")
test = Test()
window.add(test)
window.show_all()
window.connect("destroy", Gtk.main_quit)
Gtk.main()

the button is never shown. the box remains empty visually

You never show the children of Test. You never show Test either, to be fair.

Widgets, in GTK3, are hidden by default; you need to explicitly show them by calling show(), or recursively show them by calling show_all() on one of their ancestor.

Try replacing:

window.show()

with:

window.show_all()

and you should see the child widgets appear. Except for the button you add in a timeout: for that you will need to call show() explicitly, as it’s added after the show_all() call returns.

the code for test is literally inside the example
class Test(Gtk.Bin):

also, is there a reason I can’t call show_all() again on the parent? would this break things?

When I wrote “you never show the children of Test” I literally meant: you need to call show() on every child you add, otherwise it won’t be visible.

ETA: Your timeout_add() function is also wrong, the interval is the first argument, not the last.

Once you explicitly show the widgets, everything works as it should:

import gi
gi.require_version("Gtk", "3.0")
gi.require_version("GLib", "2.0")
from gi.repository import Gtk, GLib

class Test(Gtk.Bin):
    def __init__(self):
        super().__init__()

        # Add a box, and show it
        box = Gtk.Box()
        self.add(box)
        box.show()

        def on_timeout():
            # Add a button, and show it
            button = Gtk.Button.new_with_label("you will not see me")
            box.add(button)
            button.show()
            return GLib.SOURCE_REMOVE

        GLib.timeout_add(100, on_timeout)

window = Gtk.Window(title="Hello World")
window.connect("destroy", Gtk.main_quit)

# Add the Test widget, and show it
test = Test()
window.add(test)
test.show()

# Just show the window
window.show()

Gtk.main()
1 Like

You can call show_all() as many times as you want, but you typically want to control which widgets you wish to show, not perform a blanket “please show every single widget in this branch of the widget tree”. For instance, you could have multiple widgets added to a container, and then show/hide them depending on some state; if you call show_all() every time you add a widget, you’ll end up showing everything that’s currently hidden on purpose.

i just have a list of things that rerenders. should I just use show_all()? because i need to make them all visible every time

You’re making it much more complicated than it necessarily is.

You don’t need to constantly set a widget visible: once a widget is marked as visible with show(), it stays visible until you call hide().

Call show() every time you add a widget to a parent container—or, if you’re using a UI description XML file and GtkBuilder, add a <property name="visible>True</property> element.

Every time I update it, all elements are deleted and new elements are added, like rerendering it. Can I just call show_all() on every rerender?

Is there some sort of language barrier, here? Should I explain again what I wrote?

You can call show() on every widget you add; you can also call show_all() on their ancestor. The important thing is that you must make a widget visible after adding it to a parent.

ok i see. so it is ok to call show_all if the entire list is hidden and must be shown?

I don’t know how many more times I can answer the same question in the same way.

At this point, I encourage you to:

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.