QList <t *>到qml数组

时间:2017-10-11 07:09:16

标签: 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

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
    }
}

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

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

4 个答案:

答案 0 :(得分:4)

首先仔细阅读以下文章:

为了从C ++数据结构创建JavaScript数组或对象,您应该在QVariantList(由QML引擎转换为JavaScript数组)或QVariantMap(转换为JavaScript)中公开C ++中的C ++。对象)。

此处&#34;序列类型为JavaScript数组&#34; 表示:

  

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

     

特别是,QML目前支持:

QList<int>
QList<qreal>
QList<bool>
QList<QString> and QStringList
QList<QUrl>
QVector<int>
QVector<qreal>
QVector<bool>

在您的情况下,请注意:

  

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

因此,您应该以{{1​​}}形式准备列表。另请注意,由于QVariantListQVariantMap都是QVariantList类型,因此您可以将地图插入列表,反之亦然,以创建复杂的对象数组或具有复杂对象里面有一个清单。

答案 1 :(得分:3)

要将QObject列表公开给Qml,Qt建议使用QQmlListProperty

要创建此对象,您需要覆盖其部分访问功能,例如size()at()等。

你应该看看

答案 2 :(得分:3)

QML Engine将QList<QObject*>视为特例。您不能公开类型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
}

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

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

此处记录了

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

只要引擎知道variant内的类型,就可以在variant内包含内容。您可以注册Bar类型,以便QML引擎可以理解:

  • QVariant(Bar*)甚至

  • QList<QVariant(Bar*)>

但是,您永远无法让引擎理解QList<Bar*>

(注意:如果Bar派生自QObject,那么就没有必要将其注册到QML,支持将是隐式的)

其他选择...... QQmlListPropertyQList<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

的main.cpp

#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();
}

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.t2)
            console.log(foo.t2[0].x)
            console.log(foo.t2[1].x)
        }
    }
    Foo {
        id: foo
    }
}

答案 3 :(得分:1)

这是我将使用QQmlListProperty进行的操作。需要一段时间才能习惯它,但它的工作方式完全符合您的期望。

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(QQmlListProperty<Bar> bars READ bars)

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

    QQmlListProperty<Bars> bars();
    void appendBar(Bar*);
    int barCount() const;
    Bar *bar(int) const;
    void clearBars();
    void replaceBar(int, Bar*);
    void removeLastBar();

private:
    QList<Bar *> mBars;
};

#endif // FOO_H

Foo.cpp

#include "Foo.h"

QQmlListProperty<Bar> Foo::bars()
{
    return {this, this,
            [](QQmlListProperty<Bar> *prop, Bar *newBar)
            {
                Foo *foo = qobject_cast<Foo*>(prop->object);
                if (foo) {
                    foo->appendBar(newBar);
                }
            },
            [](QQmlListProperty<Bar> *prop)->int
            {
                Foo *foo = qobject_cast<Foo*>(prop->object);
                if (foo ) {
                    return foo->barCount();
                }
                return 0;
            },
            [](QQmlListProperty<Bar> *prop, int index)->Bar*
            {
                Foo *foo = qobject_cast<Foo*>(prop->object);
                if (foo) {
                    return foo->bar(index);
                }
                return nullptr;
            },
            [](QQmlListProperty<Bar> *prop)
            {
                Foo *foo = qobject_cast<Foo*>(prop->object);
                if (foo) {
                    foo->clearBars();
                }
            },
            [](QQmlListProperty<Bar> *prop, int index, Bar* newBar)
            {
                Foo *foo = qobject_cast<Foo*>(prop->object);
                if (foo) {
                    foo->replaceBar(index, newBar);
                }
            },
            [](QQmlListProperty<Bar> *prop)
            {
                Foo *foo = qobject_cast<Foo*>(prop->object);
                if (foo) {
                    foo->removeLastBar();
                }
            }
    };
}

void Foo::appendBar(Bar* newBar) {
    mBars.append(newBar);
}

int Foo::barCount() const
{
    return mBars.count();
}

Bar *Foo::bar(int index) const
{
    return mBars.at(index);
}

void Foo::clearBars() {
    mBars.clear();
}

void Foo::replaceBar(int index, Bar *newBar)
{
    mBars[index] = newBar;
}

void Foo::removeLastBar()
{
    mBars.removeLast();
}