Problems with Open-Source Downloads read https://www.qt.io/blog/problem-with-open-source-downloads and https://forum.qt.io/post/638946

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 to thisComboBox
    • myTarget is a pointer to a QObject. This pointer identifies which, out of the aforementioned list of QObjects, should be bound to thisComboBox
    • someProperty is the property of the chosen child QObject that should be bound to thisComboBox
    • onTargetChanged is a signal that is emitted by myMainObject when myTarget changes to point to a new QObject

  • Moderators

    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:

    1. 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.
    2. 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 of myTarget (myTarget is a pointer to a QObject) to currentIndex of thisComboBox:

    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 within myMainObject. myTarget can change based on user input to point to any of these QObjects from my list. So, when myTarget points at a new object, both the new object and the old object are bound to thisComboBox whereas I would like only the current object that myTarget 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.


Log in to reply