我有一个继承自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 *>
有效我可以访问它的成员x
和console.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 *>
同样的方式公开它?
答案 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}}形式准备列表。另请注意,由于QVariantList
和QVariantMap
都是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,支持将是隐式的)
其他选择......
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
#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
}
}
答案 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();
}