我有一个从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 *>作品我可以访问它的成员x和console.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 *>?
首先,请仔细阅读以下文章:
为了从C ++数据结构创建JavaScript数组或对象,您应该将C ++的内容QVariantList(通过QML引擎隐藏到JavaScript数组)或QVariantMap(将其转换为JavaScript对象)公开。
另外,“ JavaScript数组的序列类型”部分说:
QML透明地支持某些C ++序列类型作为JavaScript数组类型。
特别是,QML当前支持:
Run Code Online (Sandbox Code Playgroud)QList<int> QList<qreal> QList<bool> QList<QString> and QStringList QList<QUrl> QVector<int> QVector<qreal> QVector<bool>
在您的情况下,请注意:
不透明地支持其他序列类型,而任何其他序列类型的实例都将在QML和C ++之间作为opaque传递
QVariantList。
因此,您应该以QVariantList表格的形式准备列表。还要注意,由于QVariantMap和QVariantList均为类型QVariant,因此您可以将地图插入列表,反之亦然,以创建对象的复杂数组或内部具有列表的复杂对象。
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是另一种选择,但其他地方已经有足够的资源来了解如何做到这一点。
完整代码:
#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)
| 归档时间: |
|
| 查看次数: |
3516 次 |
| 最近记录: |