QList <T *>到QML数组

Eli*_*kis 2 c++ qt qml

我有一个从QObject继承的Bar类。我想在类Foo中使用Bar指针的QList,并在qml中公开它。

foo.h

#ifndef FOO_H
#define FOO_H

#include <QQuickItem>

class Bar : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int x READ x)

public:
    explicit Bar(QObject *parent = nullptr)
        : QObject(parent), mX(123) {}
    virtual ~Bar() {}

    int x() const { return mX; }
private:
    int mX;
};

class Foo : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject *> t1 READ t1)
    Q_PROPERTY(QList<Bar *> t2 READ t2)

public:
    explicit Foo(QQuickItem *parent = nullptr)
        : QQuickItem(parent) {
        mT1.append(new Bar(this));
        mT1.append(new Bar(this));

        mT2.append(new Bar(this));
        mT2.append(new Bar(this));
    }
    virtual ~Foo() {}

    QList<QObject *> t1() const { return mT1; }
    QList<Bar *> t2() const { return mT2; }

private:
    QList<QObject *> mT1;
    QList<Bar *> mT2;
};

#endif // FOO_H
Run Code Online (Sandbox Code Playgroud)

qmlRegisterType(“ Custom.Foo”,1,0,“ Foo”);

main.qml

import QtQuick 2.6
import QtQuick.Window 2.2
import Custom.Foo 1.0

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

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log(foo.t1)
            console.log(foo.t1.x)
            console.log(foo.t2)
            console.log(foo.t2.x)
        }
    }
    Foo {
        id: foo
    }
}
Run Code Online (Sandbox Code Playgroud)

QList<QObject *>作品我可以访问它的成员xconsole.log(foo.t1)输出,qml: [Bar(0x10e4be0),Bar(0x10bd6d0)]QList<Bar *>不能。当我尝试访问成员时,x我得到qml:undefined和console.log(foo.t2)输出qml: QVariant(QList<Bar*>)

为什么QList<Bar *>在QVariant中公开?有没有办法以相同的方式在qml中公开它QList<QObject *>

fro*_*tto 6

首先,请仔细阅读以下文章:

为了从C ++数据结构创建JavaScript数组或对象,您应该将C ++的内容QVariantList(通过QML引擎隐藏到JavaScript数组)或QVariantMap(将其转换为JavaScript对象)公开。

另外,“ JavaScript数组的序列类型”部分说:

QML透明地支持某些C ++序列类型作为JavaScript数组类型。

特别是,QML当前支持:

QList<int>
QList<qreal>
QList<bool>
QList<QString> and QStringList
QList<QUrl>
QVector<int>
QVector<qreal>
QVector<bool>
Run Code Online (Sandbox Code Playgroud)

在您的情况下,请注意:

不透明地支持其他序列类型,而任何其他序列类型的实例都将在QML和C ++之间作为opaque传递QVariantList

因此,您应该以QVariantList表格的形式准备列表。还要注意,由于QVariantMapQVariantList均为类型QVariant,因此您可以将地图插入列表,反之亦然,以创建对象的复杂数组或内部具有列表的复杂对象。


Mar*_* Ch 5

QML 引擎将其QList<QObject*>视为一种特殊情况。您无法公开 type 的属性QList<Bar*>,引擎无法理解它,并且无法将其注册为新的列表类型。

另一个没有提到的选项是投射列表……尽管有些人认为它是有罪的。

如果您必须将数据存储在其中,QList<Bar*>那么您可以将其返回QList<QObject*>如下...

QList<QObject *> t2() const {
    Q_ASSERT(sizeof(QObject*) == sizeof(Bar*));               // check pointers are the same size
    Q_ASSERT(sizeof(QList<QObject*>) == sizeof(QList<Bar*>)); // check lists are the same size
    Q_ASSERT(qobject_cast<Bar*>((QObject*)mT2.at(0)));        // check Bar is derived from QObject
    return *reinterpret_cast<const QList<QObject *>*>(&mT2);  // now cast the list
}
Run Code Online (Sandbox Code Playgroud)

它快速、简单,并且 Bar 类的所有对象属性和 Q_INVOKABLE 方法都可以在 QML 中使用。

我添加了一些检查以防万一,但是如果您可以确定您的类是从 QObject 派生的,那么您可能会选择不打扰。

QList<QObject*>支持记录在此处:http : //doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qobjectlist-based-model。它是一个特例并非巧合……它被选为一个特殊的 ;) 每个QObject*都从 复制QList并用于在 QML 引擎中创建一个新的 javascript 数组。

将内容包含在 a 中variant是可以的,只要引擎知道variant. 您可以注册Bar类型,以便 QML 引擎可以理解:

  • QVariant(Bar*) 乃至

  • QList<QVariant(Bar*)>.

然而,你永远无法让引擎理解QList<Bar*>

(注意:如果Bar派生自QObject,则无需将其注册到 QML,支持将是隐式的)

其他选项...... QQmlListProperty并且QList<QVariant>会起作用,但已在其他答案中涵盖。 QAbstractListModel是另一种选择,但其他地方已经有足够的资源来了解如何做到这一点。

完整代码:

foo.h

#ifndef FOO_H
#define FOO_H

#include <QQuickItem>

class Bar : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int x READ x)

public:
    explicit Bar(QObject *parent = nullptr)
        : QObject(parent), mX(123) {}
    virtual ~Bar() {}

    int x() const { return mX; }
private:
    int mX;
};

class Foo : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject *> t2 READ t2)

public:
    explicit Foo(QQuickItem *parent = nullptr)
        : QQuickItem(parent) {
        mT2.append(new Bar(this));
        mT2.append(new Bar(this));
    }
    virtual ~Foo() {}

    QList<QObject *> t2() const {
        Q_ASSERT(sizeof(QObject*) == sizeof(Bar*));               // check pointers are the same size
        Q_ASSERT(sizeof(QList<QObject*>) == sizeof(QList<Bar*>)); // check lists are the same size
        Q_ASSERT(qobject_cast<Bar*>((QObject*)mT2.at(0)));        // check Bar is derived from QObject
        return *reinterpret_cast<const QList<QObject *>*>(&mT2);  // now cast the list
    }

private:
    QList<Bar *> mT2;
};

#endif // FOO_H
Run Code Online (Sandbox Code Playgroud)

主程序

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include "foo.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    qmlRegisterType<Foo>("Custom.Foo", 1, 0, "Foo");

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

    return app.exec();
}
Run Code Online (Sandbox Code Playgroud)

主文件

import QtQuick 2.6
import QtQuick.Window 2.2
import Custom.Foo 1.0

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

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log(foo.t2)
            console.log(foo.t2[0].x)
            console.log(foo.t2[1].x)
        }
    }
    Foo {
        id: foo
    }
}
Run Code Online (Sandbox Code Playgroud)