Why do i keep geting TypeError: argument child: Expected Gtk.Widget, but got __main__.GObjectMeta

This is the code I’m running as a small test of implementation for a bigger project.

xml = """\
<interface>
  <template class="wellcomewind" parent="Gtk.Widget">
      <object class="Gtk.Widget">
      <object class="GtkButton" id="hello_button">
        <property name="label">Hello World</property>
        <signal name="clicked" handler="hello_button_clicked" swapped="no" />
      </object>
    </child>
    </object>
  </template>
</interface>
"""
import gi

gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Gtk, Adw, Gio, GLib


@Gtk.Template(string=xml)
class Foo(Gtk.Widget):
    __gtype_name__ = "wigit"
    hello_button = Gtk.Template.Child()

    @Gtk.Template.Callback()
    def hello_button_clicked(self, *args):
        print("hello world")
        pass







def on_activate(app):
    # … create a new window…
    win = Gtk.ApplicationWindow(application=app)
    # … with a button in it…
    btn = Gtk.Button(label='Hello, World!')
    # … which closes the window when clicked
    btn.connect('clicked', lambda x: print("hello world"))
    win.set_child(Foo)
    win.present()

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

# Run the application



if __name__ == '__main__':

    app.run(None)

the output is

Traceback (most recent call last):
  File "/home/the-game/PycharmProjects/PythonProject2/scractch.py", line 43, in on_activate
    win.set_child(Foo)
TypeError: argument child: Expected Gtk.Widget, but got __main__.GObjectMeta

then it keeps running without any window showing and when i kill it it returns this

Traceback (most recent call last):
  File "/home/the-game/PycharmProjects/PythonProject2/scractch.py", line 43, in on_activate
    win.set_child(Foo)
TypeError: argument child: Expected Gtk.Widget, but got __main__.GObjectMeta
Traceback (most recent call last):
  File "/home/the-game/PycharmProjects/PythonProject2/scractch.py", line 56, in <module>
    app.run(None)
  File "/home/the-game/miniconda3/lib/python3.12/site-packages/gi/overrides/Gio.py", line 46, in run
    with register_sigint_fallback(self.quit):
  File "/home/the-game/miniconda3/lib/python3.12/contextlib.py", line 144, in __exit__
    next(self.gen)
  File "/home/the-game/miniconda3/lib/python3.12/site-packages/gi/_ossighelper.py", line 239, in register_sigint_fallback
    signal.default_int_handler(signal.SIGINT, None)
KeyboardInterrupt

Process finished with exit code 130 (interrupted by signal 2:SIGINT)

what am I doing wrong?

I’m not very good with GTK4, but you’ve got a few problems here:

  1. The XML template is just not correct. Even the syntax is wrong, and I actually get this when trying: (process:3688482): Gtk-WARNING **: 15:11:50.306: Failed to precompile template for class wigit: Error on line 8 char 13: Element “child” was closed, but the currently open element is “object”
  2. Your main concern: in set_child() you need to give an instance, here you’re merely passing it a type. Use set_child(Foo()).
  3. You need to match the __gtype_name__ to the class property of your template. As, is, you’d get (python3:3688853): Gtk-CRITICAL **: 15:13:32.675: Error building template class 'wigit' for an instance of type 'wigit': .:0:0 Parsed template definition for type 'wellcomewind', expected type 'wigit'. It is customary to use the same name as the Python class as well to avoid confusion, yet that’s not enforced.
  4. The type names in the the XML template don’t use . as scope separation: it’s GtkWidget, not Gtk.Widget. Otherwise, you’d get: (python3:3689270): Gtk-CRITICAL **: 15:15:22.172: Error building template class 'wigit' for an instance of type 'wigit': .:0:0 Invalid template parent type 'Gtk.Widget'
  5. Here my lack of GTK4 habit starts to show, but inheriting from GtkWidget directly will require some more work to handle the children. As-is, you’d get (python3:3689513): Gtk-WARNING **: 15:16:45.314: Trying to snapshot GtkButton 0x3bd81490 without a current allocation. How you want to deal with this depends on what you’re trying to achieve, but simply changing the parent from GtkWidget to e.g. GtkBox (and the same in the Python class) will start to work.
1 Like

ok so i fixed 1-4 i think

xml = """\
<interface>
  <template class="wigit" parent="GtkBox">
      <object class="GtkBox">
      <object class="GtkButton" id="hello_button">
        <property name="label">Hello World</property>
        <signal name="clicked" handler="hello_button_clicked" swapped="no" />
      </object>

    </object>
  </template>
</interface>
"""
import gi

gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Gtk, Adw, Gio, GLib


@Gtk.Template(string=xml)
class Foo(Gtk.Widget):
    __gtype_name__ = "wigit"
    hello_button = Gtk.Template.Child()

    @Gtk.Template.Callback()
    def hello_button_clicked(self, *args):
        print("hello world")
        pass







def on_activate(app):
    # … create a new window…
    win = Gtk.ApplicationWindow(application=app)
    # … with a button in it…
    btn = Gtk.Button(label='Hello, World!')
    # … which closes the window when clicked
    btn.connect('clicked', lambda x: print("hello world"))
    win.set_child(Foo())
    win.present()

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

# Run the application



if __name__ == '__main__':

    app.run(None)

i dont understant what " GtkWidget directly will require some more work to handle the children" means
and im geting

python:150590): Gtk-CRITICAL **: 13:35:50.734: Error building template class 'wigit' for an instance of type 'wigit': .:0:0 Invalid template parent type 'GtkBox'
Traceback (most recent call last):
  File "/home/the-game/miniconda3/lib/python3.12/site-packages/gi/_gtktemplate.py", line 170, in <lambda>
    lambda s: init_template(s, cls, base_init_template)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/the-game/miniconda3/lib/python3.12/site-packages/gi/_gtktemplate.py", line 193, in init_template
    raise RuntimeError(
RuntimeError: Handler 'hello_button_clicked' was declared with @Gtk.Template.Callback but was not present in template
Traceback (most recent call last):
  File "/home/the-game/PycharmProjects/PythonProject2/scractch.py", line 57, in <module>
    app.run(None)
  File "/home/the-game/miniconda3/lib/python3.12/site-packages/gi/overrides/Gio.py", line 46, in run
    with register_sigint_fallback(self.quit):
  File "/home/the-game/miniconda3/lib/python3.12/contextlib.py", line 144, in __exit__
    next(self.gen)
  File "/home/the-game/miniconda3/lib/python3.12/site-packages/gi/_ossighelper.py", line 239, in register_sigint_fallback
    signal.default_int_handler(signal.SIGINT, None)
KeyboardInterrupt

but now a empty window is displayed so we got some progress

You now don’t have the same parent type in the template and in your Python class (GtkBox vs. Gtk.Widget), yet those need to match.

Once that’s fixed, you’ll notice that you get a complaint about the XML not being correct. Basically, replace your <object class="GtkBox">…</object> with <child>…</child>: child objects need to be wrapped in a child element, and your current inner GtkBox don’t seem currently useful. See also Gtk.Builder

back to the original error

xml = """\
<interface>
  <template class="wigit" parent="GtkWidget">
      <child>
      <object class="GtkButton" id="hello_button">
        <property name="label">Hello World</property>
        <signal name="clicked" handler="hello_button_clicked" swapped="no" />
      </object>
    </child>
  </template>
</interface>
"""
import gi

gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Gtk, Adw, Gio, GLib


@Gtk.Template(string=xml)
class Foo(Gtk.Widget):
    __gtype_name__ = "wigit"
    hello_button = Gtk.Template.Child()

    @Gtk.Template.Callback()
    def hello_button_clicked(self, *args):
        print("hello world")
        pass







def on_activate(app):
    # … create a new window…
    win = Gtk.ApplicationWindow(application=app)
    # … with a button in it…
    btn = Gtk.Button(label='Hello, World!')
    # … which closes the window when clicked
    btn.connect('clicked', lambda x: print("hello world"))
    win.set_child(Foo())
    win.present()

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

# Run the application



if __name__ == '__main__':

    app.run(None)

I’m using temples because I couldn’t figure out buttons without using temples so please tell me if there is a better way to integrate buttons