如何在QML中修改QObject数组的内容?

时间:2017-09-08 14:47:43

标签: javascript c++ arrays qt

使用Qt 5.6 QML(升级不是一个选项)...... 我需要传递一个包含QML和C ++之间结构数组的结构(两种方式)。

        // Create an object in a QML context
        var workObj = objArrayComponent.createObject(mainForm)

        // These things work
        workObj.topParam = true
        workObj.objArray = [ { someParam : true }, { someParam : false }, {someParam : true } ]

        // Neither of the following work...
        // After this call, the value remains false
        workObj.objArray[1].someParam = true;
        // After this call, the length remains 3
        workObj.objArray.push( { someParam : true } )

        // This works
        workObj.objArray = [ { someParam : false }, { someParam : true }, {someParam : false } ]

使用以下代码,我可以使用数组创建结构的实例并传递它,但我无法修改数组的内容。我无法弄清楚我错过了什么......

#include <QObject>
#include <QVariant>

class SomeObj : public QObject
{
    Q_OBJECT
public:
    explicit SomeObj(QObject *parent = nullptr) : QObject(parent) {}

    Q_PROPERTY( bool someParam MEMBER mSomeParam NOTIFY someParamChanged )

signals:

    void someParamChanged();

public slots:

private:
    bool    mSomeParam;
};

class ObjArray : public QObject
{
    Q_OBJECT

    Q_PROPERTY( bool topParam MEMBER mTopParam NOTIFY topParamChanged )
    Q_PROPERTY( QVariantList objArray MEMBER mObjArray NOTIFY objArrayChanged )

public:
    explicit ObjArray(QObject *parent = nullptr) : QObject(parent) {}

signals:

    void topParamChanged();
    void objArrayChanged();

public slots:

private:
    bool            mTopParam;
    QVariantList    mObjArray;
};

我还尝试了一个代码版本,我拆分了READ / WRITE并创建了自己的getter / setter。我确认在设置整个workObj.objArray时调用了setter,但是没有调用其他更改。

以下完整代码......

objarray.h(没有objarray.cpp,MEMBER创建getter / setter):

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQmlContext>
#include <QQmlComponent>
#include "objarray.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<ObjArray>("obj.array", 1, 0, "ObjArray");
    qmlRegisterType<SomeObj>("some.obj", 1, 0, "SomeObj");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.cpp中:

import QtQuick 2.6
import QtQuick.Window 2.2
import obj.array 1.0
import some.obj 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    MainForm {
        id: mainForm

        Component {
            id: objArrayComponent
            ObjArray {}
        }

        anchors.fill: parent
        mouseArea.onClicked: {
            // Create an object in the form's context
            var workObj = objArrayComponent.createObject(mainForm)

            workObj.topParam = true
            workObj.objArray = [ { someParam : true }, { someParam : false }, {someParam : true } ]

            // So far so good
            // results: true, (3): [true, false, true]
            console.log( "results: " + workObj.topParam + ", " +
                        "(" + workObj.objArray.length + "): [" +
                        workObj.objArray[0].someParam + ", " +
                        workObj.objArray[1].someParam + ", " +
                        workObj.objArray[2].someParam + "] "
                        )

            // This works
            workObj.topParam = false

            // Neither of the following work...
            workObj.objArray[1].someParam = true;
            workObj.objArray.push( { someParam : true } )

            // Value is not changed
            // Array size doesn't change
            // results: false, (3): [true, false, true]

            console.log( "results: " + workObj.topParam + ", " +
                        "(" + workObj.objArray.length + "): [" +
                        workObj.objArray[0].someParam + ", " +
                        workObj.objArray[1].someParam + ", " +
                        workObj.objArray[2].someParam + "] "
                        )

        // This works
        workObj.objArray = [ { someParam : false }, { someParam : true }, {someParam : false } ]

        // results: false, (3): [false, true, false]
        console.log( "results: " + workObj.topParam + ", " +
                    "(" + workObj.objArray.length + "): [" +
                    workObj.objArray[0].someParam + ", " +
                    workObj.objArray[1].someParam + ", " +
                    workObj.objArray[2].someParam + "] "
                    )

            console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"'))
            Qt.quit()
        }
    }
}

main.qml:

public:
Q_INVOKABLE void setValue( QString name, int index, bool value )
{
    if( name == "someParam" )
        mStoreIt[index].someParam = value;
}

Q_INVOKABLE bool getValue( QString name, int index )
{
    if( name == "someParam" )
         return mStoreIt[index].someParam;
}

private:
QVector<someObj>  mStoreIt;

修改
显然QML变体数组无法修改,我没时间找到更好的解决方案,所以我决定采用快速的脏设置。这对于小结构来说很好,但是缩放到更大的结构将是烦人的 没有错误检查紧凑性...

 <TextView
        android:id="@+id/hello"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Hello World, MyActivity"
        />

1 个答案:

答案 0 :(得分:0)

根据文件Qt site

  

虽然这是存储数组和地图类型值的便捷方式,但是   必须要知道上面的项和属性属性不是   QML对象(当然也不是JavaScript对象)和   属性中的键值对不是QML属性。相反,   items属性包含一组值,而属性包含一组值   键值对。因为它们存储为一组值,而不是   作为一个对象,他们的内容不能单独修改:

Item {
    property variant items: [1, 2, 3, "four", "five"]
    property variant attributes: { 'color': 'red', 'width': 100 }

    Component.onCompleted: {
        items[0] = 10
        console.log(items[0])     // This will still be '1'!
        attributes.color = 'blue'
        console.log(attributes.color)     // This will still be 'red'!
    }
}