Bidirectional Bindings using PyGObject - cannot get it to work, help or working example needed

Hi,

I am trying to get bidirectional property bindings to work in python (using pygobject and gtk3). It appears that the binding syncs one-way only even though I set the bidirectional flag.

I posted an according question on stackoverflow https://stackoverflow.com/q/67763050/2068912. The stackoverflow question includes a minimal code example with a failing test case to make it easy to reproduce and hopefully fix the problem. I would like to bring it to this forum’s attention as well because the stackoverflow question/answer seems to be stuck without solution.

Can someone help me figure out how to use the bidirectional bindings in python? I would be most grateful for hints / links / an answer over on stackoverlow / other working examples.

best regards, Johannes

Heh, Philip Withnall maintains GLib/GObject

Anyway the problem is your not setting the binding to be bidirectional, try

import gi

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
import unittest


class Obj(GObject.Object):
    """A very simple GObject with a `txt` property."""

    name = "default"
    txt = GObject.Property(type=str, default="default")

    def __init__(self, name, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.name = name
        self.connect("notify", self.log)

    def log(self, source, parameter_name):
        print(
            f"The '{self.name}' object received a notify event, "
            f"its txt now is '{self.txt}'."
        )


class TestBindings(unittest.TestCase):
    def setUp(self):
        """Sets up a bidirectional binding between a model and a widget"""
        print(f"\n\n{self.id()}")
        self.model = Obj("model")
        self.widget = Obj("widget")
        self.model.bind_property(
            "txt", self.widget, "txt", GObject.BindingFlags.BIDIRECTIONAL
        )

    @unittest.skip("suceeds")
    def test_properties_are_found(self):
        """Verifies that the `txt` properties are correctly set up."""
        for obj in [self.model, self.widget]:
            self.assertIsNotNone(obj.find_property("txt"))

    @unittest.skip("suceeds")
    def test_model_syncs_to_widget(self, data="hello"):
        """Verifies that model changes propagate to the widget"""
        self.model.txt = data
        self.assertEqual(self.widget.txt, data)

    def test_widget_syncs_to_model(self, data="world"):
        """Verifies that widget changes propagate back into the model"""
        self.widget.txt = data
        self.assertEqual(self.widget.txt, data)  # SUCCEEDS
        self.assertEqual(self.model.txt, data)  # FAILS


if __name__ == "__main__":
    unittest.main()

Hi! Thank you very much for solving the error, this was driving me crazy and I am very glad to have it working now. And thank you for pointing out Philip Whitnall’s role in maintaining Glib, I was not aware of that.

Note for future reference, to make it even more clear in case anybody else is having a similar problem :-). The following code does not work because flags are not passed correctly:

# broken, flags need to be set as positional argument:
self.model.bind_property("txt", self.widget, "txt", flags=GObject.BindingFlags.BIDIRECTIONAL)

Instead, flags must be passed as follows:

self.model.bind_property("txt", self.widget, "txt", GObject.BindingFlags.BIDIRECTIONAL)

EDIT, additional note: Proper use of bidirectional bindings is, e.g., demonstrated in pygobject’s source code in the test_bidirectional_binding test case.

Thank you so much for your help!
best regards, Johannes

1 Like

hi Zander, do you want to provide your answer over on stackoverflow as well? I am asking because you may value the stackoverflow points and badges associated with posting an answer. thanks, Johannes.

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