How to avoid binding loop when binding to Python/C++ backend?
-
Greetings,
I have the the following component:
main file:
InputPaneRow{ id:sourceFolderInputRow Layout.preferredWidth: parent.width Layout.preferredHeight: parent.height * 0.5 lableText: "Source Folder Path:" inputPlaceHolderText: "Please Select Folder to scan." inputText: gui_data.source_folder_path // <=***Binding *** browseButtonText: "Browse" openButtonText: "Open" }
InputPaneRow.qml
Pane{ id:inputPaneRowRoot property alias lableText: inputPaneRowLabel.text property alias inputPlaceHolderText: inputPaneRowTextField.placeholderText property alias inputText: inputPaneRowTextField.text <= ***binding alias*** property alias browseButtonText: inputPaneRowBrowseButton.text property alias openButtonText: inputPaneRowOpenButton.text // background: Rectangle{ // color: Material.color(Material.Cyan) // } signal browseButtonClicked() signal openButtonClicked() RowLayout { id:inputPaneRowRowLayout width: parent.width height: parent.height anchors.fill: parent Label { id: inputPaneRowLabel // font.pixelSize: parent.height * 0.45 Layout.preferredWidth: parent.width * 0.2 // Layout.minimumWidth: 180 } TextField { id: inputPaneRowTextField Layout.preferredWidth: parent.width * 0.5 Layout.minimumWidth: 250 } Button{ id: inputPaneRowBrowseButton Layout.minimumWidth: 50 onClicked: { inputPaneRowRoot.browseButtonClicked() } } Button{ id: inputPaneRowOpenButton Layout.minimumWidth: 50 onClicked: { inputPaneRowRoot.openButtonClicked() } } Item{ id:spacer Layout.fillWidth: true } } }
There is a binding
inputText: gui_data.source_folder_path
wheregui_data
is a context property of a Python class andsource_folder_path
is a property (fully implmented with getter,setter and a notify signal).This binding works when the value is set from elsewhere. But I also want any text changes in
inputPaneRowTextField
(Which the aboveinputText
is an alias of will also reflect those changes back to the python class.) Meaning when the user changes/types in the textfield, the property in python should be updated.I tried to do something like this:
InputPaneRow{ id:sourceFolderInputRow inputText: gui_data.source_folder_path onInputTextChanged: { gui_data.source_folder_path = sourceFolderInputRow.inputText } }
This works (even though it obviously creates a binding loop.) I guess there is a safety measure to break those kind of loops.
Question is, how do I reflect changes back togui_data
without using this. As far as I understand the initial binding should have been enough. Maybe it has something to do with aliasing? -
No one knows?
-
@Curtwagner1984 said in How to avoid binding loop when binding to Python/C++ backend?:
InputPaneRow
Would be nice if you would describe what you are trying to do it is unclear what
InputPaneRow
is.
Anyway from what I see you want two bindings for same property is that right?
in that case you can create new property that is, say, the sum of both of them and bind to that property.
other solution would be that the getter of the python class would return the other property as well. -
Can you avoid the binding in the first place and just set on creation of the component?
InputPaneRow{ id:sourceFolderInputRow //inputText: gui_data.source_folder_path onInputTextChanged: { // if a binding is involved you should be checking if it actually needs updating, only needed if using binding if(gui_data.source_folder_path !== sourceFolderInputRow.inputText) gui_data.source_folder_path = sourceFolderInputRow.inputText } Component.onCompleted: inputText = gui_data.source_folder_path }
-
Don't use on<Property>Changed to set value back to the backend.
You need to use the special user change signal emitted by the Control.
If your control is a TextField the signal you want is textEdited, not textChanged.