Qt 是一个用标准 C++ 编写的跨平台开发类库,它对标准 C++ 进行了扩展,引入了元对象系统、信号与槽、属性等特性,使应用程序的开发变得更高效。



本节将介绍 Qt 的这些核心特点,对于理解和编写高效的 Qt C++ 程序是大有帮助的。

Qt 的元对象系统

Qt 的元对象系统(Meta-Object System)提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。



元对象系统由以下三个基础组成:

  1. QObject 类是所有使用元对象系统的类的基类。
  2. 在一个类的 private 部分声明 Q_OBJECT宏,使得类可以使用元对象的特性,如动态属性、信号与槽。
  3. MOC(元对象编译器)为每个 QObject 的子类提供必要的代码来实现元对象系统的特性。

构建项目时,MOC 工具读取 C++ 源文件,当它发现类的定义里有 Q_OBJECT 宏时,它就会为这个类生成另外一个包含有元对象支持代码的 C++ 源文件,这个生成的源文件连同类的实现文件一起被编译和连接。



除了信号与槽机制外,元对象还提供如下一些功能:

  • QObject::metaObject() 函数返回类关联的元对象,元对象类 QMetaObject 包含了访问元对象的一些接口函数,例如 QMetaObject::className() 函数可在运行时返回类的名称字符串。

    QObject *obj = new QPushButton;

    obj->metaObject()->className (); //返回"QPushButton"

  • QMetaObject::newInstance() 函数创建类的一个新的实例。
  • QObject::inherits(const char *className) 函数判断一个对象实例是否是名称为 className 的类或 QObject 的子类的实例。例如:

    QTimer *timer = new QTimer; // QTimer 是 QObject 的子类

    timer->inherits ("QTimer"); // 返回 true

    timer->inherits ("QObject");  // 返回 true

    timer->inherits ("QAbstractButton");//返回 false,不是 QAbstractButton 的子类

  • QObject::tr() 和 QObject::trUtf8() 函数可翻译字符串,用于多语言界面设计,后续章会专门介绍多语言界面设计。
  • QObject::setProperty() 和 QObject::property() 函数用于通过属性名称动态设置和获取属性值。

对于 QObject 及其子类,还可以使用 qobject_cast() 函数进行动态投射(dynamic cast)。例如,假设 QMyWidget 是 QWidget 的子类并且在类定义中声明了 Q_OBJECT 宏。创建实例使用下面的语句:

QObject *obj = new QMyWidget;

变量 obj 定义为 QObject 指针,但它实际指向 QMyWidget 类,所以可以正确投射为 QWidget,即:

QWidget *widget = qobject_cast<QWidget *>(obj);

从 QObject 到 QWidget 的投射是成功的,因为 obj 实际是 QMyWidget 类,是 QWidget 的子类。也可以将其成功投射为 QMyWidget,即:

QMyWidget *myWidget = qobject_cast<QMyWidget *>(obj);

投射为 QMyWidget 是成功的,因为 qobject_cast() 并不区分 Qt 内建的类型和用户自定义类型。但是,若要将 obj 投射为 QLabel 则是失败的,即:

QLabel * label - qobject_cast<QLabel *>(obj);

这样投射是失败的,返回指针 label 为 NULL,因为 QMyWidget 不是 QLabel 的子类。



使用动态投射,使得程序可以在运行时对不同的对象做不同的处理。

属性系统

属性定义

Qt 提供一个 Q_PROPERTY() 宏可以定义属性,它也是基于元对象系统实现的。Qt 的属性系统与 C++ 编译器无关,可以用任何标准的 C++ 编译器编译定义了属性的 Qt C++ 程序。



在 QObject 的子类中,用宏 Q_PROPERTY() 定义属性,其使用格式如下:

Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER meznberName [(READ getFunction | WRITE setFunction)])

    [RESET resetFunction]

    [NOTIFY notifySignal]

    [REVISION int]

    [DESIGNABLE bool]

    [SCRIPTABLE bool]

    [STORED bool]

    [USER bool]

    [CONSTANT]

    [FINAL])

Q_PROPERTY 宏定义一个返回值类型为 type,名称为 name 的属性,用 READ、WRITE
关键字定义属性的读取、写入函数,还有其他的一些关键字定义属性的一些操作特性。属性的类型可以是 QVariant
支持的任何类型,也可以用户自定义类型。



Q_PROPERTY 宏定义属性的一些主要关键字的意义如下:

  • READ 指定一个读取属性值的函数,没有 MEMBER 关键字时必须设置 READ。
  • WRITE 指定一个设定属性值的函数,只读属性没有 WRITE 设置。
  • MEMBER 指定一个成员变量与属性关联,成为可读可写的属性,无需再设置 READ 和 WRITE。
  • RESET 是可选的,用于指定一个设置属性缺省值的函数。
  • NOTIFY 是可选的,用于设置一个信号,当属性值变化时发射此信号。
  • DESIGNABLE 表示属性是否在 Qt Designer 里可见,缺省为 true。
  • CONSTANT 表示属性值是一个常数,对于一个对象实例,READ 指定的函数返回值是常数,但是每个实例的返回值可以不一样。具有 CONSTANT 关键字的属性不能有 WRITE 和 NOTIFY 关键字。
  • FINAL 表示所定义的属性不能被子类重载。

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)

属性的使用

不管是否用 READ 和 WRITE 定义了接口函数,只要知道属性名称,就可以通过 QObject::property() 读取属性值,并通过 QObject::setProperty() 设置属性值。例如:

QPushButton *button = new QPushButton;

QObject *object = button;

object->setProperty("flat", true);

bool isFlat= object->property ("flat");

动态属性

QObject::setProperty() 函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。



动态属性可以使用 QObject::property() 查询,就如在类定义里用 Q_PROPERTY 宏定义的属性一样。



例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的 required 属性,并设置值为“true”,如:

editName->setProperty("required", "true");

comboSex->setProperty("required", "true");

checkAgree->setProperty("required", "true");

然后,可以应用下面的样式定义将这种必填字段的背景颜色设置为亮绿色。

*[required="true"]{background-color:lime}

类的附加信息

属性系统还有一个宏 Q_CLASSINFO(),可以为类的元对象定义“名称——值”信息,如:

class QMyClass:public QObject {
Q_OBJECT
Q_CLASSINFO("author", "Wang")
Q_CLASSINFO ("company", "UPC")
Q_CLASSINFO("version ", "3.0.1")
public:
...
};

用 Q_CLASSINFO() 宏定义附加类信息后,可以通过元对象的一些函数获取类的附加信息,如 classlnfo(int) 获取某个附加信息,函数原型定义如下:

QMetaClassInfo QMetaObject::classInfo(int index) const

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

http://m.biancheng.net/view/1826.html

Qt元对象和属性系统详解的更多相关文章

  1. Qt——元对象和属性机制

    http://www.cnblogs.com/hellovenus/p/5582521.html 一.元对象 元对象(meta object)意思是描述另一个对象结构的对象,比如获得一个对象有多少成员 ...

  2. Qt 元对象系统(Meta-Object System)(不管是否使用信号槽,都推荐使用)

    Qt 元对象系统(Meta-Object System) Qt的元对象系统基于如下三件事情: 类:QObject,为所有需要利用原对象系统的对象提供了一个基类. 宏:Q_OBJECT,通常可以声明在类 ...

  3. 007-Scala类的属性和对象私有字段实战详解

    007-Scala类的属性和对象私有字段实战详解 Scala类的使用实战 变量里的类必须赋初值 def函数时如果没参数可不带括号 2.不需要加Public声明 getter与setter实战 gett ...

  4. Dream------scala--类的属性和对象私有字段实战详解

    Scala类的属性和对象私有字段实战详解 一.类的属性 scala类的属性跟java有比较大的不同,需要注意的是对象的私有(private)字段 1.私有字段:字段必须初始化(当然即使不是私有字段也要 ...

  5. C++框架_之Qt的信号和槽的详解

    C++_之Qt的信号和槽的详解 1.概述 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal ...

  6. 搭建zabbix监控系统详解

    搭建zabbix监控系统详解 文:warren   博文大纲:一.前言 二.zabbix监控架构三.搭建Zabbix监控服务器四.搭建过程中遇到有些服务无法正常启动的解决办法 一.前言 : 要想实时的 ...

  7. java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET

    java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET 亲,“社区之星”已经一周岁了!      社区福利快来领取免费参加MDCC大会机会哦    Tag功能介绍—我们 ...

  8. Qt零基础教程(四)QWidget详解(3):QWidget的几何结构

    Qt零基础教程(四)  QWidget详解(3):QWidget的几何结构 这篇文章里面分析了QWidget中常用的几种几何结构 下图是Qt提供的分析QWidget几何结构的一幅图,在帮助的 Wind ...

  9. js原生之scrollTop、offsetHeight和offsetTop等属性用法详解

    scrollTop.offsetHeight和offsetTop等属性用法详解:标题中的几个相关相关属性在网页中有这大量的应用,尤其是在运动框架中,但是由于有些属性相互之间的概念比较混杂或者浏览器兼容 ...

随机推荐

  1. Pandas高级教程之:自定义选项

    目录 简介 常用选项 get/set 选项 经常使用的选项 最大展示行数 超出数据展示 最大列的宽度 显示精度 零转换的门槛 列头的对齐方向 简介 pandas有一个option系统可以控制panda ...

  2. Day10 类与对象-面向对象编程(1)

    面向对象编程(OOP) 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据. 抽象 三大特征: 封装 继承 多态 从认识论角度考虑是先有对象后有类.对象,是具体的事物.类,是抽象的, ...

  3. DIV+css排版问题技巧总结---v客学院技术分享

                DIV+css排版问题技巧总结 一.排版思路 1.从上到下,从左到右,从大到小. 2.首先确定排版分区,排除色块分布,然后再从简单的部分开始. 3.在某一块内将HTML部分写好 ...

  4. debian 9 pycharm安装

    官网下载PyCharm的tar.gz格式 使用命令进行解压:tar -xvzf pycharm.tar.gz 解压后将pycharm文件夹移动到/usr/local/lib/目录下 进入pycharm ...

  5. (python函数03)zip()函数

    (python函数03)zip()函数 zip是用来压缩的,它接受一系列可迭代的对象作为参数,将对象中对应的元素打包成一个个元组(tuple),然后返回有这些tuples组成的对象,可强制转化为列表和 ...

  6. vue源码阅读笔记

    1.yarn test [文件名]  -t [name-of-spec(describe or test )] 直接运行yarn test,会测试所有测试文件:yarn test 后面只跟文件名的话会 ...

  7. videojs文档翻译-Player(v6.0.0-RC.2)

    Player 当使用任何Video.js设置方法初始化视频时,将创建Player类的实例. 创建实例后,可以通过两种方式在全局访问: 调用videojs('example_video_1');直接通过 ...

  8. Java中9种常见的CMS GC问题分析与解决

    1. 写在前面 | 本文主要针对 Hotspot VM 中"CMS + ParNew"组合的一些使用场景进行总结.重点通过部分源码对根因进行分析以及对排查方法进行总结,排查过程会省 ...

  9. python编写DDoS攻击脚本

    python编写DDoS攻击脚本 一.什么是DDoS攻击 DDoS攻击就是分布式的拒绝服务攻击,DDoS攻击手段是在传统的DoS攻击基础之上产生的一类攻击方式.单一的DoS攻击一般是采用一对一方式的, ...

  10. CVPR2021 | Transformer用于End-to-End视频实例分割

    ​ 论文:End-to-End Video Instance Segmentation with Transformers 获取:在CV技术指南后台回复关键字"0005"获取该论文 ...