Bidirectional binding properties between QML and Cpp



  • Hi,
    I have a GUI element (e.g. switch) whose state is binded to some Cpp objects property and vice versa, e.g.:

    window.qml:
    MySwitch {
      state: myCppObject.property
      onStateChanged: myCppObject.property = state
    }
    
    MySwitch.qml:
    Item {
      property bool state
      
      MouseArea {
        onCLicked: state= !state
      }
    
      Rectangle {
        color: state ? "black" : white
      }
    }
    

    My implementation (the code above) has one problem. When user clicks the switch ( onCLicked: state = !state is executed) then setting value of the switch from backend stops working (because binding state: myCppObject.property now doesn't exist - at least I think so).

    What is the "nicest" way to make bidirectional bindings?



  • @MartinD hi,

    MySwitch {
      state: myCppObject.property
      // onStateChanged: myCppObject.property = state No need this
    }
    
    
    Item {
      property bool state
      
      MouseArea {
        onClicked : { myCppObject.property = !myCppObject.property } // onCLicked: state= !state
     //do this to your cpp object directly so the QML will follow ..   
      }
    
      Rectangle {
        color: state ? "black" : white
      }
    }
    


  • @LeLev Thanks. I forgot to mention that MySwitch is reausable component. It is instantiated multiple times throughout my code and binds different properties.



  • @MartinD said in Bidirectional binding properties between QML and Cpp:

    reausable

    then simply emit a signal and catch it in right place to do what ever you need after

    signal tglState()
     MouseArea {
        onClicked : { tglStage() }
      }
    


  • I tried same thing with QML CheckBox:

    CheckBox {
      text: "CheckBox"
      checked: cppObject.property
      onCheckedChanged: cppObject.property = checked
    }
    

    And again, this doesn't work - checkbox is checked and once something else other than checkbox changes cppObject.property to false, checkbox remains checked.

    How to make bidirectional binding for this checkbox? Pleae also consider that cppObjet can be set to null sometimes and when it is set to valid object checked property of checkbox must be also correctly reevaluated.


  • Moderators

    @MartinD

    I think in this case, you'll have to forgo binding.

    MySwitch {
      id: sSwitch
      state: myCppObject.property //Now only the initial state during construction
      onStateChanged: myCppObject.property = state
      Connections{
          target: myCppObject
          onPropertyChanged: sSwitch.state = property
      }
    }
    

  • Qt Champions 2018

    Another way to do it would be to reassign the binding after:

    MySwitch {
        id: sSwitch
        state: myCppObject.property
        onStateChanged: {
          myCppObject.property = state;
          state = Qt.binding(() => myCppObject.property);
        }
    }
    

    Qt Quick Controls 2 do some magic in c++ so that you don't have to rebind. Using a QQC2.Switch and just customizing its appareance would be a solution too.



  • @J.Hilk Thanks, that will almost work. But it can also happen that myCppObject can be set to null (during that the switch is not valid and e.g. should not be visible to the user) and then myCppObject is set to a valid instance. If myCppObject.property and switch state holds different values then the switch will be in incorrect state. So it seems that I have to write another piece of code to deal with this.

    Really, is it so difficult in QML to make bidirectional binding? Isn't there any better way?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.