当前位置: 首页 > news >正文

QT之Q_PROPERTY介绍以及在QWidget中的用法

目录

一、 Q_PROPERTY介绍

1、 Q_PROPERTY是什么

2、Q_PROPERTY 的语法

3、Q_PROPERTY 的作用

二、在QWidget中的用法

1、示例1:自带属性

2、 示例2:自建属性第一种

3、 示例3:自建属性第二种

4、动态属性

三、注意事项

四、总结


一、 Q_PROPERTY介绍

1、 Q_PROPERTY是什么

Q_PROPERTY 是 Qt 框架中用于声明类的属性的宏,它允许将类的属性暴露给 Qt 的元对象编译器(moc),从而支持动态属性访问、信号与槽机制、属性动画以及 QML 绑定等功能。Q_PROPERTY 通常用于定义可以在 Qt 的元对象系统中识别的属性,方便在运行时通过 QObject::property() 和 QObject::setProperty() 动态访问或修改。

2、Q_PROPERTY 的语法

Q_PROPERTY 的基本语法如下:

Q_PROPERTY(type name        READ getFunction[WRITE setFunction][RESET resetFunction][NOTIFY notifySignal][DESIGNABLE true|false][SCRIPTABLE true|false][STORED true|false][USER true|false][CONSTANT] [FINAL])
  • type: 属性的数据类型(如 int、QString、QColor 等)。
  • name: 属性的名称。
  • READ: 指定获取属性值的 getter 函数(必须)。
  • WRITE: 指定设置属性值的 setter 函数(可选)。
  • RESET: 指定重置属性值的函数(可选)。
  • NOTIFY: 指定当属性值改变时发出的信号(可选)。
  • DESIGNABLE: 指示属性是否可以在 Qt Designer 中编辑(默认为 true)。
  • SCRIPTABLE: 指示属性是否可以被脚本引擎访问(默认为 true)。
  • STORED: 指示属性是否存储在对象中(默认为 true)。
  • USER: 指示属性是否是用户可编辑的主要属性(默认为 false)。
  • CONSTANT: 指示属性是只读常量(不能有 WRITE 或 NOTIFY)。
  • FINAL: 指示属性不可被子类重写。

    下面是官方给出的对应属性(详见QT帮助文档中<the property system>):

    • 属性的行为类似于类的数据成员,但它具有通过元对象系统访问的其他特性。
    • 如果没有指定成员变量,则需要一个读访问器函数。它用于读取属性值。理想情况下,const函数用于此目的,它必须返回属性的类型或指向该类型的const引用。例如,QWidget::focus是一个只读属性,具有读取函数QWidget::hasFocus()。
    • 写访问器函数是可选的。它用于设置属性值。它必须返回void,而且必须只有一个参数,要么是属性的类型,要么是指向该类型的指针或引用。例如,QWidget::enabled具有写函数QWidget::setEnabled()。只读属性不需要写函数。例如,QWidget::focus没有写功能。
    • 如果没有指定读访问器函数,则必须关联成员变量。这使得给定的成员变量可读可写,而无需创建读写访问器函数。如果你需要控制变量访问,除了关联成员变量之外,也可以使用读写访问器函数(但不能同时使用两者)。
    • 重置功能是可选的。它用于将属性设置回其上下文特定的默认值。例如,QWidget::cursor具有典型的读写函数,QWidget::cursor()和QWidget::setCursor(),它还有一个重置函数,QWidget::unsetCursor(),因为没有调用QWidget::setCursor()可能意味着重置上下文特定的游标。RESET函数必须返回void且不接受任何参数。
    • 通知信号是可选的如果定义了,它应该指定类中存在的一个信号,每当属性的值发生变化时,该信号就会发出。成员变量的通知信号必须接受零个或一个参数,该参数的类型必须与属性相同。这个参数将接受属性的新值。NOTIFY信号只应该在属性真正发生更改时发出,以避免在QML中不必要地重新计算绑定。当需要的成员属性没有显式设置方法时,Qt会自动发出这个信号。
    • 版本号是可选的。如果包含,它将定义在特定版本的API(通常用于QML)中使用的属性及其通知器信号。如果不包含,则默认为0。
    • DESIGNABLE属性表示该属性是否应该在GUI设计工具(例如Qt Designer)的属性编辑器中可见。大多数属性都是可设计的(默认为true)。除了true或false之外,还可以指定一个布尔成员函数。
    • SCRIPTABLE属性表示脚本引擎是否可以访问该属性(默认为true)。除了true或false之外,还可以指定一个布尔成员函数。
    • STORED属性表示该属性是独立存在的,还是依赖于其他值。它还指示在存储对象的状态时是否必须保存属性值。大多数属性都是被存储的(默认值为true),但例如QWidget::minimumWidth()被存储为false,因为它的值是从属性QWidget::minimumSize()的宽度组件中获取的,这是一个QSize。
    • USER属性指示该属性是指定为类的面向用户属性还是用户可编辑属性。通常,每个类只有一个USER属性(默认为false)。例如,QAbstractButton::checked是(可检查)按钮的用户可编辑属性。注意,QItemDelegate获取和设置小部件的USER属性。
    • 常量属性的出现表明该属性的值是常量。对于给定的对象实例,常量属性的READ方法必须每次调用都返回相同的值。这个常量的值可能因对象的不同实例而不同。常量属性不能有写方法或通知信号。
    • 最终属性的存在表明该属性不会被派生类覆盖。这在某些情况下可用于性能优化,但moc并不强制执行。必须注意,永远不要覆盖FINAL属性
    • REQUIRED属性的出现表明该属性应该由类的用户设置。这不是moc强制的,并且对暴露给QML的类非常有用。在QML中,除非设置了所有必需的属性,否则具有必需属性的类无法实例化。
    • READ、WRITE和RESET函数可以继承。它们也可以是虚拟的。在使用多重继承的类中继承时,它们必须来自第一个继承的类
    • 属性类型可以是QVariant支持的任何类型,也可以是用户定义的类型

    3、Q_PROPERTY 的作用

    1. 动态属性访问:通过 QObject 的 property() 和 setProperty() 方法动态读写属性。
    2. 信号与槽:通过 NOTIFY 指定的信号,属性变化时可以触发槽函数。
    3. QML 集成:Q_PROPERTY 允许 C++ 类的属性直接在 QML 中访问和绑定。
    4. Qt Designer 支持:在 Qt Designer 中,Q_PROPERTY 声明的属性可以显示并编辑。
    5. 属性动画:属性可以被 Qt 的动画框架使用。

    二、在QWidget中的用法

    1、示例1:自带属性

    新建一个QWidget Application,在UI界面中添加几个QLineEdit和QPushButton,如下面所示:

    // Widget.h
    #ifndef WIDGET_H
    #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
    namespace Ui {
    class Widget;
    }
    QT_END_NAMESPACEclass Widget : public QWidget
    {Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_btn1_clicked();private:Ui::Widget *ui;
    };
    #endif // WIDGET_H// Widget.cpp
    #include "widget.h"
    #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
    {ui->setupUi(this);}Widget::~Widget()
    {delete ui;
    }void Widget::on_btn1_clicked()
    {auto str = ui->lineEdit->property("text").toString();ui->lineEdit_2->setText(str);ui->lineEdit_3->setProperty("text",str);
    }

    通过QObject::property("text").toString()获取属性值,通过QObject::setProperty("text",str);达到设置属性值的作用,与QObject::setText(str);达到了同样的效果。

    点击按键,运行结果如下:

    2、 示例2:自建属性第一种

    // Widget.h 
    #ifndef WIDGET_H
    #define WIDGET_H#include <QWidget>
    #include <QObject>QT_BEGIN_NAMESPACE
    namespace Ui {
    class Widget;
    }
    QT_END_NAMESPACEclass Widget : public QWidget
    {Q_OBJECTQ_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)public:Widget(QWidget *parent = nullptr);~Widget();QString name() const { return m_name; }void setName(const QString &name){if (m_name != name) {m_name = name;emit nameChanged(m_name);}}signals:void nameChanged(const QString text);private slots:void on_btn1_clicked();private:Ui::Widget *ui;QString m_name;
    };
    #endif // WIDGET_H// Widget.cpp
    #include "widget.h"
    #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
    {ui->setupUi(this);connect(this, &Widget::nameChanged, ui->label, &QLabel::setText, Qt::AutoConnection);}Widget::~Widget()
    {delete ui;
    }void Widget::on_btn1_clicked()
    {this->setProperty("name", ui->lineEdit->text());ui->lineEdit_2->setText(this->property("name").toString());ui->lineEdit_3->setProperty("text",this->property("name").toString());
    }

            创建一个属性:
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    其中:READ name是读属性值,WRITE setName是设置属性值,NOTIFY nameChanged是发送信号。
            当点击按键后,首先设置自定义属性值,然后依次调用方法设置文本,调用属性设置文本,以及通过信号和槽绑定属性修改Label的文本,结果如下:

    3、 示例3:自建属性第二种

    // Widget.h
    #ifndef WIDGET_H
    #define WIDGET_H#include <QWidget>
    #include <QObject>QT_BEGIN_NAMESPACE
    namespace Ui {
    class Widget;
    }
    QT_END_NAMESPACEclass Widget : public QWidget
    {Q_OBJECTQ_PROPERTY(QString name MEMBER m_name READ name2 WRITE setName2 NOTIFY nameChanged)public:Widget(QWidget *parent = nullptr);~Widget();QString name() const { return m_name; }void setName(const QString &name){if (m_name != name) {m_name = name;emit nameChanged(m_name);}}QString name2() const { return m_name; }void setName2(const QString &name){m_name = name + " name2";emit nameChanged(m_name);}signals:void nameChanged(const QString text);private slots:void on_btn1_clicked();void on_btn2_clicked();private:Ui::Widget *ui;QString m_name;
    };
    #endif // WIDGET_H// Widget.cpp
    #include "widget.h"
    #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
    {ui->setupUi(this);connect(this, &Widget::nameChanged, ui->label, &QLabel::setText, Qt::AutoConnection);
    }Widget::~Widget()
    {delete ui;
    }void Widget::on_btn1_clicked()
    {this->setName(ui->lineEdit->text());ui->lineEdit_2->setText(name());ui->lineEdit_3->setProperty("text",name());
    }void Widget::on_btn2_clicked()
    {this->setProperty("name", ui->lineEdit->text());ui->lineEdit_2->setText(this->property("name").toString());ui->lineEdit_3->setProperty("text",name());
    }

            创建一个属性:
    Q_PROPERTY(QString name MEMBER m_name READ name2 WRITE setName2 NOTIFY nameChanged) 其中 :MEMBER m_name指定变量m_name,  READ name2是读属性值,WRITE setName2是设置属性值,NOTIFY nameChanged是发送信号。
            当点击按键后,首先设置自定义属性值,然后依次调用方法设置文本,调用属性设置文本,以及通过信号和槽绑定属性修改Label的文本。

            当按下Start1结果如下:

    当按下Start2,运行结果如下:

    通过上述方法可以实现复杂的属性设置。

    4、动态属性

    动态属性可以在代码中添加或者是在Qt Designer中进行添加,如图所示:

    接着可以输入属性名称及类型。

    代码中添加动态属性如下:

    // Widget.h
    #ifndef WIDGET_H
    #define WIDGET_H#include <QWidget>
    #include <QObject>QT_BEGIN_NAMESPACE
    namespace Ui {
    class Widget;
    }
    QT_END_NAMESPACEclass Widget : public QWidget
    {Q_OBJECTQ_PROPERTY(QString name MEMBER m_name READ name WRITE setName NOTIFY nameChanged)public:Widget(QWidget *parent = nullptr);~Widget();QString name() const { return m_name; }void setName(const QString &name){if (m_name != name) {m_name = name;emit nameChanged(m_name);}}signals:void nameChanged(const QString text);private slots:void on_btn1_clicked();private:Ui::Widget *ui;QString m_name;
    };
    #endif // WIDGET_H// Widget.cpp#include "widget.h"
    #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
    {ui->setupUi(this);connect(this, &Widget::nameChanged, ui->label, &QLabel::setText, Qt::AutoConnection);ui->lineEdit->setProperty("string","this is string");
    }Widget::~Widget()
    {delete ui;
    }void Widget::on_btn1_clicked()
    {this->setProperty("name",ui->lineEdit->property("string").toString());ui->lineEdit_2->setText(ui->lineEdit->property("string").toString());ui->lineEdit_3->setProperty("text",ui->lineEdit->property("string").toString());
    }

    运行结果如下:

    三、注意事项

    1. moc 编译:Q_PROPERTY 依赖 Qt 的元对象编译器(moc),确保类中包含 Q_OBJECT 宏。
    2. 属性类型:属性类型必须是 Qt 支持的类型(如基本类型、QString、QColor)或已注册的自定义类型(通过 Q_DECLARE_METATYPE)。
    3. 性能:频繁更改属性可能导致多次信号发射和重绘,需优化 setter 逻辑。
    4. QML 集成:如果计划在 QML 中使用,确保属性类型和信号与 QML 兼容。

    四、总结

    Q_PROPERTY 是 Qt 中强大的工具,用于声明和管理类的属性,特别适合在 QWidget 自定义控件中扩展功能。通过 Q_PROPERTY,可以实现:

    • 动态属性访问和修改。
    • 属性变化的信号通知。
    • 与 Qt Designer 和 QML 的无缝集成。
    • 支持动画和脚本化操作。

    在 QWidget 中使用 Q_PROPERTY 的典型场景包括自定义控件的外观(如颜色、大小)、状态(如启用/禁用)或其他用户可配置的属性。通过合理设计 getter、setter 和信号,可以让自定义控件更灵活且易于集成到 Qt 生态中。

    相关文章:

  1. 武汉昊衡科技OLI光纤微裂纹检测仪:高密度光器件的精准守护者
  2. 基于Python爬虫的豆瓣电影信息爬取(可以根据选择电影编号得到需要的电影信息)
  3. GPLT-2025年第十届团体程序设计天梯赛总决赛题解(2025天梯赛题解,共计266分)
  4. -PHP 反序列化POP 链构造魔术方法流程漏洞触发条件属性修改
  5. Linux 管道理解
  6. cf | Common Multiple
  7. 来访登记二维码生成
  8. deepseek-php-client开源程序是强力维护的 PHP API 客户端,允许您与 deepseek API 交互
  9. Linux ———— 编译器g++/gcc
  10. 【3.1】pod详解——Pod的结构
  11. 32单片机——GPIO寄存器
  12. Java 异常 SSLException: fatal alert: protocol_version 全解析与解决方案
  13. Python内置函数-aiter()
  14. URI、URL与URN详解概念介绍
  15. Python内置函数---bool()
  16. 【Deepseek学习大模型推理】MOONCAKE: A KVCache-centric Architecture调度(中)调度
  17. gem5教程第六章 为ARM扩展gem5 这也是改进gem5的一个基础
  18. 深度学习--卷积神经网络调整学习率
  19. java六人打分
  20. SQL进阶知识:五、存储过程和函数
  21. 哲学家的生命终章:一场关于存在与消逝的深度对话
  22. 研讨会丨明清区域史研究的比较与对话
  23. 上海车展上的双向奔赴:跨国车企融入中国创新,联手“在中国,为全球”
  24. 观察|动力电池步入“多核时代”,宁德时代新技术密集开箱有何启示
  25. 【社论】高度警惕AI谣言对网络空间的污染
  26. 2025年一季度上海市国民经济运行情况