ConstraintLayout + VFL in Python -- "Finalizing but it still has children left"

I converted the ConstraintLayout code from the gtk4-demo to Python, and it works well, but I get an error (“Finalizing… but it still has children left”) to stdout when I close the app.

The code is:

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class ConstraintLayoutDemoWidget(Gtk.Widget):
    def __init__(self):
        super().__init__(hexpand=True, vexpand=True)

        self.constraint_layout_manager = Gtk.ConstraintLayout()
        self.set_layout_manager(self.constraint_layout_manager)

        self.button_1 = Gtk.Button(name='button1', label='Button 1')
        self.button_1.set_parent(self)
        self.button_2 = Gtk.Button(name='button2', label='Button 2')
        self.button_2.set_parent(self)
        self.button_3 = Gtk.Button(name='button3', label='Button 3')
        self.button_3.set_parent(self)

        vfl_constraints = [
            "H:|-[button1(==button2)]-12-[button2]-|",
            "H:|-[button3]-|",
            "V:|-[button1]-12-[button3(==button1)]-|",
            "V:|-[button2]-12-[button3(==button2)]-|",
        ]
        views = {'button1': self.button_1, 'button2': self.button_2, 'button3': self.button_3}
        self.constraint_layout_manager.add_constraints_from_description(vfl_constraints, hspacing=10, vspacing=10, views=views)


def on_activate(app):
    application_window = Gtk.ApplicationWindow(application=app)

    constraint_widget = ConstraintLayoutDemoWidget()

    box = Gtk.Box()
    box.append(constraint_widget)
    application_window.set_child(box)

    application_window.present()


if __name__ == '__main__':
    # Create a new application
    app = Gtk.Application(application_id='com.example.GtkApplication')
    app.connect('activate', on_activate)

    # Run the application
    app.run(None)

And the error is:

(python:1266308): Gtk-WARNING **: 18:12:28.256: Finalizing __main__+ConstraintLayoutDemoWidget 0x1a139a0, but it still has children left:
   - button1 0x1a079c0
   - button2 0x1a06670
   - button3 0x19c2990

I need to unparent the buttons from my widget when it’s being destroyed, but I’m not sure what method to override or signal to catch. Any suggestions?

maybe this helps

Greetings

This is a known limitation of the Python bindings: there is no way to override the dispose virtual function of GObject, which makes it hard to subclass GtkWidget. You can try and remove your widgets in the do_unroot() method, but you will need to recreate the widgets inside the do_root() method if you plan on moving your widget class between different parents.

Thanks for the quick responses!

I added a __del__ method to unparent the buttons, and that silences the warning. That may not be the best way, but…

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk


#   +-----------------------------+
#   | +-----------+ +-----------+ |
#   | |  Child 1  | |  Child 2  | |
#   | +-----------+ +-----------+ |
#   | +-------------------------+ |
#   | |         Child 3         | |
#   | +-------------------------+ |
#   +-----------------------------+

class ConstraintLayoutDemoWidget(Gtk.Widget):
    def __init__(self):
        super().__init__(hexpand=True, vexpand=True)

        self.constraint_layout_manager = Gtk.ConstraintLayout()
        self.set_layout_manager(self.constraint_layout_manager)

        self.button_1 = Gtk.Button(name='button1', label='Button 1')
        self.button_1.set_parent(self)
        self.button_2 = Gtk.Button(name='button2', label='Button 2')
        self.button_2.set_parent(self)
        self.button_3 = Gtk.Button(name='button3', label='Button 3')
        self.button_3.set_parent(self)

        vfl_constraints = [
            "H:|-[button1(==button2)]-12-[button2]-|",
            "H:|-[button3]-|",
            "V:|-[button1]-12-[button3(==button1)]-|",
            "V:|-[button2]-12-[button3(==button2)]-|",
        ]
        views = {'button1': self.button_1, 'button2': self.button_2, 'button3': self.button_3}
        self.constraint_layout_manager.add_constraints_from_description(vfl_constraints, hspacing=10, vspacing=10, views=views)

    def __del__(self):
        self.button_1.unparent()
        self.button_2.unparent()
        self.button_3.unparent()


def on_activate(app):
    application_window = Gtk.ApplicationWindow(application=app)

    constraint_widget = ConstraintLayoutDemoWidget()

    box = Gtk.Box()
    box.append(constraint_widget)
    application_window.set_child(box)

    application_window.present()


if __name__ == '__main__':
    # Create a new application
    app = Gtk.Application(application_id='com.example.GtkApplication')
    app.connect('activate', on_activate)

    # Run the application
    app.run(None)

That’s also a viable solution, yes. It assumes that the Python wrapper will go away before the underlying C object, which is generally the case as the Python wrapper keeps the C object alive and is responsible for dropping the last reference on the object.

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