继承QQuickItem与QQuickPaintedItem
这两个都是可以直接使用到程序中的
可以参考本专栏第一章节
继承QObject的c++对象转qml组件
往往有一种情况就是我们开发的时候采用的qwidget,写的对象已经就是qobject对象
但是我们想要将这个对象用到qml中,但是如果用户将派生对象由QObject 转QQuickItem与QQuickPaintedItem 肯定会出大问题,就是一堆代码都得跟着调整,因为
父对象是QQuickItem, 你传一个qobject 肯定报错,所以你不得连锁调整,而且最恶心的是
QQuickItem 有一大堆的属性,我们不想要,与这个类无关的属性,如visible,x,y,w,h等
派生QQuickItem 导致我们结构都感觉好像很奇葩
这个时候你只需要了解QQuickItem这个类是怎么来的
很明显就是继承QObject ,与QQmlParserStatus
其中QQmlParserStatus有两个虚函数要实现一下
virtual void classBegin()=0;
virtual void componentComplete()=0;
然后就是默认属性要实现一下,这个默认属性不实现会报一种错误
Cannot assign to non-existent default property
qml中默认属性是什么呢? 请参考https://blog.youkuaiyun.com/gongjianbo1992/article/details/102056869
通过前面的文档描述我们知道,可以把一个对象或列表属性声明为默认属性
QQmlListProperty<QObject> Father::data()
{
return QQmlListProperty<QObject>(this, 0, &Father::appendChildren ,0,0,0);
}
void Father::appendChildren(QQmlListProperty<QObject> *list, QObject *element)
{
Q_UNUSED(list);
Q_UNUSED(element);
}
应该大家很好奇默认属性怎么调用?
还记得Repeater 中的delegate吗? 他这个就是Repeater的默认属性,
Repeater的默认属性就是一个 你会发现Repeater只处理一个子Repeater的子项
//第一种写法只处理一个
Repeater{
model: 5
Rectangle{width: 10;height: 10; color: "red"}
Rectangle{width: 10;height: 10; color: "blue"}
}
//第二中写法直接调用默认属性
Repeater{
model: 5
delegate: Rectangle{width: 10;height: 10; color: "red"}
}
换句话说就是在你的QMl项里面只要实例化子项,实例化一个组件
或者直接调用默认属性赋值,因为是个列表所以要加括号
比如Rectangle的
当组件中 创建了 子项,也就是调用了默认属性则会 触发
void Father::appendChildren(QQmlListProperty<QObject> *list, QObject *element)
{
Q_UNUSED(list);
Q_UNUSED(element);
}
我不处理appendChildren
按照c++的写法就是在构造的时候处理他们
那么我们就可以使用virtual void componentComplete()=0;
在组件构造完成之后,集中处理所有子组件
void Father::componentComplete()
{
foreach (QObject *child, children()) {
if (qobject_cast<Son *>(child)) {
Father::append(qobject_cast<Son *>(child));
}
}
}
bool Father::append(Son *son)
{
if(son == nullptr)
return false;
if(m_sons.contains(son)){
return false;
}else{
m_sons.append(son);
return true;
}
}
当然有一些情况就是
子项如果不需要创建更深一层的子项就不需要设置默认属性
源码如下
Father.cpp
#include "Father.h"
#include <QDebug>
void Father::classBegin()
{
}
void Father::componentComplete()
{
foreach (QObject *child, children()) {
if (qobject_cast<Son *>(child)) {
Father::append(qobject_cast<Son *>(child));
}
}
}
Father::Father(QObject *parent) : QObject(parent)
{
}
QQmlListProperty<QObject> Father::data()
{
return QQmlListProperty<QObject>(this, 0, &Father::appendChildren ,0,0,0);
}
bool Father::append(Son *son)
{
if(son == nullptr)
return false;
if(m_sons.contains(son)){
return false;
}else{
m_sons.append(son);
return true;
}
}
void Father::appendChildren(QQmlListProperty<QObject> *list, QObject *element)
{
Q_UNUSED(list);
Q_UNUSED(element);
}
Father.h
#ifndef FATHER_H
#define FATHER_H
#include <QObject>
#include <QQmlParserStatus>
#include <QQmlListProperty>
#include "Son.h"
class Father : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QQmlListProperty<QObject> data READ data)
Q_CLASSINFO("DefaultProperty", "data")
public:
void classBegin() override;
void componentComplete() override;
public:
explicit Father(QObject *parent = nullptr);
QQmlListProperty<QObject> data();
bool append(Son *son);
private:
QList<Son *> m_sons;
public slots:
static void appendChildren(QQmlListProperty<QObject> *list, QObject *element);
};
#endif // FATHER_H
Son.h + Son.cpp
#ifndef SON_H
#define SON_H
#include <QObject>
class Father;
class Son : public QObject
{
Q_OBJECT
public:
explicit Son(QObject *parent = nullptr);
signals:
public slots:
};
#endif // SON_H
//==============================================
#include "Son.h"
Son::Son(QObject *parent) : QObject(parent)
{
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QDebug>
#include "Father.h"
#include "Son.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<Father>("com.ui",1,0,"Father");
qmlRegisterType<Son>("com.ui",1,0,"Son");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
总结如下
有了这项技术你就可以专门写一些组件适配到qml了