如何使用 Python+PyGObject 的 GObject.bind_property 函数进行 2 向数据绑定?



这个问题的背景(也是我的总体目标)是以一种很好的方式构建Python GTK应用程序。我正在尝试使用 GTK 的双向数据绑定将小部件属性绑定到模型属性。

我的期望是双向绑定应使两个属性保持同步。相反,我发现更改仅在一个方向上传播,即使我使用的是GObject.BindingFlags.BIDIRECTIONAL标志。我创建了以下最小示例和失败的测试用例test_widget_syncs_to_model来说明问题。请注意,在更实际的示例中,模型对象可以是Gtk.Application的实例,小部件对象可以是Gtk.Entry的实例。

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"nn{self.id()}")
self.model = Obj("model")
self.widget = Obj("widget")
self.model.bind_property(
"txt", self.widget, "txt", flags=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()

上述程序输出:

ssF
======================================================================
FAIL: test_widget_syncs_to_model (__main__.TestBindings)
Verifies that widget changes propagate back into the model
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/jh/.config/JetBrains/PyCharmCE2021.1/scratches/scratch_14.py", line 52, in test_widget_syncs_to_model
self.assertEqual(self.model.txt, data)  # FAILS
AssertionError: 'default' != 'world'
- default
+ world

----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures=1, skipped=2)

__main__.TestBindings.test_widget_syncs_to_model
The 'widget' object received a notify event, its txt now is 'world'.
Process finished with exit code 1

我的具体问题是,如何使双向数据绑定工作?...如果有人可以修复我的示例或提供另一个工作示例,我将很高兴。

从更广泛的意义上讲,双向绑定是否是在结构良好的 Python GTK 应用程序中同步 UI 状态和模型状态的方法?为此,预期和得到充分支持的方法是什么?谢谢!

我在 gnome 话语线程中得到了关于 python 中双向属性绑定的答案。

为了更清楚起见,以下代码不起作用,因为标志未正确传递:

# broken, flags are passed incorrectly as keywords argument:
self.model.bind_property("txt", self.widget, "txt", flags=GObject.BindingFlags.BIDIRECTIONAL)

相反,必须按如下方式传递标志:

# functioning, flags are passed correctly as a positional argument:
self.model.bind_property("txt", self.widget, "txt", GObject.BindingFlags.BIDIRECTIONAL)

更多示例代码:例如,在 test_bidirectional_binding 测试用例中 pygobject 的源代码中演示了双向绑定的正确使用。

最新更新