Qt中的属性系统

原创
Qt提供了一个非常复杂的属性系统,既允许我们使用Q_PROPERTY()宏定义编译期间的静态属性,也允许我们使用setProperty函数添加动态属性。

Q_PROPERTY()的宏定义如下:

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])

下面是一些关于标记的简单介绍:

  • READ标记: 如果没有为属性标记MEMBER标记,则READ标记必不可少。声明一个读取属性的函数。
  • WRITE标记: 可选配置。声明一个可选属性的函数,它指定的函数只能有一个参数,返回值必须为void。
  • MEMBER标记: 如果你没有为属性指定READ函数就必须为其关联一个成员变量,这样的话这个成员变量不用指定READ/WRITE函数就可以读写。当然,如果你想控制其读写,也可以指定READ/WRITE函数。
  • RESET标记: 可选配置。这个函数设定的目的是为了让一个属性回滚到与其上下文匹配的默认值。
  • NOTIFY标记: 可选配置。给属性关联一个信号(该信号必须是已在类中声明过的),当属性的值发生变化时就会触发该信号。为MEMBER变量指定的NOTIFY信号最多只能有一个参数,而且其类型必须与属性的类型一致。当信号出发时,它的值就是属性的值。
  • REVISON标记: 可选配置。这个标记通常是将属性导出到QML中使用时指定的,它指定了属性适用的API版本。默认值为0。
  • DESIGNABLE标记: 可选配置。用来说明一个属性是否可被Qt Designer使用,默认值为true。你也可以使用一个返回布尔值的成员函数代替true或false。
  • SCRIPTABLE标记: 可选配置。用来说明一个属性是否可以被脚本引擎访问,默认值为true。
  • STORED标记: 可选配置。表明一个属性是独立存在的,还是从其他属性值衍生出来的。默认值为true。
  • USER标记: 可选配置。表明一个属性是否设计为面向用户的或者用户可编辑的。一般一个类只能有一个USER标记为true的属性,默认为false。
  • CONSTANT标记: 可选配置。表明一个属性为常量。一个标明为常量的属性不能有WRITE函数和NITIFY信号。
  • FINAL标记: 可选配置。标明一个属性不能被派生类修改。moc工具不会检查一个FINAL标记为true的属性是否被派生类修改,因此实现者要自己小心注意别在派生类中修改它。

下面是一个关于属性使用的简单示例:

.h文件中的代码:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QVBoxLayout>

class Widget : public QWidget
{
    Q_OBJECT

    Q_PROPERTY(int testProperty READ testProperty WRITE setTestProperty NOTIFY testPropertyChanged)

public:
    Widget(QWidget *parent = 0);
    ~Widget();

private:
    int m_TestProperty;
    int testProperty() const;
    void setTestProperty(int);

signals:
    void testPropertyChanged(int);
};

// ---------------------------------------------------------------------
class TestPropertyWidget : public QWidget
{
    Q_OBJECT

public:
    TestPropertyWidget(QWidget *parent = nullptr);
    ~TestPropertyWidget();

    Widget *getMainWidget(void){
        return m_Widget;
    }

private:
    Widget *m_Widget = nullptr;
};

#endif // WIDGET_H

.cpp中的代码

#include "widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    m_TestProperty = 10;
}

Widget::~Widget()
{

}

int Widget::testProperty() const
{
    return m_TestProperty;
}

void Widget::setTestProperty(int property)
{
    m_TestProperty = property;
    emit testPropertyChanged(property);
}

// ---------------------------------------------------------------------
TestPropertyWidget::TestPropertyWidget(QWidget *parent)
    :QWidget(parent)
{
    QVBoxLayout *m_MainLayout = new QVBoxLayout(this);

    m_Widget = new Widget;
    m_MainLayout->addWidget(m_Widget);

    QObject::connect(m_Widget, &Widget::testPropertyChanged, [&](int testPropertyValue)->void{
       qDebug() << "TestPropertyChanged " <<  testPropertyValue;
    });
}

TestPropertyWidget::~TestPropertyWidget()
{

}

main函数中的调用:

#include "widget.h"
#include <QApplication>
#include <QObject>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TestPropertyWidget w;
    w.setGeometry(100, 100, 800, 600);
    w.show();

    qDebug() << w.getMainWidget()->property("testProperty").toInt();

    w.getMainWidget()->setProperty("testProperty", 20);


    return a.exec();
}

程序的最终输出结果为
10
TestPropertyChanged 20

首先打印属性“testProperty”中的值,然后为改变属性中的值为20,属性发生变化时发送信号通知,在接收信号的处理函数中打印“TestPropertyChanged 20

不会飞的纸飞机
扫一扫二维码,了解我的更多动态。

下一篇文章:Qt中的模态、非模态、半模态对话框