quick 2 — qml 与c++的混合编程
Qt Quick 技术的引入,能够快速流畅的构建用户界面,动画、绚丽的都不在话下。但他不是万能的。也有很多局限性,原来的qt技术,比如低阶的网络编程如QTcpSocket、多线程,又比如XML文档处理类库QXMLStreamReader、QXMLStreamWriter,再如文件操作QFile等,在QML中使用并不方便。因此,基于这种情况就需要混合使用QML和C++:使用QML构建界面,C++实现非界面的业务逻辑和复杂运算。
1. 在QML中使用C++类的对象
Qt提供了两种在QML中使用C++对象的方式:
(1)在C++中实现一个类,注册为QML环境的一个类型,在QML环境中使用该类型创建对象;
(2)在C++中构造一个对象,将这个对象设置为QML的上下文属性,在QML环境中直接使用该属性。
1.1 方法一:C++类注册QML类型
1.1.1 定义可以导出的C++类
满足2个前提:
(1)从QObjec或QObject的派生类继承;
(2)使用Q_OBJECT宏;
这两个条件是为了让一个类进入Qt的元对象系统,只有使用元对象系统,类的某些方法才可能通过字符串形式的名字调用,才能在QML中被访问。
1.1.1.1 信号、槽
只要是信号、槽,都可以在QML中被访问,可以把C++对象的信号连接到QML中定义的方法上,也可以吧QML对象的信号连接到C++对象的槽上,还可以直接调用C++对象的槽或信号。在定义类的成员函数时使用 Q_INVOKABLE 宏来修饰,就可以让该方法被元对象系统调用。这个类型必须在返回类型前面。
1.1.1.2 Q_INVOKABLE 宏
在定义类的成员函数时使用 Q_INVOKABLE 宏来修饰,就可以让该方法被元对象系统调用。这个类型必须在返回类型前面。
使用Q_INVOKABLE 将方法注册到元对象系统中,在QMl中就能调用${Object}.${method}来访问了,在main.qml中使用 getAlgorithm() 和 setAlgorithm() 的QML代码:
...................................
1.1.1.3 Q_ENUMS 宏
如果导出类定义的枚举变量,可以使用Q_ENUM宏将该枚举类型注册到元对象系统中:
使用Q_ENUM注册之后,在QML中就可以使用${CLASS_NAME}.${ENUM_VALUE}的形式来访问了。
1.1.1.4 Q_PROPERTY 宏
Q_PROPERTY 宏用来定义可通过元对象系统访问属性,通过它定义的属性,可以在QML中访问、修改,也可以在属性变化时发射特定的信号。常用的是READ、WRITE、NOTIFY三个选项。
(1)READ 标记:如果没有置顶MEMBER标记,则READ必不可少;声明一个读取属性的函数,该函数一般没有参数,返回定义的属性。
(2)WRITE 标记:可选配置。声明一个设定属性的函数。它指定的函数没有返回值,只能有一个与属性类型匹配的参数。
(3)NOTIFY 标记:可选配置。给属性关联一个信号(该信号必须是已经在类中声明过的),当属性的值发生变化时就会触发信号。信号的参数,一般就是你定义的属性。
1.1.2 注册一个QML可用的类型
需要4步:
(1)实现C++类;
(2)注册QML类型;
(3)在QML中导入类型;
(4)在QML中创建由C++导出的类型的实例并使用。
1.1.2.1 注册QML类型
注册QML类型,有多种方法可以调用:(这里说明几种常规类型,其他参考Qt SDK)
(1)qmlRegisterSingletonType() 用来注册一个单例类型
(2)qmlRegisterType() 用来注册一个非单例类型
(3)qmlRegisterTypeNotAvailable() 注册一个类型占位
(4)qmlRegisterUncreatableType()通常用来注册一个具有附加属性的附加类型
其中 qmlRegisterType() 是个模版函数,有两个原型:
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
template<typename T, int metaObjectRevision>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
前一个原型一般是用来注册一个新类型,而后一个可以为特定的版本注册类型。例如:
1.1.2.2 在QML中导入C++注册的类型
在qml中引入注册的包,然后就可以使用注册类型了。(引入包,使用import语句)
import an.qt.ColorMaker 1.0
1.2.2.3 在QML中创建C++导入类型的实例
1.1.3 代码示例
1.1.3.1 c++ 类 ColorMaker.h
#ifndef COLORMAKER_H
#define COLORMAKER_H
#include <QObject>
#include <QTimerEvent>
#include <QColor>
class ColorMaker : public QObject
{
Q_OBJECT
Q_ENUMS(EmAlgorithm);
Q_PROPERTY(QColor color READ getColor WRITE setColor NOTIFY sigColorChanged)
Q_PROPERTY(QColor timeColor READ timeColor)
public:
enum EmAlgorithm{EmRandomRGB, EmRandomRed, EmRandomGreen, EmRandomBlue, EmLinearIncrease};
explicit ColorMaker(QObject *parent = nullptr);
~ColorMaker();
QColor getColor() const;
void setColor(const QColor &color);
QColor timeColor() const;
Q_INVOKABLE EmAlgorithm getAlgorithm() const;
Q_INVOKABLE void setAlgorithm(EmAlgorithm algorithm);
signals:
void sigColorChanged(const QColor &color);
void sigCurrentTime(const QString &strTime);
public slots:
void slotSart();
void slotStop();
protected:
void timerEvent(QTimerEvent *e);
private:
EmAlgorithm m_algorithm;
QColor m_currColor;
int m_nColorTimer;
};
#endif // COLORMAKER_H
1.1.3.2 c++ 类 ColorMaker.cpp
#include "ColorMaker.h"
#include <QTime>
#include <QDebug>
ColorMaker::ColorMaker(QObject *parent) : QObject(parent),
m_algorithm(EmRandomRGB),
m_currColor(Qt::black),
m_nColorTimer(0)
{
qsrand(QDateTime::currentDateTime().toTime_t());
}
ColorMaker::~ColorMaker()
{
}
QColor ColorMaker::getColor() const
{
return m_currColor;
}
void ColorMaker::setColor(const QColor &color)
{
m_currColor = color;
emit sigColorChanged(m_currColor);
}
QColor ColorMaker::timeColor() const
{
QTime time = QTime::currentTime();
int r = time.hour();
int g = time.minute() * 2;
int b = time.second() * 4;
return QColor::fromRgb(r, g, b);
}
ColorMaker::EmAlgorithm ColorMaker::getAlgorithm() const
{
return m_algorithm;
}
void ColorMaker::setAlgorithm(ColorMaker::EmAlgorithm algorithm)
{
m_algorithm = algorithm;
}
void ColorMaker::slotSart()
{
if(m_nColorTimer == 0)
{
m_nColorTimer = startTimer(1000);
}
}
void ColorMaker::slotStop()
{
if(m_nColorTimer > 0)
{
killTimer(m_nColorTimer);
m_nColor