Qt扫盲-Qt 属性系统记录

news2024/12/27 10:13:51

Qt 属性系统记录

  • 一、概述
  • 二、属性声明
  • 三、通过元对象系统读写属性
  • 四、简单例子
  • 五、动态属性
  • 六、对一个类添加额外的属性

一、概述

Qt 提供了一个复杂的属性系统,类似于一些编译器供应商提供的系统。然而,作为一个独立于编译器和平台的库,Qt并不依赖于诸如 __property 或 [property] 这样的非标准编译器特性。Qt 解决方案适用于Qt支持的所有平台上的任何标准c++编译器。属性系统基于元对象系统,元对象系统还通过信号和槽提供对象间通信。

属性在哪里是被用到的呢?属性我一般用的多是通过 qml 来与 c++ 交互的时候,数据交互的时候使用。

属性在 Qt 的帮助文档里看到是这样的,就是 Properties.
在这里插入图片描述

二、属性声明

声明也很简单,要声明属性,请在 继承 QObject的类 中使用Q_PROPERTY()宏,继承的类必须继承QObject 。

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 后面的都是跟的一个函数哈,

下面是一些取自QWidget类的属性声明的典型示例。

  Q_PROPERTY(bool focus READ hasFocus)
  Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
  Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)

下面的例子展示了如何使用member关键字将成员变量导出为Qt属性。

注意,必须指定一个通知信号以允许QML属性绑定。

      Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
      Q_PROPERTY(qreal spacing MEMBER m_spacing NOTIFY spacingChanged)
      Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged)
      ...
  signals:
      void colorChanged();
      void spacingChanged();
      void textChanged(const QString &newText);

  private:
      QColor  m_color;
      qreal   m_spacing;
      QString m_text;

属性的行为类似于类的数据成员,但它具有通过元对象系统访问的其他特性。重点了解一下这个 下面加粗的就好。

  • READ:如果没有指定成员变量,则需要一个读访问器函数。它用于读取属性值。理想情况下,const函数用于此目的,它必须返回属性的类型或指向该类型的const引用。例如,QWidget::focus是一个只读属性,具有读取函数QWidget::hasFocus()。
  • WRITE: 写访问器函数是可选的。它用于设置属性值。它必须返回void,而且必须只有一个参数,要么是属性的类型,要么是指向该类型的指针或引用。例如,QWidget::enabled具有写函数QWidget::setEnabled()。只读属性不需要写函数。例如,QWidget::focus没有写功能。
  • MEMBER: 如果没有指定读访问器函数,则必须关联成员变量。这使得给定的成员变量可读可写,而无需创建读写访问器函数。如果你需要控制变量访问,除了关联成员变量之外,也可以使用读写访问器函数(但不能同时使用两者)。
  • RESET:重置功能是可选的。它用于将属性设置回其上下文特定的默认值。例如,QWidget::cursor具有典型的读写函数,QWidget::cursor()和QWidget::setCursor(),它还有一个重置函数,QWidget::unsetCursor(),因为没有调用QWidget::setCursor()可能意味着重置上下文特定的游标。RESET函数必须返回void且不接受任何参数。
  • NOTIFY: 通知信号是可选的。如果定义了,它应该指定类中存在的一个信号,每当属性的值发生变化时,该信号就会发出。成员变量的通知信号必须接受零个或一个参数,该参数的类型必须与属性相同。这个参数将接受属性的新值。NOTIFY信号只应该在属性真正发生更改时发出,以避免在QML中不必要地重新计算绑定。当需要的成员属性没有显式设置方法时,Qt会自动发出这个信号。
  • REVISION: 版本号是可选的。如果包含,它将定义在特定版本的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属性。
  • CONSTANT:常量属性的出现表明该属性的值是常量。对于给定的对象实例,常量属性的READ方法必须每次调用都返回相同的值。这个常量的值可能因对象的不同实例而不同。常量属性不能有写方法或通知信号。
  • FINAL:最终属性的存在表明该属性不会被派生类覆盖。这在某些情况下可用于性能优化,但moc并不强制执行。必须

注意,永远不要覆盖FINAL属性。
READ、WRITE和RESET函数可以继承。它们也可以是虚拟的。在使用多重继承的类中继承时,它们必须来自第一个继承的类。

属性类型可以是QVariant支持的任何类型,也可以是用户定义的类型。在这个例子中,类QDate被认为是一个用户定义的类型。

Q_PROPERTY(QDate date READ getDate WRITE setDate)

因为QDate是用户定义的,所以必须在属性声明中包含头文件。
由于历史原因,QMap和QList作为属性类型是QVariantMap和QVariantList的同义词。

三、通过元对象系统读写属性

可以使用泛型函数 QObject::property() 和 QObject::setProperty() 来读取和写入属性,而不需要了解除属性名称之外的所有所属类。在下面的代码片段中有两个方法设置属性,调用QAbstractButton::setDown()和调用QObject::setProperty()都将属性设置为“down”。

QPushButton *button = new QPushButton;
QObject *object = button;

button->setDown(true);
object->setProperty("down", true);

通过WRITE访问器访问属性是两者中更好的一种,因为它更快,并且在编译时提供更好的诊断,但是以这种方式设置属性要求我们在编译时了解类。通过名称访问属性使我们可以访问在编译时不知道的类。我们可以在运行时通过查询类的QObject、QMetaObject和QMetaProperties来发现类的属性。

QObject *object = ...
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i=0; i<count; ++i) {
      QMetaProperty metaproperty = metaobject->property(i);
      const char *name = metaproperty.name();
      QVariant value = object->property(name);
      ...
}

在上面的代码片段中,QMetaObject::property() 用于获取关于某个未知类中定义的每个属性的元数据。属性名从元数据中获取,并传递给 QObject::property() 以获得当前对象中属性的值。

四、简单例子

假设我们有一个MyClass类,它派生自QObject,并在其私有部分中使用Q_OBJECT宏。我们想在MyClass中声明一个属性来跟踪优先级值。属性的名称是priority,类型是在MyClass中定义的枚举类型priority。
我们在类的private部分使用Q_PROPERTY()宏声明属性。所需的读取函数名为priority,我们还包含了一个名为setPriority的写入函数。枚举类型必须使用Q_ENUM()宏向元对象系统注册。注册枚举类型使枚举器名称可以在调用QObject::setProperty()时使用。我们还必须为READ和WRITE函数提供自己的声明。MyClass的声明看起来像这样:

  class MyClass : public QObject
  {
      Q_OBJECT
      Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)

  public:
      MyClass(QObject *parent = 0);
      ~MyClass();

      enum Priority { High, Low, VeryHigh, VeryLow };
      Q_ENUM(Priority)

      void setPriority(Priority priority)
      {
          m_priority = priority;
          emit priorityChanged(priority);
      }
      Priority priority() const
      { return m_priority; }

  signals:
      void priorityChanged(Priority);

  private:
      Priority m_priority;
  };

READ函数是const,返回属性的类型。WRITE函数返回void,并且只有一个属性类型的参数。元对象编译器实现了这些需求。
给定一个指向MyClass实例的指针或一个指向MyClass实例QObject的指针,我们有两种方法设置它的priority属性:

  MyClass *myinstance = new MyClass;
  QObject *object = myinstance;

  myinstance->setPriority(MyClass::VeryHigh);
  object->setProperty("priority", "VeryHigh");

在这个例子中,枚举类型是在MyClass中声明的属性类型,并使用Q_ENUM()宏在元对象系统中注册。这样枚举值就可以作为字符串使用,就像调用setProperty()一样。如果枚举类型是在另一个类中声明的,那么它的完全限定名称(即OtherClass::Priority)将是必需的,而且其他类也必须继承QObject并使用Q_ENUM()宏在那里注册枚举类型。

还有一个类似的宏,Q_FLAG()。与Q_ENUM()一样,它注册了一个枚举类型,但它将该类型标记为一组标志,即可以组合在一起的值。I/O类可能有可读和可写的枚举值,然后QObject::setProperty()可以接受读|写。应该使用Q_FLAG()来注册这种枚举类型。

五、动态属性

QObject::setProperty()也可以用于在运行时为类的实例添加新属性。当使用一个名称和一个值调用它时,如果QObject中存在一个具有给定名称的属性,并且给定的值与属性的类型兼容,则该值将存储在属性中,并返回true。如果值与属性的类型不兼容,则不会修改属性,返回false。但是,如果QObject中不存在给定名称的属性(即,如果没有使用Q_PROPERTY()声明它),则会自动将具有给定名称和值的新属性添加到QObject中,但仍然会返回false。这意味着返回false不能用来确定某个属性是否被设置,除非你事先知道该属性已经存在于QObject中。
请注意,动态属性是在每个实例的基础上添加的,即它们是添加到QObject,而不是QMetaObject。通过向QObject::setProperty()传递属性名和无效的QVariant值,可以从实例中删除属性。QVariant的默认构造函数构造了一个无效的QVariant。
可以使用QObject::property()查询动态属性,就像使用Q_PROPERTY()在编译时声明的属性一样。

六、对一个类添加额外的属性

连接到属性系统的是一个额外的宏,Q_CLASSINFO(),可用于将额外的名称—值对附加到类的元对象,这个属性的话就是自己加的哈,例如:

Q_CLASSINFO("Version", "3.0.0")

具体在类的写法:

  class MyClass : public QObject
  {
      Q_OBJECT
      Q_CLASSINFO("author", "Sabrina Schweinsteiger")
      Q_CLASSINFO("url", "http://doc.moosesoft.co.uk/1.0/")

  public:
      ...
  };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基础07——集合

Java基础07——集合一、集合和数组的对比二、ArrayList成员方法三、集合练习1. 添加数字并遍历2. 添加学生对象并遍历学生类测试类输出结果3. 添加用户对象并判断是否存在用户类测试类输出结果4. 添加手机对象并返回要求的数据&#xff08;返回多个数据&#xff09;手机类测试类…

【算法】Day06

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录1. BST二叉搜索树的后序遍历序列2. 二叉树中和为某一值的路径&#xff08;二&#xff09;[回溯法]3. 字符串的排列 [全排列问题]4. 最小的K个数 [topK问题]普通小孩也要热爱生活&#xff01; 1. BST二叉搜索树的后序…

IF:6+ 综合分析揭示了一种炎症性癌症相关的成纤维细胞亚型在预测膀胱癌患者的预后和免疫治疗反应方面具有重要意义...

桓峰基因的教程不但教您怎么使用&#xff0c;还会定期分析一些相关的文章&#xff0c;学会教程只是基础&#xff0c;但是如果把分析结果整合到文章里面才是目的&#xff0c;觉得我们这些教程还不错&#xff0c;并且您按照我们的教程分析出来不错的结果发了文章记得告知我们&…

Linux 中断子系统(七):注册中断

Linux 注册中断的 API request_irq():不使用中断线程化request_threaded_irq():使用中断线程化中断线程化 为什么需要将中断下半部处理线程化,原因如下: 中断具有最高优先级,有中断发生时,会抢占进程,导致实时任务不能及时处理。中断上下文总是可以抢占进程上下文,这…

【PyTorch】教程:学习基础知识-(3) Datasets-DataLoader

Dataset & DataLoader PyTorch 提供了两个数据处理的基本方法&#xff1a;torch.utils.data.DataLoader torch.utils.data.Dataset 允许使用预加载的数据集以及自己的数据。 Dataset 存储样本及其对应的标签&#xff0c; DataLoader 在 Dataset 基础上封装了一个可迭代的对…

Python文本颜色设置

Python文本颜色设置实现过程&#xff1a;书写格式&#xff1a;数值表示的参数含义&#xff1a;常见开头格式&#xff1a;实例&#xff1a;实现过程&#xff1a; 终端的字符颜色是用转义序列控制的&#xff0c;是文本模式下的系统显示功能&#xff0c;和具体的语言无关。 转义序…

Acwing4699. 如此编码

某次测验后&#xff0c;顿顿老师在黑板上留下了一串数字 23333 便飘然而去。 凝望着这个神秘数字&#xff0c;小 P 同学不禁陷入了沉思…… 已知某次测验包含 nn 道单项选择题&#xff0c;其中第 i 题&#xff08;1≤i≤n&#xff09;有 ai 个选项&#xff0c;正确选项为 bi&…

CAS And Atomic

CAS(Compare And Swap 比较并交换)&#xff0c;通常指的是这样一种原子操作&#xff1a;针对一个变量&#xff0c;首先比较它的内存值与某个期望值是否相同&#xff0c;如果相同&#xff0c;就给它赋一个新值,底层是能保证cas是原子性的CAS的应用 在Java 中&#xff0c;CAS 操作…

Android开发-AS学习(三)(布局)

相关文章链接&#xff1a;Android开发-AS学习&#xff08;一&#xff09;&#xff08;控件&#xff09;Android开发-AS学习&#xff08;二&#xff09;(控件&#xff09;Android开发应用案例——简易计算器&#xff08;附完整源码&#xff09;二、布局2.1 Linearyout常见属性说…

测试NGINX和uwsgi.ini设置

1.uwsgi修改测试 将服务器升级到16核16G配置后&#xff0c;我将uwsgi.ini中的部分参数调整如下&#xff1a; processes 32 threads 16 结果是导致内存暴满&#xff0c;然后直接服务器都无法连接&#xff0c;导致服务器卡死。之前有博客说processes处理器*2&#xff0c;结果…

【阶段三】Python机器学习26篇:机器学习项目实战:LightGBM回归模型

本篇的思维导图: 项目实战(LightGBM回归模型) 项目背景 为促进产品的销售,厂商经常会通过多个渠道投放广告。本案例将根据某公司在电视、广播和报纸上的广告投放数据预测广告收益,作为公司制定广告策略的重要参考依据。 本项目应用LightGBM回归算法进行项目实战,整…

Nginx入门

介绍&#xff1a; 下载和安装&#xff1a; 安装过程&#xff1a; 1、因为nginx是由c语言编写的&#xff0c;所以需要下载gcc进行编译 yum -y install gcc pcre-devel zlib-devel openssl openssl-devel 2、下载nginx安装包 wget https://nginx.org/download/nginx-1.16.1.ta…

【Java基础知识 1】第一个Java程序(Java的第一步)

本文已收录专栏 &#x1f332;《Java进阶之路》&#x1f332; 编写一个Java程序 第一个Java程序非常简单&#xff0c;代码如下&#xff1a; public class Java01_HelloWorld {public static void main(String[] agrs){System.out.println("欢迎来到Java进阶之路&#x…

蓝桥杯 stm32 按键点灯 CubeMX

注&#xff1a;我们使用的是 HAL 库 文章目录前言一、按键 原理图&#xff1a;二、按键CubeMX配置:三、代码讲解1. 读按键&#xff1a;&#xff08; 三行代码&#xff09;2.按键消抖&#xff1a;3&#xff0c;按键点灯&#xff1a;总结实验效果&#xff1a;前言 一、按键 原理…

基于yolov5-v7.0开发构建银行卡号实例分割检测识别分析系统

在之前的文章中我们已经做了很多基于yolov5完成实例分割的项目&#xff0c;感兴趣的话可以自行移步阅读&#xff1a;《基于YOLOv5-v7.0的药片污染、缺损裂痕实例分割检测识别分析系统》《基于yolov5-v7.0开发构建裸土实例分割检测识别模型》《基于yolov5-v7.0开发实践实例分割模…

CSDN第24期周赛(记录一下)

▶ 爱要坦荡荡 (163.com) 每一道题都有思路&#xff0c;可是只有一道Accepted100%&#xff0c;一道很简单的50%&#xff0c;一道输出错误10%并报错Segmentation Fault&#xff0c;一道字符串有思路但是没时间了 一&#xff0c;蛇皮矩阵 Accepted 10% 报错Segmentation Fault…

2、矩阵介绍

目录 一、矩阵的构造 二、矩阵大小及结构的改变 三、矩阵下标的引用 1.矩阵下标访问单个矩阵元 2.线性引用矩阵元 3.访问多个矩阵元素 四、矩阵信息的提取 1.矩阵结构 2.矩阵大小 3.矩阵的数据类型 一、矩阵的构造 矩阵的构建方式有两种&#xff0c;一种与单元数组相…

【寒假每日一题】DAY.7 有序序列判断

牛客网例题&#xff1a;点我做题 【❤️温馨提示】先做题&#xff0c;再看讲解效果更佳哟 描述 输入一个整数序列&#xff0c;判断是否是有序序列&#xff0c;有序&#xff0c;指序列中的整数从小到大排序 或者从大到小排序(相同元素也视为有序)。输入描述&#xff1a; 第一行…

【C++】stack、queue的模拟实现及deque介绍

一、stack 1. 以vector作为底层容器 从栈的接口中可以看出&#xff0c;栈实际是一种特殊的vector&#xff0c;因此使用vector完全可以模拟实现stack。 由于stack的所有工作是底层容器完成的&#xff0c;而这种具有“修改某物接口&#xff0c;形成另一种风貌”的性质&#xf…

Dubbo学习

文章目录1.概念1.1 Dubbo特性1.2 设计架构2.快速开始2.1需求假设2.2.工程架构2.3 创建模块2.3.1 gmall-interface—公共接口层2.3.2 gmall-user—用户模块2.3.3 gmall-order-web—订单模块2.3.4 测试结果2.3.5 使用Dubbo改造2.3.6 注解版3.监控中心4.整合SpringBoot5.Dubbo配置…