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)
I’m not very good with GTK4, but you’ve got a few problems here:
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”
Your main concern: in set_child() you need to give an instance, here you’re merely passing it a type. Use set_child(Foo()).
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.
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'
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.
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