3

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.

4

1 回答 1

1

非常棘手,但这是 QML 的预期行为。您所遭受的是绑定分配与程序分配之间的冲突,这是 QML 的常见缺陷。

首先,您已经设置了一个绑定myArray(实际上)表示任何时间__test__.value更改,重新分配一个文字数组到myArray. 稍后您通过程序修改该数组来破坏该绑定。请记住,文字数组实际上是每次在绑定中触发信号时都会评估的 JavaScript 代码。

因此,您在最后一个 console.log 中看到的并不是 bool 已恢复,而是整个 myArray 已重置为新值,从绑定中重建。

您真正想要的是一个可以分配的新 bool 属性,并且您的文字数组绑定到该属性。像这样:

property bool myBoolFlag: false
property var myArray : [{
        name : "CustomName" + __test__.value,
        boolFlag : myBoolFlag
    }]

然后,当您分配给myBoolFlag数组时,将重建。当你触发数组时valueChanged,数组也会被重建,但这次 bool 值是从属性中提取的并且具有正确的值。

于 2015-08-11T16:00:28.360 回答