I'm playing around with QtQuick in Qt 5.9 and I encountered a strange issue.
When I created two Tumblers
and a CheckBox
in QML everything was working fine.
But when I created an event handler for a id: secondTumbler
which manipulates testCheckBox.checked
status the CheckBox
started to act in a strange way.
When I launch the app and firstly scroll around any tumbler and then click the CheckBox
it will not check. The second click will eventually check it but that is a strange behavior.
The only thing I wrote is the below code in the main.qml:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Tumbler {
id: firstTumbler
model: 10
anchors.left: parent.left
}
Tumbler {
id: secondTumbler
model: 10
anchors.right: parent.right
onCurrentIndexChanged: {
testCheckBox.checked = false
}
}
CheckBox {
id: testCheckBox
anchors.left: firstTumbler.right
onCheckedChanged: {
if(testCheckBox.checked == true)
{
secondTumbler.currentIndex = firstTumbler.currentIndex
}
}
}
}
What am I missing?
The issue is that javascript runs asynchronously. So, signals and slots dont work as they do in C++. They fire along with the other code, not sequentially. This makes them an unrealiable Intermediary for logical processing since the order that events can happen can vary.
Instead,
Use property bindings for this one by setting a property such as currentIndex to another property created using property var <my property>
and currentIndex: <my property>
Then you can change the value of currentIndex by setting <my property>
without disrupting the flow of things.
Tumbler {
id: firstTumbler
model: 10
anchors.left: parent.left
}
/* Edit in response to comment #1
*/
property bool followFirst: testCheckbox.checked
/* end of Edit in response to comment #1 */
Tumbler {
id: secondTumbler
model: 10
/* modify the property of currentIndex by changing this variable which will be bound to the currentIndex property */
property var m_index: 0
anchors.right: parent.right
/* conditional assignment for currentIndex -- do not set currentIndex directly or this will disappear..
instead set secondTumbler.m_index */
currentIndex: testCheckBox.checked === true ? firstTumbler.currentIndex : m_index
/* ensures that changing the currentIndex does not change the actual property, but instead changes m_index which will be bound to that property */
onCurrentIndexChanged: {
m_index = currentIndex;
/* Edit in response to comment #1
*/
if (followFirst) { testCheckBox.checked = false }
/* end of Edit in response to comment #1 */
}
}
this will allow the chckbox to change state along with the tumbler without running into state conflicts arising from the current index changing.