Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Two way property binding in QML



  • Hello.

    I'm trying to define a property in the back end bind it to a qml checkbox with the goal that when the QML checkbox checked value is changed so will the property value. (And the other way around, when the property changes, so will the checked value of the checkbox)
    Sadly I only managed to do it in one way. Python -> QML. When I set the value in python, the changes indeed reflect to QML. However, it doesn't work the other way around.

    Here is what I did:
    I defined a property in Python like so:

    class ContextPropertyExposedClass(QObject):
    
        def __init__():
            super().__init()
            self._checked: bool = False
        
        #getter
        def checked(self):
            return self._checked
        
        #setter
        def set_checked(self,checked_state):
            self._checked = checked_state
        
        #signal emitted when property changes
        @Singal
        def checked_changed(self):
            pass
        
        #slot to test if value changed on backend
        @Slot()
        def print_checked(self):
            print(f"Checked:{self._checked}")
    
        checked = Property(bool, fget=checked,fset=set_checked notify=checked_changed)
    

    And then in QML:

    CheckBox {
        text: "Is Checked"
        checked: ContextPropertyExposedClass.checked
    }
    
    Button{
        onClicked:{
            ContextPropertyExposedClass.print_checked()
        }
    }
    

    When I set the value of checked in Python it's correctly reflected to QML. However, when I change the checkbox value in QML, and then click the button to print the values, the values in python stay the same. The setter function never gets called when the value changes in QML. I also tried to connect a slot to the checked_changed signal to see if it's emitted when the value is changed from QML. It did not fire.

    If I do:

    CheckBox {
        text: "Is Checked"
        checked: ContextPropertyExposedClass.checked
        onCheckedChanged:{
            ContextPropertyExposedClass.checked = checked
        }
    }
    

    Then it works. But I thought the whole point of binding is that the change is reflected automatically without this additional step. Am I missing something? Is this the intended behavior?



  • Its NOT bidirectional. There are ways to bind to the values from other objects and C++, but it is about as messy as doing it from the on<value>Changed signal.

    https://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html
    https://doc.qt.io/qt-5/qml-qtqml-binding.html


Log in to reply