PDA

View Full Version : Very basic question on how to setup a QT quick checkbox.



philp
1st September 2015, 22:08
I am new to QT quick and am having difficulty understanding the basic sequence of how items are executed. Sorry if the question is so basic. I have worked my way through an example that has the date/time and weather information. The top level item is a Rectangle and it has a bool property called forceOffline. Now this property can be changed by either a Config button which brings up a dialog set of checkboxes (one of which modifies it) or a single button at the top level.
My problem is that if I tick the checkbox to change the forceOffline property and then use the single button to switch back and then go back to the dialog the checkbox remains checked. Sorry if I have not made this very clear. Below I have my checkbox item


import QtQuick 2.3

Item {
id: root
property bool checked: true
width: checkBox.width
height: checkBox.height

Image {
id: checkBox
source: root.checked ?
"../../content/resources/checkbox.png" :
"../../content/resources/draw-rectangle.png"
Keys.onPressed: {
if (event.key == Qt.Key_Return ||
event.key == Qt.Key_Enter ||
event.key == Qt.Key_Space)
root.checked = !root.checked;
}
MouseArea {
anchors.fill: parent
onClicked: {
root.checked = !root.checked;
}
}
}
}

I use code like


CheckBox {
id: offlineCheckBox
checked: root.forceOffline
KeyNavigation.up: secondsCheckBox
KeyNavigation.down: locationTextInput
}

to create an instance of the Checkbox. I thought that the binding of "checked: root.forceOffline" would ensure that the checkbox was correctly ticked or not depending on its boolean state. Can anybody help me understand this?
AS another quick question, when dealing with ordinary QT C++ you can always add a diagnostic to discover the current status of a variable. Not sure how you do this in QT quick..the closest I seem to be able to do is to do things like:


onForceOfflineChanged: {
console.log ("onForceOfflineChanged= " + forceOffline)

}

QT Quick is very different to what I have been used to.

Thank you for reading this.

anda_skoa
1st September 2015, 23:05
The problem you encounter is that the imperative code inside checkbox assigns a value to the checked property.
This assignment overwrites the property binding you had initially set on that property.

You have a couple of options (none of which are particularily pretty):

1) define a signal in CheckBox and send that signal instead of changing the checked property.
In the signal handler toggle the forceOffline property

2) keep CheckBox as it is and restore the binding when it is overwritten



CheckBox {
id: offlineCheckBox
checked: root.forceOffline

onCheckedChanged: {
root.forceOffline = checked;
checked = Qt.binding(function() { return root.forceOffline; });
}
}


3) using a Connections element instead of the original binding


CheckBox {
id: offlineCheckBox
checked: root.forceOffline

onCheckedChanged: root.forceOffline = checked
Connections {
target: root
onForceOfflineChanged: parent.checked = root.forceOffline
}
}


And probably more.

Cheers,
_

philp
5th September 2015, 14:08
Thank you for your help anda_skoa; I really appreciate your help. I tried your second solution and it worked beautifully :). As soon as I get enough time I will try the other solutions out as well. I have a lot to learn about QT quick and I am still confused about how the binding works. Initially i thought that they work a bit like reference variables...in that if one property changes then the other will also. Would you be so kind as to explain a little more about your statement

The problem you encounter is that the imperative code inside checkbox assigns a value to the checked property.
This assignment overwrites the property binding you had initially set on that property.

I assume that the original binding is "checked: root.forceOffline" as specified when the CheckBox is first created i.e. in the code

CheckBox {
id: offlineCheckBox
checked: root.forceOffline
}

Is it the line "root.checked = !root.checked;" that destroys this binding when inside of the CheckBox item (Module)?
I am really sorry if my question is very basic and has totally a misunderstanding of bindings.
Thanks again very much for your time

anda_skoa
5th September 2015, 15:04
Initially i thought that they work a bit like reference variables...in that if one property changes then the other will also.

That is actually not a bad way to look at it.
A property binding is just even more advanced since it can contain references to several other properties as part of the binding expression.



I assume that the original binding is "checked: root.forceOffline" as specified when the CheckBox is first created i.e. in the code

CheckBox {
id: offlineCheckBox
checked: root.forceOffline
}

Yes, that I what I meant.



Is it the line "root.checked = !root.checked;" that destroys this binding when inside of the CheckBox item (Module)?

Yes, you are correct.

Basically you are writing the "checked" property in two places, once during setup of the element and once during execution of the onClicked signal handler.

If we forget for a moment that the initial value is not just a fixed value but a binding, we can look at this like having two places in C++ code writing to the same member variable.
After the second write that value is the current one and any knowledge about any earlier value is "lost".

The problems here are that
(a) this is not very visible (one write happening inside the component)
and
(b) the original "value" being a binding which we know would be updating the property automatically

So the assignment executed by the onClicked signal handler does not only change the value (which would be OK, we want it to do that), but it also removes this "auto-update" feature and we want to keep that.



I am really sorry if my question is very basic and has totally a misunderstanding of bindings.
Thanks again very much for your time

Not at all!
This is one of the trickier parts of QML and even experienced developers hit it now and then, sometimes not recognizing it immediately.

Cheers,
_

P.S.: in case you haven't discovered it yet: the QtQuick.Controls module provides standard UI components such as a check box