簡體   English   中英

列表<T*>到 qml 數組

[英]QList<T*> to qml array

我有一個繼承自 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");

主文件

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)輸出console.log(foo.t1) qml: [Bar(0x10e4be0),Bar(0x10bd6d0)]QList<Bar *>沒有。 當我嘗試訪問成員x我得到console.log(foo.t2) : undefined 和console.log(foo.t2)輸出console.log(foo.t2) qml: QVariant(QList<Bar*>)

為什么QList<Bar *>在 QVariant 中暴露? 有沒有辦法在 qml 中以同樣的方式公開它QList<QObject *>

首先請仔細閱讀以下文章:

為了從 C++ 數據結構創建 JavaScript 數組或對象,您應該在QVariantList (轉換為 JavaScript 數組)或QVariantMap (轉換為 JavaScript 對象)中公開 C++ 的數組或對象。

另外“JavaScript 數組的序列類型”部分說:

QML 透明地支持某些 C++ 序列類型作為 JavaScript 數組類型。

特別是,QML 目前支持:

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

在您的情況下,請注意:

不透明地支持其他序列類型,而是將任何其他序列類型的實例作為不透明的QVariantList在 QML 和 C++ 之間傳遞。

因此,您應該在QVariantList准備您的列表。 還要注意,由於既QVariantMapQVariantList是類型QVariant ,這樣可以插入一個地圖到一個列表,或反之亦然,創建對象的一系列復雜的或具有一個列表內一個復雜的對象。

QML 引擎將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

主程序

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

主文件

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

要將QObject列表公開給 Qml,Qt 建議使用QQmlListProperty

要創建這個對象,你需要覆蓋它的一些訪問函數,比如size()at()等。

你應該看看

這是我將如何使用QQmlListProperty做到這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

文件

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM