How to break property bindings to c++ QObjects
-
So I found lots of documentation about how to create property bindings in QT, but not so much how to un-bind those properties.
In my application, I have a list of QObjects that the user can select and then interact with. Initially, it loads some data for those objects and then initializes some QtQuick controls in the app GUI with that data, then binds the control values to the objects. In QtQuick, I use the javascript such as the following to set that up:
MyComboBox{ id: thisCombobox ... Component.onCompleted: { thisCombobox.currentIndex = (myMainObject.myTargetObject.someProperty) myMainObject.myTargetObject.someProperty = Qt.binding(function() { return (thisComboBox.currentIndex) }) } Connections { target: myMainObject onTargetChanged: { thisComboBox.currentIndex = (myMainObject.myTarget.someProperty) //Note: myTarget now points to a different object from before myMainObject.myTarget.someProperty = Qt.binding(function() { return (thisComboBox.currentIndex) }) } } }
My problem is that when the user selects a new target object, the property binding to the other object is maintained and now the combobox is changing properties for two objects at once (or more after each new selection).
Can anyone advise me on what are my options for breaking these bindings that have been setup when they are no longer wanted?
I think one possible solution could be for my object to emit a separate signal just before a new target is selected so that these bindings can be broken, however, if there is a way within the C++ code to break all bindings prior to a target change, then that might be a much simpler solution for me.
Edit: to clarify the above code snippet here are some definitions:
thisComboBox
is a custom version of QComboBox that I have made in QML. Though it could be any QControl class for the purpose of this thread.myMainObject
is the main C++ object within my application. Noteably, it contains a list of similar child objects that I am selectively binding tothisComboBox
myTarget
is a pointer to a QObject. This pointer identifies which, out of the aforementioned list of QObjects, should be bound tothisComboBox
someProperty
is the property of the chosen child QObject that should be bound tothisComboBox
onTargetChanged
is a signal that is emitted bymyMainObject
whenmyTarget
changes to point to a new QObject
-
Item { id: thatItem // This establishes a binding visible: someObject.someProperty }
// This breaks the binding thatItem.visible = false
Also, you can use Binding QML component to set up bindings more explicitly, and to have more control over them.
-
The problem is I'm binding to my C++ QObject and in QML I no longer have a handle to the old target object when I get the signal to bind to a new target object.
From my current understanding of bindings, I can see two possible solutions:
- I can emit an additional signal before the target is changed to tell QML to break the binding while it still has a handle to the old target.
- Add a property to my main QObject which has a pointer to the previous target, this way QML has a way of knowing which object to break the binding for.
I was hoping there would be a way to break the binding in C++ or to just break the bindings to all of the objects. Perhaps I can do this with a for loop, I'll have to sharpen my java skills, though.
-
@kgregory said in How to break property bindings to c++ QObjects:
The problem is I'm binding to my C++ QObject and in QML I no longer have a handle to the old target object when I get the signal to bind to a new target object.
What mechanism causes "thisComboBox" to no longer be the object you want to be bound to? Can this object be assigned to a higher level property and have the value bound to that property?
-
@fcarney this last line of the code I posted above binds property
someProperty
ofmyTarget
(myTarget is a pointer to a QObject) tocurrentIndex
ofthisComboBox
:myMainObject.myTarget.someProperty = Qt.binding(function() { return (thisComboBox.currentIndex) })
So whenever you interract with
thisComboBox
,someProperty
gets a new value.Again,
myTarget
is a pointer to a QObject, one of many similar QObjects that I hold in a list withinmyMainObject
.myTarget
can change based on user input to point to any of these QObjects from my list. So, whenmyTarget
points at a new object, both the new object and the old object are bound tothisComboBox
whereas I would like only the current object thatmyTarget
points to to be bound. -
I suggest restructuring the bindings to avoid changing them after creation of the control.
MyComboBox { id: thisComboBox onCurrentIndexChanged: myMainObject.myTarget.someProperty = thisComboBox.currentIndex Connections { target: myMainObject onTargetChanged: thisComboBox.currentIndex = myMainObject.myTarget.someProperty } }
-
Look into conditional binding:
https://doc.qt.io/qt-5/qml-qtqml-binding.html#conditional-bindings
At some point you bind to the value based upon a condition. That would be in the when clause:Binding { target: myMainObject.myTarget property: "someProperty" value: thisComboBox.currentIndex when: <some condition> }
You might want to look at restoreMode in case you have a value or binding you need to restore.