Qt6 C++ 开发指南学习记录三
三、Qt框架功能概述
3.1 Qt6框架中的模块
Qt
框架中的模块分为以下两大类:
- Qt Essentials:Qt框架的基础模块,这些模块提供了Qt在所有平台上的基本功能。在安装Qt时,这些基础模块是自动安装的,无须选择。
- Qt Addons:Qt框架的附加模块,这些是实现一些特定功能的模块。
3.1.1 Qt基础模块
Qt
框架的基础模块提供了Qt
在所有平台上的基本功能,它们在所有开发平台上都可用,在Qt 6
所有版本上源代码和二进制代码是兼容的。
Qt框架的基础模块
模块 | 功能 |
---|---|
Qt Core | 这个模块是Qt框架的核心,定义了元对象系统对标准C++进行扩展 |
Qt GUI | 提供用于GUI设计的一些基础类,可用于窗口系统集成、事件处理、字体和文字处理等 |
Qt Network | 提供实现TCP/IP网络通信的一些类 |
Qt Widgets | 提供用于创建GUI的各种界面组件类 |
Qt D-Bus | D-Bus是实现进程间通信(Inter process communication,IPC)和远程过程调用(remote procedure call,RPC)的一种通信协议,这个模块提供实现D-Bus通信协议的一些类 |
Qt Test | 提供一些对应用程序和库进行单元测试的类 |
Qt QML | 提供用QML编程的框架,它定义了QML和基础引擎 |
Qt Quick | 这个模块是用于开发QML应用程序的标准库,提供创建UI的一些基本类型 |
Qt Quick Controls | 提供一套基于Qt Quick的控件,可用于创建复杂的UI |
Qt Quick Dialogs | 提供通过QML使用系统对话框的功能 |
Qt Quick Layouts | 提供用于管理界面布局的QML类型 |
Qt Quick Test | 提供QML应用程序的单元测试框架 |
3.1.2 Qt附加模块
Qt
附加模块是一些能够实现特定功能的模块,用户安装Qt
时可以选择性地安装这些附加模块。
模块 | 功能 |
---|---|
Active Qt | 用于开发使用ActiveX和COM控件的Windows应用程序 |
Qt 3D | 支持二维和三维图形渲染,用于开发近实时的仿真系统 |
Qt 5 Core Compatiblity | 提供一些Qt 5中有而Qt 6中没有的API,这是为了兼容Qt 5 |
Qt Bluetooth | 提供访问蓝牙硬件的功能 |
Qt Charts | 提供用于数据显示的一些二维图表组件 |
Qt Concurrent | 提供一些类,使我们无须使用底层的线程控制就可以编写多线程应用程序 |
Qt Data Visualization | 提供用于三维数据可视化显示的一些类 |
Qt Help | 提供一些在应用程序中集成帮助文档的类 |
Qt Image Formats | 支持附加图片格式的插件,格式包括TIFF、MNG和TGA等 |
Qt Multimedia | 提供处理多媒体内容的一些类,处理方式包括播放音频和视频,通过麦克风和摄像头录制音频和视频 |
Qt Network Authorization | 使Qt应用程序能访问在线账号或HTTP服务,而又不暴露用户密码 |
Qt NFC | 提供访问近场通信(near field communication,NFC)硬件的功能 |
Qt OpenGL | 提供一些便于在应用程序中使用OpenGL的类 |
Qt Positioning | 通过GPS或WiFi定位,为应用程序提供定位信息 |
Qt Print Support | 提供一些用于打印控制的类 |
Qt Remote Objects | 提供一种进程间通信技术,可以在进程间或计算机之间方便地交换信息 |
Qt SCXML | 用于通过SCXML(有限状态机规范)文件创建状态机 |
Qt Sensors | 提供访问传感器硬件的功能,传感器包括加速度计、陀螺仪等 |
Qt Serial Bus | 提供访问串行工业总线(如CAN和Modbus总线)的功能 |
Qt Serial Port | 提供访问兼容RS232引脚的串行接口的功能 |
Qt Shader Tools | 提供用于三维图形着色的工具 |
Qt SQL | 提供一些使用SQL操作数据库的类 |
Qt SVG | 提供显示SVG图片文件的类 |
Qt UI Tools | 提供一些类,可以在程序运行时加载用Qt Designer设计的UI文件以动态创建UI |
Qt Virtual Keyboard | 实现不同输入法的虚拟键盘 |
Qt Wayland Compositor | 实现了Wayland协议,能创建用户定制的显示服务 |
Qt WebChannel | 用于实现服务器端(QML或C++应用程序)与客户端(HTML/JavaScript或QML应用程序)进行P2P通信 |
Qt WebEngine | 提供一些类和函数,通过Chromium浏览器项目实现在应用程序中嵌入显示动态网页 |
Qt WebSockets | 提供WebSocket通信功能。WebSocket是一种Web通信协议,可实现客户端程序与远程主机的双向通信 |
3.2 Qt全局定义
头文件<QtGlobal>
包含Qt
框架中的一些全局定义,包括基本数据类型、函数和宏。一般的Qt
类的头文件都会包含这个头文件,所以用户程序中无须包含这个头文件就可以使用其中的定义。
3.2.1 数据类型定义
Qt
为各种常见数据类型定义了类型符号,确保在各个平台各种基本数据类型都具有统一确定的长度。
<QtGlobal>
中定义的数据类型
Qt数据类型 | POSIX标准等效定义 | 字节数 |
---|---|---|
qint8 | signed char | 1 |
qint16 | signed short | 2 |
qint32 | signed int | 4 |
qint64 | long long int | 8 |
qlonglong | long long int | 8 |
quint8 | unsigned char | 1 |
quint16 | unsigned short | 2 |
quint32 | unsigned int | 4 |
quint64 | unsigned long long int | 8 |
qulonglong | unsigned long long int | 8 |
uchar | unsigned char | 1 |
ushort | unsigned short | 2 |
uint | unsigned int | 4 |
ulong | unsigned long | 8 |
qreal | double | 8 |
qsizetype | ssize_t | 8 |
qfloat16 | – | 2 |
qreal
默认表示8
字节double
类型的浮点数,如果Qt
使用-qreal float
选项进行配置,就表示4
字节float
类型的浮点数。
qfloat16
是Qt 5.9
中增加的一种类型,用于表示16
位的浮点数qfloat16
不是在头文件<QtGlobal>
中定义的,要使用qfloat16
,需要包含头文件<QFloat16>
。
qsizetype
是在Qt 5.10
中增加的一种类型,等效于POSIX
标准中的ssize_t
,表示有符号整数。
3.2.2 函数
头文件<QtGlobal>
中包含一些常用函数的定义,这些函数多以模板类型作为输入和输出参数类型。若存在double
和float
两种类型参数的overload
型函数,只列出double
类型参数的函数。
<QtGlobal>
中的全局函数定义:
函数原型 | 功能 |
---|---|
T qAbs(const T &value) | 返回变量value的绝对值 |
const T &qBound(const T &min, const T &value, const T &max) | 返回value限定在min~max的值 |
T qExchange(T &obj, U &&newValue) | 将obj的值用newValue替换,返回obj的旧值 |
int qFpClassify(double val) | 返回val的分类,包括FP_NAN(非数)、FP_INFINITE(正或负的无穷大)、FP_ZERO(零)等几种类型 |
bool qFuzzyCompare(double p1, double p2) | 若p1和p2近似相等,返回true |
bool qFuzzyIsNull(double d) | 若参数d约等于0,返回true |
double qInf() | 返回无穷大的数 |
bool qIsFinite(double d) | 若d是一个有限的数,返回true |
bool qIsInf(double d) | 若d是一个无穷大的数,返回true |
bool qIsNaN(double d) | 若d为非数,返回true |
const T &qMax(const T &value1, const T &value2) | 返回value1和value2中的较大值 |
const T &qMin(const T &value1, const T &value2) | 返回value1和value2中的较小值 |
qint64 qRound64(double value) | 将value近似为最接近的qint64类型整数 |
int qRound(double value) | 将value近似为最接近的int类型整数 |
一些基础的数学运算函数在<QtMath>
头文件中定义,这些函数,如三角运算函数、弧度与角度的转换函数等。
3.2.3 宏定义
<QtGlobal>
头文件中定义了很多宏:
- QT_VERSION表示Qt版本。这个宏展开为数值形式0xMMNNPP。例如Qt版本为Qt 6.2.3, 则QT_VERSION为0x060203。
- Q_BYTE_ORDER表示系统内存中数据的字节序。Q_BIG_ENDIAN表示大端字节序,Q_LITTLE_ENDIAN表示小端字节序。在需要判断系统字节序时可以用到这几个宏,例如:
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
...
#endif
- Q_DECL_IMPORT和Q_DECL_EXPORT分别用于在使用或设计共享库时导入或导出库的内容。
- Q_UNUSED(name)用于声明函数中未被使用的参数。当函数的输入参数在函数对应的代码里未被使用时,需要用这个宏声明,否则会出现编译警告。
- foreach(variable, container)用于遍历容器的内容。
- qDebug(const char *message, …)用于在debugger窗口显示信息。在Qt Creator中,debugger窗口就是Application Output窗口。qDebug()输出数据的格式与C语言的printf()函数的类似,可以格式化输出各种数据。qDebug()一般用于调试程序时显示一些中间信息。
3.3 Qt的元对象系统
Qt
中引入了元对象系统对标准C++
语言进行扩展,增加了信号与槽、属性系统、动态翻译等特性,为编写GUI
应用程序提供了极大的方便。
3.3.1 元对象系统概述
Qt
的元对象系统的功能建立在以下三个方面:
- QObject类是所有使用元对象系统的类的基类。
- 必须在一个类的开头部分插入宏Q_OBJECT,这样这个类才可以使用元对象系统的特性。
- MOC为每个QObject的子类提供必要的代码来实现元对象系统的特性。
构建项目时,MOC
会读取C++
源文件,当它发现类的定义里有Q_OBJECT
宏时,它就会为这个类生成另一个包含元对象支持代码的C++
源文件,这个生成的源文件连同类的实现文件一起被标准C++
编译器编译和连接。
1、QObject类
QObject
类是所有使用元对象系统的类的基类,也就是说,如果一个类的父类或上层父类是QObject
,它就可以使用信号与槽、属性等特性。
QObject
类与元对象系统特性相关的函数:
特性 | 函数 | 功能 |
---|---|---|
元对象 | QMetaObject *metaObject() | 返回这个对象的元对象 |
元对象 | QMetaObject staticMetaObject | 这是类的静态变量,不是函数,存储了类的元对象 |
类型信息 | bool inherits() | 判断这个对象是不是某个类的子类的实例 |
动态翻译 | QString tr() | 类的静态函数,返回一个字符串的翻译版本 |
对象树 | QObjectList &children() | 返回子对象列表 |
对象树 | QObject *parent() | 返回父对象指针 |
对象树 | void setParent() | 设置父对象 |
对象树 | T findChild() | 按照对象名称,查找可被转换为类型T的子对象 |
对象树 | QList findChildren() | 返回符合名称和类型条件的子对象列表 |
信号与槽 | QMetaObject::Connection connect() | 设置信号与槽关联 |
信号与槽 | bool disconnect() | 解除信号与槽的关联 |
信号与槽 | bool blockSignals() | 设置是否阻止对象发射任何信号 |
信号与槽 | bool signalsBlocked() | 若返回值为 true,表示对象被阻止发射信号 |
属性系统 | QList dynamicPropertyNames() | 返回所有动态属性名称 |
属性系统 | bool setProperty() | 设置属性值,或添加动态属性 |
属性系统 | QVariant property() | 返回属性值 |
元对象系统的特性是通过QObject
的一些函数实现的:
- 元对象(meta object)。每个QObject及其子类的实例都有一个元对象,这个元对象是自动创建的。静态变量staticMetaObject就是这个元对象,函数metaObject()返回这个元对象指针。
// 获取一个对象的元对象有两种方式
QPushButton *btn= new QPushButton();
const QMetaObject *metaPtr= btn->metaObject(); //获取元对象指针
const QMetaObject metaObj= btn->staticMetaObject; //获取元对象
- 类型信息。QObject的inherits()函数可以判断对象是不是从某个类继承的类的实例。
- 动态翻译。函数tr()用于返回一个字符串的翻译版本,在设计多语言界面的应用程序时需要用到tr()函数。
- 对象树(object tree)。对象树指的是表示对象间从属关系的树状结构。QObject类的parent()函数返回其父对象,children()函数返回其子对象,findChildren()函数可以返回某些子对象或所有子对象。窗口和窗口上的组件就构成对象树,窗口可以访问任何一个界面组件。对象树中的某个对象被删除时,它的子对象会被自动删除,所以,一个窗口被删除时,它上面的所有界面组件也会被自动删除。
- 信号与槽。通过在一个类的定义中插入宏Q_OBJECT,我们就可以使用Qt扩展的C++语言特性编程。
- 属性系统。在类的定义代码中可以用宏Q_PROPERTY定义属性,QObject的setProperty()函数会设置属性的值或定义动态属性;property()函数会返回属性的值。
2、QMetaObject类
每个QObject
及其子类的实例都有一个自动创建的元对象,元对象是QMetaObject
类型的实例。元对象存储了类的实例所属类的各种元数据,包括类信息元数据、方法元数据、属性元数据等,所以,元对象实质上是对类的描述。
QMetaObject
类的主要接口函数:
分组 | 函数原型 | 功能 |
---|---|---|
类的信息 | char *className() | 返回这个类的类名称 |
类的信息 | QMetaType metaType() | 返回这个元对象的元类型 |
类的信息 | QMetaObject *superClass() | 返回这个类的上层父类的元对象 |
类的信息 | bool inherits(QMetaObject *metaObject) | 返回true表示这个类继承自metaObject描述的类,否则返回false |
类的信息 | QObject newInstance(***) | 创建这个类的一个实例,可以给构造函数传递最多10个参数 |
类信息元数据 | QMetaClassInfo classInfo(int index) | 返回序号为index的一条类信息的元数据,类信息是在类中用宏Q_CLASSINFO定义的一条信息 |
类信息元数据 | int indexOfClassInfo(char *name) | 返回名称为name的类信息的序号,序号可用于classInfo()函数 |
类信息元数据 | int classInfoCount() | 返回这个类的类信息条数 |
类信息元数据 | int classInfoOffset() | 返回这个类的第一条类信息的序号 |
构造函数元数据 | int constructorCount() | 返回这个类的构造函数的个数 |
构造函数元数据 | QMetaMethod constructor(int index) | 返回这个类的序号为index的构造函数的元数据 |
方法元数据 | int indexOfConstructor(char *constructor) | 返回一个构造函数的序号,constructor包括正则化之后的函数名和参数名 |
方法元数据 | QMetaMethod method(int index) | 返回序号为index的方法的元数据 |
方法元数据 | int methodCount() | 返回这个类的方法的个数,包括基类中定义的方法,方法包括一般的成员函数,还包括信号和槽 |
方法元数据 | int methodOffset() | 返回这个类的第一个方法的序号 |
方法元数据 | int indexOfMethod(char *method) | 返回名称为method的方法的序号 |
枚举类型元数据 | QMetaEnum enumerator(int index) | 返回序号为index的枚举类型的元数据 |
枚举类型元数据 | int enumeratorCount() | 返回这个类的枚举类型个数 |
枚举类型元数据 | int enumeratorOffset() | 返回这个类的第一个枚举类型的序号 |
枚举类型元数据 | int indexOfEnumerator(char *name) | 返回名称为name的枚举类型的序号 |
属性元数据 | QMetaProperty property(int index) | 返回序号为index的属性的元数据 |
属性元数据 | int propertyCount() | 返回这个类的属性的个数 |
属性元数据 | int propertyOffset() | 返回这个类的第一个属性的序号 |
属性元数据 | int indexOfProperty(char *name) | 返回名称为name的属性的序号 |
信号与槽 | int indexOfSignal(char *signal) | 返回名称为signal的信号的序号 |
信号与槽 | int indexOfSlot(char *slot) | 返回名称为slot的槽函数的序号 |
静态函数 | bool checkConnectArgs(****) | 检查信号与槽函数的参数是否兼容 |
静态函数 | void connectSlotsByName(QObject *object) | 迭代搜索object的所有子对象,将匹配的信号和槽连接起来 |
静态函数 | bool invokeMethod(****) | 运行QObject对象的某个方法,包括信号、槽或成员函数 |
静态函数 | QByteArray normalizedSignature(char *method) | 将方法method的名称和参数字符串正则化,去除多余空格。函数返回的结果可用于 checkConnectArgs()、indexOfConstructor()等函数 |
通过QMetaObject
类的这些函数,我们可以在运行时获取一个QObject
对象的类信息和各种元数据。类的元数据又分为多种类型,且有专门的类来描述。
3.3.2 运行时类型信息
通过使用QObject
和QMetaObject
提供的以下一些接口函数,我们可以在运行时获得一个对象的类名称以及其父类的名称,判断其是否从某个类继承而来。要实现这些功能,我们并不需要C++
编译器的运行时类型信息(run-time type information
,RTTI
)支持。
- 函数 QMetaObject::className()。
// 函数可在运行时返回类名称的字符串
QPushButton *btn= new QPushButton();
const QMetaObject *meta= btn->metaObject(); //获取对象的元对象指针
QString str= QString(meta->className()); //str= "QPushButton"
- 函数QObject::inherits()。
// 函数可以判断一个对象是不是继承自某个类的实例,顶层的父类是QObject。
QPushButton *btn= new QPushButton();
bool result= btn->inherits("QPushButton"); //true
result= btn->inherits("QObject"); //true
result= btn->inherits("QWidget"); //true
result= btn->inherits("QCheckBox"); //false
如果一个类是多重继承的,其中一个父类是QObject
,那么inherits("QObject")
会返回true
。
3. 函数QMetaObject::superClass()。
// 函数返回该元对象所描述类的父类的元对象,通过父类的元对象可以获取父类的一些元数据
QPushButton *btn= new QPushButton();
const QMetaObject *meta= btn->metaObject();
QString str1= QString(meta->className()); //str1="QPushButton"
const QMetaObject *metaSuper= btn->metaObject()->superClass();
QString str2= QString(metaSuper->className()); //str2="QAbstractButton"
- 函数qobject_cast()。
// 个函数是头文件<QObject>中定义的一个非成员函数,对于QObject及其子类的对象,可以使用函数qobject_cast()进行动态类型转换。
// 如果自定义的类要支持函数qobject_cast(),那么自定义的类需要直接或间接继承自QObject,且在类定义中插入宏Q_OBJECT。
QObject *btn