Simplest way for two-way binding a text field
-
Hi, I'm having trouble to have updates sent to a bound property without explicitly defining an event handler.
class Model(QtCore.QObject): """simplest model with a text property""" def __init__(self): super().__init__() self._member_a = 'YES' def a(self): return self._member_a def set_a(self, v): print(f'changing to {v}') self._member_a = v @QtCore.Signal def a_changed(self): pass a = QtCore.Property(str, a, set_a, notify=a_changed) model = Model() app = QtGui.QGuiApplication(sys.argv) view = QtQuick.QQuickView() view.rootContext().setContextProperty('model', model) view.setResizeMode(QtQuick.QQuickView.SizeRootObjectToView) with Path('Main.qml').open('w') as f: f.write(''' import QtQuick 2.0 import QtQuick.Controls 2.0 TextField { text: model.a // I don't want this: // onEditingFinished: model.a = text }''') view.setSource('Main.qml') view.resize(100, 100) view.show() result = app.exec_()My setup is with PySide6 6..0.1:
$ poetry show astroid 2.5 An abstract syntax tree for Python with inference support. isort 5.7.0 A Python utility / library to sort Python imports. lazy-object-proxy 1.5.2 A fast and thorough lazy object proxy. mccabe 0.6.1 McCabe checker, plugin for flake8 pylint 2.7.0 python code static checker pyside6 6.0.1 Python bindings for the Qt cross-platform application and UI framework shiboken6 6.0.1 Python / C++ bindings helper module toml 0.10.2 Python Library for Toms Obvious, Minimal Language wrapt 1.12.1 Module for decorators, wrappers and monkey patching.I tried to find proper guidance in the documentation, but failed.
Is there a better way than to define the
onEditingFinishedhandler?Thanks!
-
Thanks - the
emitis a necessary addition, I agree. I meant that adding a line by definition makes code less simple.But what I really don't understand is why I would need the
onEditingFinishedhandler in the qml itself. I was hoping to get the 2-way binding working without explicit event handling, by just bindingTextfield.textproperty tomodel.aproperty.@xtofl In QML the binding is unidirectional: from right to left:
Foo { id: foo a: bar.b }This binding indicates that every time the property "b" (which must be a signal) of the object "bar" then the property "a" of the object "foo" will be updated with that value. In python it would be something like:
bar.b_Signal.connect(lambda: setattr(foo, "a", foo.b))If you want to implement a 2-way binding then create a class that listens when one of those properties change ("a" or "b") and then updates the other.
-
Hi,
@xtofl said in Simplest way for two-way binding a text field:
def set_a(self, v):
print(f'changing to {v}')
self._member_a = vYou are not emitting the change signal.
The classic implementation is:
def set_a(self, value): if self._member_a == value: return self._member_a = value self.a_changed.emit(value) -
In what way is it less simple ?
The only simpler would be:
def set_a(self, value): if self._member_a != value: self._member_a = value self.a_changed.emit(value) -
Thanks - the
emitis a necessary addition, I agree. I meant that adding a line by definition makes code less simple.But what I really don't understand is why I would need the
onEditingFinishedhandler in the qml itself. I was hoping to get the 2-way binding working without explicit event handling, by just bindingTextfield.textproperty tomodel.aproperty. -
Thanks - the
emitis a necessary addition, I agree. I meant that adding a line by definition makes code less simple.But what I really don't understand is why I would need the
onEditingFinishedhandler in the qml itself. I was hoping to get the 2-way binding working without explicit event handling, by just bindingTextfield.textproperty tomodel.aproperty.@xtofl In QML the binding is unidirectional: from right to left:
Foo { id: foo a: bar.b }This binding indicates that every time the property "b" (which must be a signal) of the object "bar" then the property "a" of the object "foo" will be updated with that value. In python it would be something like:
bar.b_Signal.connect(lambda: setattr(foo, "a", foo.b))If you want to implement a 2-way binding then create a class that listens when one of those properties change ("a" or "b") and then updates the other.