Qt之属性系统
一、属性的定义
1.赋予属性读写操作
Qt提供了一个Q_PROPERTY()宏可以定义属性,它也是基于元对象系统实现的,在QObject的子类中,用Q_PROPERTY()定义属性。
QWidget类兴义属性的一些例子:
Q_PROPERTY(bool focus READ hasFocus) Q_PROPERTY(bool enable READ isEnable WRITE setEnable) Q_PROPERTY(QCursor cursor READ WRITE setCursor RESET unsetCursor)
Q_PROPERTY(bool focus READ hasFocus):定义了一个focurs属性,指明了它是bool类型,而且需要用自定义的hasFocus()函数来读取这个属性值。
Q_PROPERTY(bool enable READ isEnable WRITE setEnable):定义了一个enable属性,指明了它是bool类型,需要使用自定的isEnable()函数读取这个属性值,通过setEnable()函数来修改属性值。
Q_PROPERTY(QCursor cursor READ WRITE setCursor RESET unsetCursor):定义了一个cursor属性,指明了它是QCursor 类型,需要使用自定的setCursor()函数来修改属性值,通过unsetCursor()函数来进行默认值设置。
2.将类的成员变量导出为一个属性值
上述所说的属性值并不是QWidget的成员变量,如果想要将QWidget类中的某个变量导出一个属性值,需要使用关键字MEMBER将变量注册到Qt的属性系统中。
如下所示:
class Person : public QObject
{ Q_OBJECT Q_PROPERTY(QString name MEMBER m_name) private: QString m_name; };
上述代码中把Person类中的私有成员变量m_name导出为一个属性值,并且命名为name,那么从外界访问时能识别到的的属性值只有name而不是m_name。
3.Q_PROPERTY的常用格式
我们声明的属性值,常用的操作无非就是读、写、将成员变量导出为属性值、关联信号等。
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChaned)
Q_PROPERTY(QString name MEMBER m_name)
public:
explicit Person(QString name, QObject *parent = nullptr);
int age();
void setAge(int value);
signals:
void ageChaned(int value);
private:
int m_age;
QString m_name;
};
例如上述代码中:
- 使用age这个属性值,用READ关键字指定获取属性值的函数为age(),用WRITE关键指定修改属性值的函数为setAge()。
- 上述的age这个属性值并不是类中的成员变量,是凭空声明出来的一个属性值,如果想要将类中已有的成员变量设置为属性值,需要使用关键字MEMBER,如代码中的属性name关联着m_name,修改属性值name时,m_name的值也会随之改变。
- 给属性值设置关联信号,如果我们希望某个属性值变化时能够发出信号,Qt的属性系统是用关键字NOTIFY来指定信号。
二、属性的使用
不管是否使用了READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QObject:property()读取属性值,并通过QObject::setProperty()设置属性值
例如:
QPushButton *pButton = new QPushButton(this);
pButton->setProperty("flat", QVariant(true));
bool bFlat = pButton->property("flat").toBool();
1.动态属性
- 动态属性是在运行时动态添加到对象上的属性,而不需要在编译时声明或定义。
- 你可以使用
QObject类的setProperty方法来为对象添加动态属性,这个方法接受属性名和属性值作为参数。 - 动态属性对于自定义属性非常有用,因为它们允许你在不修改类定义的情况下为对象添加自定义信息。
- 动态属性通常用于个别对象实例,而不是整个类。
2.静态属性:
- 静态属性是在编译时静态定义的属性,它们通常在类定义中使用
Q_PROPERTY宏来声明。 - 静态属性的声明通常伴随着属性的读取和写入方法的定义,以及属性的默认值等信息。
- 静态属性通常用于整个类,而不是单个对象实例。这意味着所有该类的对象共享相同的属性。
下面示例演示了动态属性和静态属性的区别:
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString staticProperty READ getStaticProperty)
public:
QString getStaticProperty() const { return m_staticProperty; }
private:
QString m_staticProperty = "Static Property Value";
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyObject object1;
object1.setProperty("dynamicProperty", "Dynamic Property Value"); // 添加动态属性
QString dynamicValue = object1.property("dynamicProperty").toString(); // 读取动态属性值
QString staticValue = object1.getStaticProperty(); // 读取静态属性值
qDebug() << "Dynamic Property:" << dynamicValue; // 输出动态属性值
qDebug() << "Static Property:" << staticValue; // 输出静态属性值
return app.exec();
}
在这个示例中,dynamicProperty 是一个动态属性,可以在运行时添加。staticProperty 是一个静态属性,通过 Q_PROPERTY 宏在类定义中声明。
总的来说,动态属性用于为对象添加自定义属性,而静态属性用于在类级别定义属性,通常伴随着属性的读取和写入方法。
3.类的附加信息
属性系统还有一个宏Q_CLASSINFO(),可以为类的元对象定义"名称-值"信息,如下所示:
class Person : public QObject
{
Q_OBJECT
Q_CLASSINFO("author", "Wang")
Q_CLASSINFO("company", "UPC")
Q_CLASSINFO("version", "1.0.0")
public:
...
};
用Q_CLASSINFO()宏定义附加类信息后,可以通过元对象的一些函数获取类的附件信息,如calssInfo(int)获取某个附加信息。
函数原型定义如下:
QMetaClassInfo QMteaObject::classInfo(int index) const
返回值是QMetaClassInfo类型,有name()和value两个函数,可获得类附加信息的名称和值。
示例代码如下:
Person *pBoy = new Person();
const QMetaObject* metaObject = pBoy->metaObject();
int infoCount = metaObject->classInfoCount();
for (int i = 0; i < infoCount; ++i) {
QMetaClassInfo info = metaObject->classInfo(i);
qDebug() << "Key:" << info.name() << ", Value:" << info.value();
}
打印信息:

4.在不知道类的属性情况下获取属性的值
Person *pBoy = new Person("王小明");
const QMetaObject *metaobject = pBoy->metaObject();
int count = metaobject->propertyCount();
for (int i = 0; i < count; ++i) {
QMetaProperty metaproperty = metaobject->property(i);
const char *name = metaproperty.name();
QVariant value = pBoy->property(name);
}
三、完整代码示例
头文件:
#ifndef PERSON_H
#define PERSON_H
#include <QObject>
class Person : public QObject
{
Q_OBJECT
Q_CLASSINFO("author", "Wang")
Q_CLASSINFO("company", "UPC")
Q_CLASSINFO("version", "1.0.0")
Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChaned)
Q_PROPERTY(QString name MEMBER m_name)
Q_PROPERTY(int score MEMBER m_score)
public:
explicit Person(QString name, QObject *parent = nullptr);
int age();
void setAge(int value);
void incAge();
signals:
void ageChaned(int value);
private:
int m_age;
QString m_name;
int m_score;
};
#endif // PERSON_H
源文件:
#include "person.h"
Person::Person(QString name, QObject *parent) : QObject(parent)
{
m_name = name;
}
int Person::age()
{
return m_age;
}
void Person::setAge(int value)
{
m_age = value;
emit ageChaned(m_age);
}
void Person::incAge()
{
m_age++;
emit ageChaned(m_age);
}
属性调用:
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
{
m_pBoy = new Person("王小明");
connect(m_pBoy, &Person::ageChaned, this, &MainWindow::on_ageChanged);
m_pBoy->setProperty("socre", QVariant(95));
m_pBoy->setProperty("sex", QVariant("Boy")); //动态属性
m_pBoy->setProperty("age", QVariant(10));
}
MainWindow::~MainWindow()
{
}
void MainWindow::on_ageChanged(int value)
{
Q_UNUSED(value);
Person *pPserson = qobject_cast<Person*>(sender()); //类型投射
QString name = pPserson->property("name").toString();
QString sex = pPserson->property("sex").toString();
//int age = pPserson->property("age").toInt();//通过属性获取年龄
int age = pPserson->age(); //通过接口函数获取年龄
qDebug() << name + "," + sex + "," + QString::asprintf("年龄=%d", age);
}
打印信息:

浙公网安备 33010602011771号