Better_Software_Header_MobileBetter_Software_Header_Web

Find what you need - explore our website and developer resources

QML Component Design

The Two-Way Binding Problem and How to Avoid It

// CheckBox.qml (simplified)
Item {
    id: root

    property bool checked: false;
    property alias text: label.text

    Rectangle {
         color: root.checked ? 'black' : 'white'
    }

    Text {
        id: label
    }

    MouseArea {
        anchors.fill: parent
        onClicked: root.checked = !root.checked
    }
}
// in main.qml
CheckBox {
    id: colorCheckbox

    anchors {
        //... position the checkbox
    }

    text: "Make it Blue"

    //Todo: hook up to _controller's isBlue property in both directions
}
CheckBox {
    id: colorCheckbox
    // other properties, positioning, ...

    checked: _controller.isBlue
    onCheckedChanged: _controller.isBlue = checked;
}
//Checkbox.qml, Proposed Value version (simplified)
Item {
    id: root

    property bool checked: false;
    property alias text: label.text

    signal checkedProposed(bool proposedChecked)

    //UI related code...

    MouseArea {
        anchors.fill: parent
        onClicked: root.checkedProposed( !root.checked )
    }
}
CheckBox {
     id: colorCheckbox

     checked: _controller.isBlue
     onCheckedProposed: _controller.isBlue = proposedChecked;
}
CheckBox {
    id: colorCheckbox
    // other properties, positioning, ...

    checked: _controller.isBlue
    onCheckedChanged: _controller.isBlue = checked;
}
Item {
    id: root

    property alias checked: internal.isOn
    property alias text: label.text

    //UI related code...

    BooleanValue {
        id: internal
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            internal.toggle(); // works, using convenience function on BooleanValue
            // internal.setOn(!internal.isOn) // works too
            // internal.isOn = !internal.isOn // Wrong: breaks the binding
        }
    }
}
class BooleanValue : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool isOn READ isOn WRITE setOn NOTIFY isOnChanged)

public:
    explicit BooleanValue(QObject *parent = nullptr);
    bool isOn() const;

public slots:
    void setOn(bool isOn); // Be sure to make it a slot or Q_INVOKABLE

    //convenience API is now possible
    void toggle();

signals:
    void isOnChanged(bool isOn);

private:
    bool m_isOn = false;
};
CheckBox {
    //BAD: don't create bindings in an imperative way
    function isBlueBinding() {
        return _controller.isBlue;
    }

    checked: isBlueBinding()

    onCheckedChanged: {
        _controller.isBlue = checked;
        checked = Qt.binding(isBlueBinding);
    }
}
SomeController {
    id: colorController
}

CheckBox {
    //BAD: API is unclear and inflexible
    property alias checked: colorController.isBlue
}
class SomeController : public QObject
{
    Q_OBJECT
    //BAD: Wastefull and overly bloated
    Q_PROPERTY(BooleanValue *isBlue READ isBlue CONSTANT)

public:
    explicit SomeController(QObject *parent = nullptr);
    BooleanValue *isBlue() const;

private:
    BooleanValue *m_isBlue;
};
CheckBox {
    model: _controller.isBlue
}
CheckBox {
    id: colorCheckbox

    onCheckedChanged: _controller.isBlue = checked;

    Binding {
        target: colorCheckBox
        property: "checked"
        value: _controller.isBlue
    }
}
CheckBox {
    id: colorCheckbox
    onCheckedChanged: _controller.isBlue = checked;

    Connections {
        target: _controller
        onIsBlueChanged: colorCheckbox.checked = isBlue;
    }
}

About KDAB


11 Comments

22 - Dec - 2021

stef

22 - Dec - 2021

André Somers

8 - Aug - 2024

Adam

19 - Aug - 2024

André

22 - Dec - 2021

grecko

23 - Dec - 2021

André Somers

22 - Dec - 2021

GrecKo

CheckBox {
    checked: backend.isBlue
    onToggled: {
        backend.isBlue = checked;
        checked = Qt.binding(() => backend.isBlue);
    }
}

22 - Dec - 2021

André Somers

22 - Dec - 2021

grecko

27 - Jan - 2022

Sander Valcke

27 - Jan - 2022

André Somers

AndréSomers

André Somers

Senior Software Engineer

Learn Modern C++

Learn more