[英]QList<T*> to qml array
I have a class Bar which inherits from QObject.我有一个继承自 QObject 的类 Bar。 I want to have a QList of Bar pointers in class Foo and expose it in qml.
我想在 Foo 类中有一个 Bar 指针的 QList 并在 qml 中公开它。
foo.h 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"); 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 *>
works I can access it's member x
and console.log(foo.t1)
outputs qml: [Bar(0x10e4be0),Bar(0x10bd6d0)]
but QList<Bar *>
doesn't. QList<QObject *>
工作我可以访问它的成员x
和console.log(foo.t1)
输出console.log(foo.t1)
qml: [Bar(0x10e4be0),Bar(0x10bd6d0)]
但QList<Bar *>
没有。 When I try to access member x
I get qml: undefined and console.log(foo.t2)
outputs qml: QVariant(QList<Bar*>)
.当我尝试访问成员
x
我得到console.log(foo.t2)
: undefined 和console.log(foo.t2)
输出console.log(foo.t2)
qml: QVariant(QList<Bar*>)
。
Why QList<Bar *>
is exposed in QVariant?为什么
QList<Bar *>
在 QVariant 中暴露? Is there a way to expose it in qml same way QList<QObject *>
?有没有办法在 qml 中以同样的方式公开它
QList<QObject *>
?
First off read the following article carefully:首先请仔细阅读以下文章:
In order to create JavaScript arrays or objects from C++ data structures, you should expose those of C++ in QVariantList
(which gets converted to JavaScript array) or QVariantMap
(which gets converted to JavaScript object).为了从 C++ 数据结构创建 JavaScript 数组或对象,您应该在
QVariantList
(转换为 JavaScript 数组)或QVariantMap
(转换为 JavaScript 对象)中公开 C++ 的数组或对象。
Also section "Sequence Type to JavaScript Array" says:另外“JavaScript 数组的序列类型”部分说:
Certain C++ sequence types are supported transparently in QML as JavaScript Array types.
QML 透明地支持某些 C++ 序列类型作为 JavaScript 数组类型。
In particular, QML currently supports:
特别是,QML 目前支持:
QList<int> QList<qreal> QList<bool> QList<QString> and QStringList QList<QUrl> QVector<int> QVector<qreal> QVector<bool>
In your case, note that:在您的情况下,请注意:
Other sequence types are not supported transparently, and instead an instance of any other sequence type will be passed between QML and C++ as an opaque
QVariantList
.不透明地支持其他序列类型,而是将任何其他序列类型的实例作为不透明的
QVariantList
在 QML 和 C++ 之间传递。
Therefore, you should prepare your list in a QVariantList
.因此,您应该在
QVariantList
准备您的列表。 Also note that since both QVariantMap
and QVariantList
are of type QVariant
, so you can insert a map into a list or vice versa, to create a complex array of objects or a complex object having a list inside.还要注意,由于既
QVariantMap
和QVariantList
是类型QVariant
,这样可以插入一个地图到一个列表,或反之亦然,创建对象的一系列复杂的或具有一个列表内一个复杂的对象。
QML Engine recognizes QList<QObject*>
as a special case. QML 引擎将
QList<QObject*>
识别为特殊情况。 You can't expose a property of type QList<Bar*>
, the engine doesn't understand it, and there is no way to register it as a new list type.您不能公开
QList<Bar*>
类型的属性,引擎不理解它,并且无法将其注册为新的列表类型。
Another option which hadn't been mentioned is casting the list ... as sinful as it may be considered by some.另一个没有提到的选项是投射列表……尽管有些人认为它是有罪的。
If you must have your data stored in QList<Bar*>
then you can return it as a QList<QObject*>
as below...如果您必须将数据存储在
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
}
It's fast, easy, and all the object properties and Q_INVOKABLE methods of the Bar class are available in QML.它快速、简单,并且 Bar 类的所有对象属性和 Q_INVOKABLE 方法都可以在 QML 中使用。
I've added a few checks in just in case, but if you can be certain your class is derived from QObject then you might choose not to bother.我已经添加了一些检查以防万一,但是如果您可以确定您的类是从 QObject 派生的,那么您可能会选择不打扰。
QList<QObject*>
support is documented here: http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qobjectlist-based-model . QList<QObject*>
支持记录在此处: http : //doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qobjectlist-based-model 。 It is no coincidence that it is a special case... it has been chosen to be a special ;) Each QObject*
is copied from the QList
and used to create a new javascript array inside the QML Engine.它是一种特殊情况并非巧合……它被选为特殊情况;) 每个
QObject*
都是从QList
复制的,并用于在 QML 引擎内创建一个新的 javascript 数组。
Encompassing things inside a variant
is fine, so long as the engine knows the type which is inside the variant
.将事物包含在
variant
是可以的,只要引擎知道variant
的类型即可。 You can register Bar
type so that the QML engine could understand:您可以注册
Bar
类型,以便 QML 引擎可以理解:
QVariant(Bar*)
and even QVariant(Bar*)
甚至
QList<QVariant(Bar*)>
. QList<QVariant(Bar*)>
。
However you can never get the engine to understand QList<Bar*>
.但是,您永远无法让引擎理解
QList<Bar*>
。
(note: if Bar
derives from QObject
, then there is no need to register it to QML, support will be implicit) (注意:如果
Bar
派生自QObject
,则无需将其注册到 QML,支持将是隐式的)
Other options... QQmlListProperty
and QList<QVariant>
will work, but have been covered in other answers.其他选项...
QQmlListProperty
和QList<QVariant>
将起作用,但已在其他答案中介绍。 QAbstractListModel
is another option, but there are already enough resources elsewhere to see how that is done. QAbstractListModel
是另一种选择,但其他地方已经有足够的资源来了解它是如何完成的。
full code:完整代码:
#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
}
}
To expose a list of QObject
to Qml, Qt recommends to use QQmlListProperty
.要将
QObject
列表公开给 Qml,Qt 建议使用QQmlListProperty
。
To create this object you need to override some of its access function, like size()
, at()
, etc.要创建这个对象,你需要覆盖它的一些访问函数,比如
size()
、 at()
等。
You should have a look to你应该看看
Here is how I would do it using QQmlListProperty
.这是我将如何使用
QQmlListProperty
做到这QQmlListProperty
。 It takes awhile to get used to it, but it works exactly the way you'd expect.习惯它需要一段时间,但它的工作方式完全符合您的预期。
Foo.h 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();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.