Strange binding behavior when using binding on array's element
-
Hi @geniuss
var element = testObject.myArray[0] element.boolFlag = true
Here you are updating the copy and not that object in array. Replace
element
withtestObject.myArray[0]
and you should notice the update. -
Indeed, you're correct. This example was supposed to be a simulation of a problem from a real project which is too big to be posted in full here.
But this example is wrong. I will make another example once I figure out how to reproduce the problem. -
Keep in mind that bindings to "var" properties may not work as expected since they don't emit "changed" signals when they're modified. You might need to manually call myArrayChanged() after modifying it for the binding to work as expected.
-
Okay, I managed to reproduce it. But for this I had to add C++ part.
C++ code is this:
// main.cpp #include <QGuiApplication> #include <QQuickWindow> #include <QQmlApplicationEngine> #include <QQmlContext> class Test : public QObject { Q_OBJECT Q_PROPERTY(QString emptyString READ getEmptyString NOTIFY valueChanged) QString getEmptyString(){ return ""; } public: Test(QObject* parent = 0) : QObject(parent) {} Q_INVOKABLE void triggerNotify() { valueChanged(); } signals: void valueChanged(); }; int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; Test* test = new Test(&engine); engine.rootContext()->setContextProperty("__test__", (QObject*)test); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, [](QObject* rootObject) { QQuickWindow *appWindow = qobject_cast<QQuickWindow *>(rootObject); appWindow->show(); }); engine.load(QUrl(QStringLiteral("qrc:/ui/main.qml"))); return app.exec(); }
QML code is this:
// main.qml import QtQuick 2.4 import QtQuick.Controls 1.3 ApplicationWindow { id: container width: 640 height: 480 property int clicksCounter: 0 Item { id: testObject property var myArray : [{ name : "CustomName" + __test__.emptyString, 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::triggerNotify> 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__.triggerNotify() 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] : DONEqml: CLICK #2[BLUE SQUARE] : Triggering notify by calling C++ Test::triggerNotify 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: falseSo what happens here is that after I set testObject.myArray[0].boolFlag from FALSE to TRUE and call test.triggerNotify() method my flag automatically resets to its initial value. Same goes if any other type used - int, string, etc. Why does this happen?
[UPDATE] QT 5.5 is used, Visual Studio 2013 Update 4 x32.
-
@geniuss Here is you answer:
http://doc.qt.io/qt-5/qml-var.html#change-notification-semantics
Edit: But that doesn't justify why it becomes false O_o -
Exactly, there is no connection between "change notification semantics" for "var" and my problem.
-
@geniuss I think that is the way how it works. A change of that string will trigger reevaluation of the property
myArray
and thus causing theboolFlag
to get its original value i.efalse
. -
This is madness then :) It should not work that way normally in my understanding.
Perhaps I'll post this as a bug if no one gives me a suitable answer. -
@geniuss I would suggest you to ask at Qt Interest Mailing List. You can get an answer directly from Qt Engineers regarding these internals.
-
@p3c0 I tried but that didn't work. Folks on Stack Overflow don't know either. I got no other choice :
https://bugreports.qt.io/browse/QTBUG-47407