Qt之属性系统

一、属性的定义

1.赋予属性读写操作

Qt提供了一个Q_PROPERTY()宏可以定义属性,它也是基于元对象系统实现的,在QObject的子类中,用Q_PROPERTY()定义属性。

QWidget类兴义属性的一些例子:

1
2
3
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的属性系统中。

如下所示:

1
2
3
4
5
6
class Person : public QObject <br>{
    Q_OBJECT
    Q_PROPERTY(QString name MEMBER m_name)
private:
    QString m_name;
};

上述代码中把Person类中的私有成员变量m_name导出为一个属性值,并且命名为name,那么从外界访问时能识别到的的属性值只有name而不是m_name。

3.Q_PROPERTY的常用格式

我们声明的属性值,常用的操作无非就是读、写、将成员变量导出为属性值、关联信号等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);<br>
signals:
    void ageChaned(int value);<br>
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()设置属性值

例如:

1
2
3
QPushButton *pButton = new QPushButton(this);
pButton->setProperty("flat", QVariant(true));
bool bFlat = pButton->property("flat").toBool();

1.动态属性

  • 动态属性是在运行时动态添加到对象上的属性,而不需要在编译时声明或定义。
  • 你可以使用 QObject 类的 setProperty 方法来为对象添加动态属性,这个方法接受属性名和属性值作为参数。
  • 动态属性对于自定义属性非常有用,因为它们允许你在不修改类定义的情况下为对象添加自定义信息。
  • 动态属性通常用于个别对象实例,而不是整个类。

2.静态属性:

  • 静态属性是在编译时静态定义的属性,它们通常在类定义中使用 Q_PROPERTY 宏来声明。
  • 静态属性的声明通常伴随着属性的读取和写入方法的定义,以及属性的默认值等信息。
  • 静态属性通常用于整个类,而不是单个对象实例。这意味着所有该类的对象共享相同的属性。

下面示例演示了动态属性和静态属性的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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(),可以为类的元对象定义"名称-值"信息,如下所示:

1
2
3
4
5
6
7
8
9
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)获取某个附加信息。

函数原型定义如下:  

1
QMetaClassInfo QMteaObject::classInfo(int index) const

返回值是QMetaClassInfo类型,有name()和value两个函数,可获得类附加信息的名称和值。

示例代码如下:

1
2
3
4
5
6
7
8
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.在不知道类的属性情况下获取属性的值

1
2
3
4
5
6
7
8
9
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);
} 

三、完整代码示例

头文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#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

源文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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);
}

属性调用:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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);
}

打印信息: 

  

posted @   TechNomad  阅读(917)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示