前言
用过Qt的都知道Qt的元对象系统,Qt的元对象系统为对象间通信、运行时类型信息和动态属性系统提供了信号和插槽机制。今天我们就来认识下Qt的动态属性系统。
初识Qt属性系统
引入官方文档的介绍:
Qt提供了一个复杂的属性系统,类似于一些编译器供应商提供的系统。然而,作为一个独立于编译器和平台的库,Qt不依赖于像__property或[property]这样的非标准编译器特性。Qt解决方案可以在Qt支持的每个平台上与任何标准C++编译器一起工作。它基于元对象系统,该系统也通过信号和插槽提供对象间的通信。
使用Qt动态属性,需要继承自QObject类,并使用宏 Q_PROPERTY()
我们熟知的QWidget就定义了很多的属性
具体结构为:
Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER memberName [(READ getFunction | WRITE setFunction)]) [RESET resetFunction] [NOTIFY notifySignal] [REVISION int] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] [USER bool] [CONSTANT] [FINAL] [REQUIRED])
可以看到字段很多,具体可自行查看官方文档。下面介绍Q_PROPERTY的常见用法。
用法
项目开发中,如果使用的是Qt Creator,输入Q_PROPERTY时,自动补全功能就会联想出一些可选项,选择附带有type、READ、WRITE、NOTIFY字段的选项,这是一个最常规的用法,提供类型、读写和信号,能够满足大部分需求了。
定义
输入完成后,使用快捷键Alt+回车,就会提示生成对应的变量和函数,确认后就会自动补全
还可以鼠标光标放在Q_PROPERTY,然后右键→Refactor也是一样的效果
运用
按照上面的定义方式可以使用定义的接口setName和name进行修改和取值,还可以使用下面的方式进行操作
bool setProperty(const char *name, const QVariant &value);
QVariant property(const char *name) const;
name就是type对应的属性名称,使用setProperty的方式的一个好处就是只需要知道属性名称和类型,另外使用setName的方式速度会更快,两种方式各有利弊吧
setProperty("name", "1111");
qDebug() << __FUNCTION__ << "song" << "name:" << m_name << property("name").toString();
在父类中定义的属性,子类也是可以使用的
QPushButton *button = new QPushButton;
QObject *object = button;
button->setDown(true);
object->setProperty("down", true);
动态属性
动态属性就是没有手动添加Q_PROPERTY,直接调用setProperty,如果该属性没有,则会自动添加,提供一个invalid的QVariant就可以移除
setProperty("name22", "1111");
qDebug() << __FUNCTION__ << "song" << "name22:" << property("name22").toString();
setProperty("name22", QVariant());
qDebug() << __FUNCTION__ << "song" << "name22:" << property("name22");
需要注意的是动态属性并不会添加到元对象系统中,所以元对象相关的功能就用不了,如无法在QML中使用属性
QML中使用
直接看代码就好了, 这也是C++与QML交互运用
#include <QObject>
#include <QColor>
#include <qqml.h>
class TestClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
QML_ELEMENT
public:
explicit TestClass(QObject *parent = nullptr);
const QColor &color() const;
void setColor(const QColor &newColor);
signals:
void colorChanged();
private:
QColor m_color;
};
import QtQuick 2.15
import QtQuick.Window 2.15
import com.mycompany.qmlcomponents 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
TestClass {
id: testClass
color: Qt.red
}
Rectangle {
width: 100
height: 100
color: testClass.color
}
}
还有更简单的定义方式,把READ和WRITE去掉,只保留NOTIFY,这样就可以把setter和getter的接口去掉,这样也是可以的,代码量更少,QML中使用NOTIFY是必须的,在C++中对属性进行操作则可以使用前面介绍的setProperty
class TestClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
QML_ELEMENT
public:
explicit TestClass(QObject *parent = nullptr);
signals:
void colorChanged();
private:
QColor m_color;
};
结语
Qt属性系统贯穿整个Qt框架,作为Qt框架的使用者必须要有所了解,并且会基本的运用,本篇文章就介绍一些常见的点。
最后的QML的完整demo地址:GitHub