Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding Checkbox 'checked' property with a C++ object Q_PROPERTY

I'm learning QtQuick and I'm playing with data binding between C++ classes and QML properties.

In my C++ object Model, I have two properties :

Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(bool status READ getStatus WRITE setStatus NOTIFY statusChanged)

And in my .qml file :

TextEdit {
    placeholderText: "Enter your name"
    text: user.name
}

Checkbox {
    checked: user.status
}

When I change the user name with setName from my C++ code, it is automatically reflected in the view. When I check/uncheck the checkbox, or when I call setStatus() from my C++ code, nothing happens. It seems the property checked of checkboxes haven't the same behavior as TextEdit components.

I don't want to bind my properties in a declarative way. Doesn't Qt Quick support property binding ?

Thank you for your help.

like image 532
Neozaru Avatar asked May 25 '14 21:05

Neozaru


3 Answers

As leemes points out, user clicking the check box breaks the binding you've created. So, don't create the binding, but instead connect to the change signal directly to handle the "get" case. Use "onClicked" to handle the "set" case. This solution requires you also initialize in Component.onCompleted(). For example...

CheckBox {
    id: myCheck
    onClicked: user.status = checked
    Component.onCompleted: checked = user.status
    Connections {
        target: user
        onStatusChanged: myCheck.checked = user.status
    }
}
like image 89
Mike Avatar answered Oct 23 '22 01:10

Mike


A way around this is to restore the binding (that gets removed by the user clicking the checkbox) in onClicked, by something like:

CheckBox {
    checked: user.status
    onClicked: {
        user.status = checked;
        checked = Qt.binding(function () { // restore the binding
            return user.status;
        });
    }
}

This avoids problems if you don't have the possibility to access your model at the time Component.onCompleted is invoked.

like image 39
jco Avatar answered Oct 23 '22 03:10

jco


I find it more natural to make checkbox only emit signal on click, not change its state:

// MyCheckBox.qml 
CheckBox {
   id: control

   property bool changeOnClick: true // or just emit clicked()

    MouseArea {
        anchors.fill: parent
        enabled: !control.changeOnClick
        onClicked: control.clicked();
    }
}

Then you can bind it once and request change of the source on click:

MyCheckBox {
    changeOnClick: false
    checked: user.state
    onClicked: {
        user.state = !user.state;
    }
}
like image 44
rsht Avatar answered Oct 23 '22 01:10

rsht