12.qml使用c++开发组件

继承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了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱搞事的程小猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值