Qt元对象系统及应用(一)

2023-11-12

1.元对象系统

元对象系统(Meta-Object System)是Qt框架中一个非常重要的机制,它提供了一种在运行时动态获取对象信息的方法,并且能够实现对象之间的通信。

元对象系统的核心是QObject类提供的QMetaObject对象。每个QObject对象都有一个对应的QMetaObject成员,它包含了该对象的类型信息、信号和槽信息、属性信息、枚举信息等。这些信息在运行时可以被动态获取,从而实现了许多高级特性,如信号和槽、元数据反射等。

在使用元对象系统时,要在QObject的子类中添加Q_OBJECT宏来启用元对象特性。这个宏会自动生成一些元对象信息,并且会将这些信息注册到Qt的元对象系统中。当对象被实例化时,它的元对象信息也会被创建并注册到元对象系统中。

元对象编译器( Meta-Object Compile, Moc)为QObject的子类提供了实现元对象特性所必须得代码。

我们还可以使用qobject_cast来检查一个对象是否是某个特定类型或其派生类的实例。这是通过比较对象的元对象来实现的,如果元对象的名称与目标类型相同或目标类型是元对象所对应类型的基类,那么就认为这个对象是目标类型的实例。这种方法比C++中的dynamic_cast更高效,因为它只涉及元对象的比较,而不需要进行运行时类型检查。

元对象系统涉及的主要类有下面几个:

  • QMetaObject 元对象类
  • QMetaClassInfo 封装了类的信息
  • QMetaMethod 封装了类中的方法信息
  • QMetaProperty 封装了类中的属性信息

2.元对象与属性系统

Qt提供了一个复杂的属性系统,作为一个独立于编译器和平台的库,它不依赖于任何非标准编译器功能。Qt可与其支持的每个平台上的C++编译器配合使用。属性系统是基于元对象系统实现的。下面是属性声明的通用公式:


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

属性声明举例:

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

  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
    如果未指定MEMBER变量,则需要READ访问器函数。用于读取属性值。理想情况下,const函数用于此目的,并且它必须返回属性的类型或对该类型的const引用。例如,QWidget::focus是一个带有read函数的只读属性,QWidget::hasFocus()。
  • WRITE
    访问器函数是可选的。用于设置属性值。它只接受一个参数,要么是属性的类型,要么是指向该类型的指针或引用。例如,QWidget::enabled具有WRITE函数QWidget::setEnabled()。只读属性不需要WRITE函数。例如,QWidget::focus没有WRITE功能。
  • MEMBER
    如果未指定READ访问器函数,则需要MEMBER变量关联。这使得给定的成员变量可读写,而无需创建READ和WRITE访问器函数。如果需要控制变量访问,除了MEMBER变量关联之外,还可以使用READ或WRITE访问器函数(但不能同时使用这两种函数)。
  • RESET
    重置功能是可选的。它用于将属性设置回其上下文特定的默认值。例如,QWidget::cursor具有典型的READ和WRITE函数,QWidget::cursors()和QWidgep::setCursor(),RESET函数必须返回void,并且不接受任何参数。
  • NOTIFY
    通知是可选的。如果使用该关键词,则应该指定该类中的一个现有信号,该信号在属性值更改时发出。MEMBER变量的NOTIFY信号必须为零或一个参数,该参数必须与属性的类型相同。该参数将采用属性的新值。NOTIFY信号应该只在属性真正更改时发出,以避免在QML中不必要地重新评估绑定。当没有显式setter的MEMBER属性需要时,Qt会自动发出该信号。
  • REVISION
    修订号是可选的。如果包括在内,它定义了要在API的特定版本中使用的属性及其通知信号(通常用于暴露于QML)。如果不包括在内,则默认为0。
  • DESIGNABLE
    表示属性是否应在GUI设计工具(例如Qt Designer)的属性编辑器中可见。大多数属性都是DESIGNABLE(默认为true)。可以指定一个布尔成员函数。
  • SCRIPTABLE
    表示脚本引擎是否应该访问此属性(默认为true)。可以指定一个布尔成员函数。
  • STORED
    表示属性应该被认为是单独存在还是依赖于其他值。它还指示在存储对象的状态时是否必须保存属性值。大多数属性都是STORED(默认为true),但例如,QWidget::minimumWidth的STORED为false,因为它的值只是取自属性QWidget::minimumSize的宽度组件,该属性是QSize。
  • USER
    表示该属性是指定为类的面向用户属性还是用户可编辑属性。通常,每个类只有一个USER属性(默认值为false)。例如,QAbstractButton::checked是用户可编辑属性。请注意,QItemDelegate获取并设置小部件的USER属性。
  • CONSTANT
    表示属性值是常量。对于给定的对象实例,常量属性的READ方法每次调用时都必须返回相同的值。对于对象的不同实例,该常数值可能不同。常量属性不能具有WRITE方法或NOTIFY信号。
  • FINAL
    表示派生类不会覆盖该属性。在某些情况下,这可以用于性能优化,但moc不会强制执行。必须注意决不能覆盖FINAL属性。

通过元对象系统访问属性:

  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);
      ...
  }

2.1 动态属性

通过QObject子类对象的setProperty函数可以设置一个不存在的属性,该属性将存储在QObject 子类对象中,而不是QMetaObject中,不能通过元对象系统访问。这类属性称为动态属性。如果绑定动态属性的数据类型是自定义类型,则需要通过Q_DECLARE_METATYPE()宏声明,这样属性值才能通过QVariant包装存储。

3. 元对象与信号槽

信号和槽是Qt框架的重要特性之一,用来在对象之间通信。元对象系统为信号槽的实现提供了底层支持。

3.1 信号槽应用场景

在GUI编程中,当触发某个事件时,我们通常希望通知另一个对象。更普遍地说,我们希望所有对象之间都能够相互交流。例如,用户单击Close按钮,我们可能希望调用窗口的Close函数。其他框架使用回调来实现这种通信,回调是指向函数的指针。虽然使用这种方法的成功框架确实存在,但回调可能是不直观的,并且在确保回调参数的类型正确性方面可能会遇到问题。

在Qt中,使用信号和槽在对象间通信,当特定事件发生时,会发出一个信号。QWidget 有许多预定义的信号,我们也可以继承QWidget实现自定义UI组件,并在子类中添加我们自己的信号。槽是响应特定信号而调用的函数。QWidget有许多预定义的槽函数,但通常的做法是子类化QWidget,并添加自己的槽函数,以便处理相应的信号。

3.2 信号槽的连接

信号槽机制是类型安全的:信号的签名必须与接收插槽的签名匹配。基于字符串的SIGNAL和SLOT语法将在运行时检测类型不匹配。信号和槽是松散耦合的:发出信号的类既不知道也不关心哪个插槽接收信号。Qt的信号槽机制确保,如果将信号连接到槽函数,槽函数将在正确的时间使用信号的参数进行调用。信号槽可以采用任何类型的任意数量的参数。它们是完全类型安全的。

所有继承自QObject或其子类之一(例如,QWidget)的类都可以包含信号槽。当对象状态改变时,它们会发出信号。这就是对象所做的所有通信。它不知道也不关心是否有任何对象正在接收它发出的信号。这是真正的信息封装,并确保对象可以用作软件组件。

槽函数可以用于接收信号,但它们也是正常的成员函数。就像一个对象不知道是否有任何对象接收它的信号一样,一个槽函数也不知道是否有任何信号连接到它。这确保了可以用Qt创建真正独立的组件。

我们可以将任意数量的信号连接到单个槽函数,也可以将信号连接到任意数量的槽函数。甚至可以将一个信号直接连接到另一个信号。(无论何时发出第一个信号,都会立即发出第二个信号。)信号和槽共同构成了强大的组件编程机制。下图是信号槽的连接示例:
信号槽连接示意图

3.3 信号槽要点总结

  • 信号是Public函数,可以在任何地方发射信号,但是推荐只在定义信号的类中发射信号。
  • 根据信号槽连接方式的不同(参见Qt::ConnectionType),槽函数会被立即调用,也可能延迟调用。
  • 几个槽函数连接到一个信号,当信号发射时,这些槽函数将按照连接的顺序依次调用。
  • 信号由moc自动生成,不得在.cpp文件中实现。它们永远不能有返回类型(即使用void)。
  • 信号参数注意事项:经验表明,如果信号和槽函数是无参数的,它们将更易于重用。

本篇介绍了元对象系统及其应用的部分内容,下一篇会继续这个话题,并给出一个反射的应用示例,感谢大家的支持。

以上就是本篇全部内容了,欢迎吐槽评论!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt元对象系统及应用(一) 的相关文章

随机推荐

  • VS CODE 离线插件下载

    VS CODE 离线插件下载 老方法 一 进入VSCODE 插件下载官网 二 搜索需要下载的插件 三 进行地址替换 四 下载 五 在windows环境下安装插件 新方法 一 进入VSCODE 插件下载官网 二 搜索需要下载的插件 三 下载
  • 【原創】checkstyle配置文件说明(checkstyle 3.5)

    属性 说明 basedir 代码所在的位置 AbstractClassName format 定义抽象类的命名规则 PackageName format 定义包名的命名规则 TypeName format 定义类和接口的命名规则 token
  • 警惕!MySQL成数据勒索新目标

    据最新报道显示 继MongoDB和Elasticsearch之后 MySQL成为下个数据勒索目标 从2月12日凌晨开始 已有成百上千个开放在公网的MySQL数据库被劫持 删除了数据库中的存储数据 攻击者留下勒索信息 要求支付比特币以赎回数据
  • Kibana常用命令

    Kibana常用命令 查看集群的健康情况 GET cat health v 查看节点的情况 GET cat nodes v 查询各个索引状态 GET cat indices v 创建索引 PUT movie index 查看某一个索引的分片
  • 9月17日星期二 恒指/美原油/美黄金 走势分析

    财经早餐 2019年09月17日星期二 重点关注的财经数据与事件 09 30 中国70个大中城市住宅销售价格月报 09 30 澳洲联储公布9月货币政策会议纪要 17 00 德国及欧元区9月ZEW经济景气指数 21 15 美国8月工业产出月率
  • idea删除模块后重新创建显示该模块已经被注册

    idea删除模块后重新创建显示该模块已经被注册 原因 注册信息没有删除干净 解决方案 找到gradle xml modules xml workspace xml文件 进一步删除模块信息
  • odoo 打开form 视图 默认为编辑状态

    为了编辑方便 客户会经常要求 odoo 打开form 视图 默认为编辑状态 或者根据某些条件 为编辑状态 下面介绍两种方式进行 1 在form 初始化加载时进行拦截 设置属性打开编辑状态 FormView include 满足条件 form
  • springboot的yaml写法之map、list和map<String,List>

    分两步 设置yaml 注入参数 1 设置yaml 文件名 application yml runcommand firstMapList key11 k1 k2 k3 key22 k1 k2 k3 list lk1 lk2 lk3 maps
  • java 编译时注解框架 lombok-ex

    lombok ex lombok ex 是一款类似于 lombok 的编译时注解框架 编译时注 拥有运行时注解的便利性 和无任何损失的性能 主要补充一些 lombok 没有实现 且自己会用到的常见工具 创作目的 补充 lombok 缺失的注
  • nginx输出php错误日志,Nginx错误日志(error_log)配置及信息详解

    Nginx状态信息 status 配置及信息详解 nginx与php fpm一样内建了一个状态页 对于想了解nginx的状态以及监控nginx非常有帮助 为了后续的zabbix监控 我们需要先了解一下nginx的状态页 Nginx状态信息
  • 【Matplotlib】【Python】如何使用matplotlib颜色映射

    颜色映射 colormap 是一系列颜色 它们从起始颜色渐变到结束颜色 在可视化中 颜色映射用于突出数据的规律 例如 你可能用较浅的颜色来显示较小的值 并使用较深的颜色来显示较大的值 模块pyplot内置了一组颜色映射 要使用这些颜色映射
  • 学习UpdatePanel控件-

    原文可以显示图片 转载 http blog csdn net ILOVEMSDN archive 2007 11 11 1879343 aspx UpdatePanel控件的使用 2008 10 07 05 46 P M ScriptMan
  • JVM 二. 类加载相关

    目录 一 类的加载 二 类的加载器 类加载器的双亲委派机制 一 类的加载 什么是类的加载 我们编写java代码存储为 java结尾的文件 经过编译器编译 将java代码转换为虚拟机指令生成 class结尾的文件 当需要某个类时 虚拟机加载指
  • ZCMU--5155: 小蒜数(C语言)

    题目描述 在所有不大于 n 的正整数中 蒜头君将不是 9 的倍数的所有奇数剔除掉 将是 7 的倍数的所有偶数剔除掉 剩下的数从小到大首尾相接拼起来 组成了一个 小蒜数 请问这个数一共有多少位 输入 输入为整数 n 1 n 1000 测试点编
  • swiper中使用iframe导致无法滑动的3个解决方案

    看到这个标题 很多同学都会疑惑 为什么swiper中要放iframe呢 事实上 当我遇到这个需求前 我也没想到会有这样的骚操作 swiper中嵌入网站 每次滑动切换一个网站 想想听炫酷的 可做起来就不酷了 当你开开心心的把iframe放到每
  • 音频格式RAW和PCM区别和联系

    定义 RAW 在一些外国品牌的播放机中名为 BitSream 我们通常称为 源码 意义是把光盘上的音频格式不加处理地 原汁原味 地从同轴和光纤输出 这就要求用户的功放具备这种音频格式的解码功能 PCM 名为 脉冲调制编码 它的作用是当前的将
  • 多益校招面经--软件开发岗

    多益网络2021校招面经 软件开发岗 笔试通过 专业面试凉凉 第一次面试 太紧张了 很多东西提起来脑子一片空白 现在结束后想了一下都能想明白 以下是面经 1 个人介绍 2 项目介绍 3 开发语言的了解程度 个人是C 4 C 和JAVA的区别
  • 通过接口传递经纬度,并计算距离

    微信小程序调用接口 存储经纬度 PostMapping update location public R updateLocation RequestBody UserQuery userQuery if userService getLo
  • MDK5__配色方案的修改

    一 必要的知识 与MDK主题相关的文件有两个 在X Keil v5 UV4路径下 global propglobal prop def其中global prop def是系统默认的主题配置 如果修改过字体等 系统会生成一个global pr
  • Qt元对象系统及应用(一)

    目录 1 元对象系统 2 元对象与属性系统 2 1 动态属性 3 元对象与信号槽 3 1 信号槽应用场景 3 2 信号槽的连接 3 3 信号槽要点总结 1 元对象系统 元对象系统 Meta Object System 是Qt框架中一个非常重