Qt 在数组上使用绑定时出现奇怪的绑定行为';s元素

Qt 在数组上使用绑定时出现奇怪的绑定行为';s元素,qt,visual-studio-2013,qml,qtquick2,qt5.5,Qt,Visual Studio 2013,Qml,Qtquick2,Qt5.5,我有一个带有属性的项。此属性包含JavaScript对象数组,而JavaScript对象数组又包含其他属性 当我将对象的一个属性的绑定设置为某个变量并且其(变量)值更改触发绑定时,数组中的所有属性都将重置为其初始值。 我创建了一个小演示来演示这个问题 C++代码: // main.cpp #include <QGuiApplication> #include <QQuickWindow> #include <QQmlApplicationEngine> #in

我有一个带有属性的
。此属性包含JavaScript对象数组,而JavaScript对象数组又包含其他属性

当我将对象的一个属性的绑定设置为某个变量并且其(变量)值更改触发绑定时,数组中的所有属性都将重置为其初始值。 我创建了一个小演示来演示这个问题

C++代码:

// 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"
//main.cpp
#包括
#包括
#包括
#包括
类测试:公共QObject
{
Q_对象
Q_属性(QString值读取值通知值更改)
公众:
测试(QObject*parent=0):QObject(parent){}
QString value()常量{return”“;}
Q_信号无效值已更改();
};
int main(int argc,char*argv[])
{
QGUI应用程序应用程序(argc、argv);
qqmlaplicationengine;
试验;
engine.rootContext()->setContextProperty(“\uuuuuu test\uuuuuuuuuuuuuuuuu”和&test);
engine.load(QUrl(QStringLiteral(“qrc:/ui/main.qml”));
返回app.exec();
}
#包括“main.moc”
QML代码:

// 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)
            }
        }
    }
}
//main.qml
导入QtQuick 2.4
导入QtQuick.Controls 1.3
应用程序窗口{
id:集装箱
可见:正确
宽度:640
身高:480
属性int ClicksCenter:0
项目{
id:testObject
属性变量myArray:[{
名称:“CustomName”+_测试值,
boolFlag:false
}]
}
长方形{
x:10
y:10
宽度:100
身高:100
颜色:“红色”
鼠耳{
锚定。填充:父级
再次点击:{
container.ClicksCenter++
console.log(“单击#“+container.ClicksCenter+”[RED SQUARE]:将testObject.myArray[0]设置为TRUE\n”)
testObject.myArray[0]。boolFlag=true
console.log(“单击#“+container.clicksCenter+”[RED SQUARE]:完成\n”)
}
}
}
长方形{
x:120
y:10
宽度:100
身高:100
颜色:“蓝色”
鼠耳{
锚定。填充:父级
再次点击:{
container.ClicksCenter++
控制台。日志(“单击”+”+容器。点击计数器+ [ [蓝色方] ]:通过调用C++方法\n触发通知
console.log(“单击#“+container.ClicksCenter+”[BLUE SQUARE]:[BEFORE]testObject.myArray[0]。名称:“+testObject.myArray[0]。名称+”,testObject.myArray[0]。boolFlag:“+testObject.myArray[0]。boolFlag)
__测试值已更改()
console.log(“单击#“+container.ClicksCenter+”[BLUE SQUARE]:[AFTER]testObject.myArray[0]。名称:“+testObject.myArray[0]。名称+”,testObject.myArray[0]。boolFlag:“+testObject.myArray[0]。boolFlag)
}
}
}
}
以下是我得到的:

qml:单击#1[红色方框]:将testObject.myArray[0]设置为TRUE qml: 单击#1[红色方块]:完成

qML:单击“2”[蓝色方]:通过调用C++触发通知 方法

qml:单击#2[蓝色方框]:[之前]testObject.myArray[0]。名称: CustomName,testObject.myArray[0]。boolFlag:true qml:单击#2[蓝色] SQUARE]:[AFTER]testObject.myArray[0]。名称:CustomName, testObject.myArray[0]。boolFlag:false

所以这里发生的事情是,在我将
testObject.myArray[0].boolFlag
false
设置为
true
并调用
test.valueChanged()
方法后,我的标志自动重置为其初始值。使用的任何其他类型也一样-
int
string

为什么会发生这种情况


Visual Studio已安装update 4。

非常棘手,但这是QML的预期行为。您所遭受的是绑定赋值与过程赋值之间的冲突,这是QML的一个常见陷阱

首先,您已经设置了一个到
myArray
的绑定,该绑定(实际上)表示,只要
\uuuuuuuuuuuuuu测试值
发生更改,就可以将一个文本数组重新分配给
myArray
。然后,通过按程序修改该数组来破坏该绑定。请记住,文本数组实际上是每次在绑定中触发信号时都要计算的JavaScript代码

因此,您在上一个console.log中看到的并不是bool已被还原,而是整个myArray已重置为一个新值,并从绑定中重建

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

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

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

我已经稍微简化了您的测试用例。
visible
属性允许您在启动时显示窗口。根据定义,所有信号都是可调用的,所以您不需要将它们转发给另一个可调用的方法。这可能是QML中绑定实现中的一个Qt错误……我将此作为错误发布:如果这是真的,那么它不是QML绑定机制中的一个架构缺陷吗?因为我想将对数组元素的绑定(如果是JS对象,甚至是对此类元素的某些内部结构)设置为
myArray
本身。为什么在qml中提供这样的支持会成为一个问题?您建议的通过外部变量myBoolFlag进行的修复实际上不适用于绑定包含多个元素的可修改数组。这样整个绑定机制就不能用于这样的数组了。缺陷?我不想走那么远,但要走自己的路。绑定系统并不适用于复杂的通用对象,如数组。考虑将数组封装在QML类中,该数组在数组更改时有明确的信号,并且不使用绑定来存储数组。或者使用C++类来保存复杂的数据结构,这样就可以完成完全的控制。