目录
元对象概念
QT的元对象系统基于以下三个组件:
- 类:QObject,所有需要使用元对象系统的基类
- 宏:Q_OBJECT,在类的private部分声明
- 编译器:元对象编译器(moc),为每个QObject子对象自动生成必要的代码来实现元对象特性
在程序编译的时候,会先使用元对象编译器读入C++的源文件,如果它发现了类里有Q_OBJECT声明,它就会创建一个C++源文件,为该类生成包含元对象实现的代码。
基于这样的一个元对象系统,QT实现了
- 对象间的通信机制信号和槽
- 属性系统
- 类信息系统
- ...
运行时获取类的名称
const QMetaObject *meta_obj = boy_->metaObject();
QString(meta_obj->className());
通过名字动态设置和获取对象属性
ui->spinBox_boy->setProperty("is_boy", true);
ui->spinBox_girl->setProperty("is_boy", false);
QSpinBox *spinBox = qobject_cast<QSpinBox*>(sender());
if(spinBox->property("is_boy").toBool())
boy_->set_age(spinBox->value());
else
girl_->set_age(spinBox->value());
Q_PROPERTY
属性的定义
用宏 Q_PROPERTY() 定义属性,其使用格式如下:
Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER meznberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
Q_PROPERTY 宏定义一个返回值类型为 type,名称为 name 的属性,用 READ、WRITE 关键字定义属性的读取、写入函数,还有其他的一些关键字定义属性的一些操作特性。属性的类型可以是 QVariant 支持的任何类型,也可以用户自定义类型。
Q_PROPERTY 宏定义属性的一些主要关键字的意义如下:
- READ 指定一个读取属性值的函数,没有 MEMBER 关键字时必须设置 READ。
- WRITE 指定一个设定属性值的函数,只读属性没有 WRITE 设置。
- MEMBER 指定一个成员变量与属性关联,成为可读可写的属性,无需再设置 READ 和 WRITE。
- RESET 是可选的,用于指定一个设置属性缺省值的函数。
- NOTIFY 是可选的,用于设置一个信号,当属性值变化时发射此信号。
- DESIGNABLE 表示属性是否在 Qt Designer 里可见,缺省为 true。
- CONSTANT 表示属性值是一个常数,对于一个对象实例,READ 指定的函数返回值是常数,但是每个实例的返回值可以不一样。具有 CONSTANT 关键字的属性不能有 WRITE 和 NOTIFY 关键字。
- FINAL 表示所定义的属性不能被子类重载。
属性的使用
只要知道属性名称,就可以通过 QObject::property() 读取属性值,并通过 QObject::setProperty() 设置属性值。例如:
Q_PROPERTY(unsigned age READ age WRITE set_age NOTIFY age_changed)
Q_PROPERTY(QString name MEMBER name_)
//写
boy_->setProperty("score", 95);
boy_->setProperty("age", 10);
//读
const QMetaObject *meta_obj = boy_->metaObject();
QMetaProperty prop = meta_obj->property(i);
const char *prop_name = prop.name();
QString propValue = boy_->property(prop_name).toString();
QObject::setProperty() 函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。
Q_CLASSINFO
使用宏Q_CLASSINFO可以为类的元对象定义“名称-值”信息
其实这个就相当于在类内定义了一些“名称-值”的结构体数据,这些数据在程序中可以通过一些接口读取到。
类信息的定义
class QMyClass:public QObject {
Q_OBJECT
Q_CLASSINFO("author", "xiaowang")
Q_CLASSINFO("version ", "1.0.0")
public:
...
};
类信息的使用
QMyClass myclass;
const QMetaObject *meta_obj = myclass.metaObject();
for(int i = 0; i < meta_obj->classInfoCount(); i++)
{
QMetaClassInfo meta_class_info = meta_obj->classInfo(i);
qDebug() << meta_class_info.name();
qDebug() << meta_class_info.value();
}