gtk4 + python workaround for unsupported functions bind_property_with_closures() and bind_property_full()

33 Views Asked by At

I am searching for the best way to automatically write a GObject variable to a widget after formatting it. For example to limit the decimal places of a real variable displayed in the widget.

I think this normally would be done with the functions bind_property_with_closures() or bind_property_full(), but only bind_property() is available.

Now I found the workaround, to first write the real variable with bind_property() to a hidden widget. And then bind it from the hidden widget to the visible widget while modifying it with my python function float_with_2_digits().

#!/usr/bin/python3
import sys
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Adw, Gtk, Gio, Gdk, GLib, GObject

xml = """\
<interface>
  <template class="example2" parent="GtkBox">
    <property name="spacing">12</property>
    <property name="margin-top">12</property>
    <property name="margin-end">12</property>
    <property name="margin-bottom">12</property>
    <property name="margin-start">12</property>

    <child>
        <object class="GtkLabel" id='my_hidden_label'>
            <property name="visible">FALSE</property>
        </object>
    </child>

    <child>
        <object class="GtkLabel">
            <binding name="label">
               <closure type='gchararray' function='float_with_2_digits'>
                  <lookup name="label">my_hidden_label</lookup>
                </closure>
            </binding>
        </object>
    </child>

  </template>
</interface>
"""

class Article(GObject.Object):
    price = GObject.Property(type=float)

    def __init__(self, price):
        super().__init__()
        self.price = price

@Gtk.Template(string=xml)
class MyBox(Gtk.Box):
    __gtype_name__ = "example2"

    my_label = Gtk.Template.Child("my_hidden_label")

    @Gtk.Template.Callback()
    def float_with_2_digits(self, my_box, real1):
        real3=""
        if real1:
            real2=float(real1.replace(',','.'))
            real3=f'{real2:.2f}'
        print("real1=<%s> => real3=<%s>" % (real1,real3))
        return real3

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        article = Article(0)

        # unknown: article.bind_property_with_closures
        # not implemented: article.bind_property_full
        article.bind_property("price",
           self.my_label, "label",
           GObject.BindingFlags.SYNC_CREATE)

        article.price=1.6666

class MainWindow(Gtk.ApplicationWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        my_box = MyBox()
        self.set_child(my_box)

class MyApp(Adw.Application):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.connect('activate', self.on_activate)

    def on_activate(self, app):
        self.win = MainWindow(application=app)
        self.win.present()

app = MyApp(application_id="de.bschu.expression2")
app.run(sys.argv)

The workaround is done with a closure that is defined in a UI template. The workaround is working. But I wonder if there is a better way. How do you solve this ?

If there is no better workaround, I hope at least that my workaround is useful for other people.

0

There are 0 best solutions below