I have an Item
with a property. This property contains an array of JavaScript objects wich in turn contain other properties.
When I set binding for one of object's properties to some variable and its (variable) value changes triggering the binding then all properties in the array are reset to their initial values. I've created a small demo to show the problem.
C++ code:
// main.cpp
#include <QGuiApplication>
#include <QQuickWindow>
#include <QQmlApplicationEngine>
#include <QQmlContext>
class Test : public QObject
{
Q_OBJECT
Q_PROPERTY(QString value READ value NOTIFY valueChanged)
public:
Test(QObject* parent = 0) : QObject(parent) {}
QString value() const { return ""; }
Q_SIGNAL void valueChanged();
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Test test;
engine.rootContext()->setContextProperty("__test__", &test);
engine.load(QUrl(QStringLiteral("qrc:/ui/main.qml")));
return app.exec();
}
#include "main.moc"
QML code:
// main.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
id: container
visible: true
width: 640
height: 480
property int clicksCounter: 0
Item {
id: testObject
property var myArray : [{
name : "CustomName" + __test__.value,
boolFlag : false
}]
}
Rectangle {
x: 10
y: 10
width: 100
height: 100
color: "red"
MouseArea {
anchors.fill: parent
onClicked: {
container.clicksCounter++
console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : Set testObject.myArray[0] to TRUE\n")
testObject.myArray[0].boolFlag = true
console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : DONE\n")
}
}
}
Rectangle {
x: 120
y: 10
width: 100
height: 100
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
container.clicksCounter++
console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : Triggering notify by calling C++ <Test::valueChanged> method \n")
console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : [BEFORE] testObject.myArray[0].name: " + testObject.myArray[0].name + ', testObject.myArray[0].boolFlag: ' + testObject.myArray[0].boolFlag)
__test__.valueChanged()
console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : [AFTER] testObject.myArray[0].name: " + testObject.myArray[0].name + ', testObject.myArray[0].boolFlag: ' + testObject.myArray[0].boolFlag)
}
}
}
}
Here is what I get:
qml: CLICK #1[RED SQUARE] : Set testObject.myArray[0] to TRUE qml: CLICK #1[RED SQUARE] : DONE
qml: CLICK #2[BLUE SQUARE] : Triggering notify by calling C++ <Test::valueChanged> method
qml: CLICK #2[BLUE SQUARE] : [BEFORE] testObject.myArray[0].name: CustomName, testObject.myArray[0].boolFlag: true qml: CLICK #2[BLUE SQUARE] : [AFTER] testObject.myArray[0].name: CustomName, testObject.myArray[0].boolFlag: false
So what happens here is that after I set testObject.myArray[0].boolFlag
from false
to true
and call test.valueChanged()
method, my flag automatically resets to its initial value. Same goes for any other type used - int
, string
, etc.
Why does this happen?
Visual Studio has update 4 installed.
visible
property lets you show the window on startup. All signals are invokable by definition, so you don't need to forward them to another invokable method. It might be a Qt bug in the binding implementation in QML... – Kuba hasn't forgotten Monica