Question regarding the use of class level variables created using Gtk.Template.Child()

I have defined a class using the @Gtk.Template() decorator.

I can define a variable using Gtk.Template.Child() just fine, I can later access it, e.g. a Button:

myButton1 = Gtk.Template.Child(‘myButton1’)
myButton1.set_label(‘First button’)

When I, however, put several buttons in an array, e.g.

buttons = [Gtk.Template.Child(‘myButton1’), Gtk.Template.Child(‘myButton2’)]

I can no longer access them.

pages[0].set_label(‘A button’)

Errors out with “AttributeError: ‘Child’ object has no attribute ‘set_label’”

Why is this so? Is there a way to get at “the real object” from a Child()?

The @Gtk.Template decorator loops through the class’ attributes and checks whether they’re of instance CallThing (this is how @Gtk.Template.Callback works) or Child. It doesn’t loop through iterable attributes.

See: gi/_gtktemplate.py · cd8432ea88bab67a4bbfa8c41a5b03b26064aea5 · GNOME / pygobject · GitLab

1 Like

In other words: template children must be defined directly on the class, not inside an array or so.

Understood so far, but why does this not work either?

plu_1_0_0 = Gtk.Template.Child('plu_1_0_0')
plu_1_1_0 = Gtk.Template.Child('plu_1_1_0')
plu_1_2_0 = Gtk.Template.Child('plu_1_2_0')
plu_1_3_0 = Gtk.Template.Child('plu_1_3_0')
plu_1_4_0 = Gtk.Template.Child('plu_1_4_0')

pages = [
    [
        [ plu_1_0_0 ,plu_1_1_0, plu_1_2_0, plu_1_3_0, plu_1_4_0 ]
    ]
]

Here I define them at class level and only put them in an array afterwards. My guess is that loop a not been run here already. If I move the array creation into _init_, it works.

(Why, oh why, do cash registers need so many buttons… :slight_smile: )

Well, that is how attributes work in Python in general. If you do:

class MyClass:
    foo = 42

    def __init__(self):
        self.bar = 35

Then foo is a class attribute MyClass.foo (which is also accessible on instances of the class), and bar is in instance attribute. Each instance of the class has its own bar, independently of others, whereas there is a single foo on the class (which is accessible through any instance).

Now, Gtk.Template.Child is a magic thing that you use to define an attribute on the class, and it results in your instances having the resulting object (typically widget) as an instance attribute of the same name. So it shadows the class attribute – when you write self.plu_1_0_0, you access the instance attribute, of type Gtk.Button, but if you write MyClass.plu_1_0_0 you will still see the class attribute, of type Gtk.Template.Child. If you want to do something with those instance attributes (or any other instance attributes), you should do that in __init__ – before that, there isn’t even an instance to speak of.

Hope this makes some sense :slightly_smiling_face:

1 Like

Yes, this does make sense. Thank you for your clarifications.