本文最后更新于 2025-02-20,学习久了要注意休息哟

第一章 QT入门

1.1 什么是QT

不论我们学习什么样的知识点首先第一步都需要搞明白它是什么,这样才能明确当前学习的方向是否正确,下面给大家介绍一下什么是Qt。

是一个跨平台的C++应用程序开发框架

  • 具有短平快的优秀特质: 投资少、周期短、见效快、效益高

  • 几乎支持所有的平台, 可用于桌面程序开发以及嵌入式开发

  • 有属于自己的事件处理机制

  • 可以搞效率的开发基于窗口的应用程序。

Qt是标准 C++ 的扩展, C++的语法在Qt中都是支持的

  • 良好封装机制使得 Qt 的模块化程度非常高,可重用性较好,可以快速上手。
  • Qt 提供了一种称为 signals/slots 的安全类型来替代 callback(回调函数),这使得各个元件 之间的协同工作变得十分简单。

1.2 Qt 的优势

简洁、跨平台、强大的图形界面开发框架

1.2.1 跨平台能力

  • 一次开发,多平台运行:支持 Windows、Linux、Mac,无需为不同系统重复编写代码。
  • 对比传统框架:MFC/C# 仅适用于 Windows,移植到其他平台成本高。

1.2.2 业界广泛应用

  • 知名软件案例
    • Google Earth:高精度虚拟地球软件。
    • Wireshark:网络抓包分析工具,助力开发者调试。
    • VirtualBox:开源虚拟机(对标收费的 VMWare)。
    • VLC:轻量开源多媒体播放器。
    • WPS Office:兼容微软 Office 的国产办公套件。
    • YY 语音:国内主流游戏语音通讯平台。

1.2.3 代码结构清晰

  • 代码分离设计:系统生成代码与用户代码完全隔离,避免混乱(如删除控件后无需手动修复代码)。
  • 对比 MFC:混合代码导致维护困难。

1.2.4 界面美观易定制

  • QSS 样式表:类似 Web 的 CSS,轻松调整控件外观(颜色、字体、布局等)。
  • 效果:可设计现代化、高颜值的用户界面。

1.2.5 2D/3D 图形支持

  • 图形渲染能力:内置 OpenGL 支持,适合开发三维应用、游戏或可视化工具。

智慧生产大屏

汽车界面

1.2.6 丰富资源与开发友好

  • API 数量:250+ 类库,覆盖文件、网络、数据库等模块。
  • 文档完善:官方提供详细说明和示例代码,降低学习门槛。

1.2.3 嵌入式开发首选

  • 嵌入式 Linux:Qt 是嵌入式设备界面开发的最佳选择(适配华清远见、正点原子、野火等开发板)。

1.2.4 学习必要性

  • C++ 开发者的刚需
    • 快速开发测试工具界面(如调试工具、数据可视化界面)。
    • 即使主攻后台开发,界面能力仍为职场加分项。

Qt = 跨平台 + 高颜值 + 易维护 + 全领域覆盖(桌面/嵌入式/3D)。

1.3 为什么学习QT?

  • Qt 是一个跨平台的 C++ 图形用户界面应用程序框架
  • Qt 为应用程序开发者提供建立艺术级图形界面所需的所有功能
  • Qt 是完全面向对象的,很容易扩展,并且允许真正的组件编程

1.4 QT的发展史

1991年
    Qt 最早由奇趣科技(TrollTech)开发
1996年
    进入商业领域
    它也是目前流行的 Linux 桌面环境 KDE 的基础
2008年
    奇趣科技被诺基亚公司收购
    Qt 成为诺基亚旗下的编程语言
2012年
    Qt 又被 Digia 公司收购
2014年4月
    跨平台的集成开发环境 Qt Creator 3.1.0 发布
    同年 5 月 20 日配发了 Qt5.3 正式版
    至此 Qt 实现了对 iOS、Android、WP 等各平台的全面支持
2020年
    Qt 团队宣布 6.0 版本发布
当前
    当前Qt 最新版本为 Qt 6.3

1.5 QT模块

Qt类库里大量的类根据功能分为各种模块,这些模块又分为以下几大类:

  • Qt 基本模块(Qt Essentials):提供了 Qt 在所有平台上的基本功能。

  • Qt 附加模块(Qt Add-Ons):实现一些特定功能的提供附加价值的模块。

  • 增值模块(Value-AddModules):单独发布的提供额外价值的模块或工具。

  • 技术预览模块(Technology Preview Modules):一些处于开发阶段,但是可以作为技术预览使用的模块。

  • Qt 工具(Qt Tools):帮助应用程序开发的一些工具。

Qt官网或者帮助文档的“All Modules”页面可以查看所有这些模块的信息。以下是官方对Qt基本模块的描述。关于其他模块感兴趣的话可以自行查阅。

于其他模块感兴趣的话可以自行查阅。

QT模块描述

| 模块 | 描述 |
| ——————— | ————————————————– |
| Qt Core | Qt 类库的核心,所有其他模块都依赖于此模块 |
| Qt GUI | 设计 GUI 界面的基础类,包括 OpenGL |
| Qt Multimedia | 音频、视频、摄像头和广播功能的类 |
| Qt Multimedia Widgets | 实现多媒体功能的界面组件类 |
| Qt Network | 使网络编程更简单和轻便的类 |
| Qt QML | 用于 QML 和 JavaScript 语言的类 |
| Qt Quick | 用于构建具有定制用户界面的动态应用程序的声明框架 |
| Qt Quick Controls | 创建桌面样式用户界面,基于 Qt Quick 的用户界面控件 |
| Qt Quick Dialogs | 用于 Qt Quick 的系统对话框类型 |
| Qt Quick Layouts | 用于 Qt Quick 2 界面元素的布局项 |
| Qt SQL | 使用 SQL 用于数据库操作的类 |
| Qt Test | 用于应用程序和库进行单元测试的类 |
| Qt Widgets | 用于构建 GUI 界面的 C++ 图形组件类 |

第二章 QT初体验

2.1 搭建Qt开发环境

2.1.1 QT 的版本

1、QT4

  • 奠定了 Qt 跨平台开发的基础。
  • 支持 Windows、Linux、Mac 等主流操作系统。
  • 引入了信号与槽机制,简化了事件处理。

2、QT5

  • 全面支持 C++11 标准,代码更现代化。
  • 引入 QML 和 Qt Quick,支持声明式 UI 开发,适合移动端和嵌入式设备。
  • 增强了对 OpenGL 的支持,图形渲染性能大幅提升。
  • 模块化设计,开发者可按需选择功能模块。

3、QT6

  • 基于 C++17 标准,性能更优,代码更简洁。
  • 进一步优化 QML 和 Qt Quick,提升 UI 开发效率。
  • 增强了对 3D 图形和高分辨率屏幕的支持。
  • 改进了模块化设计,减少依赖,提升编译速度。

2.1.1 软件获取

1、离线安装包

在我们学习Qt之前必须要安装开发环境,本小节基于Qt自带的集成开发环境(IDE)为大家讲解一下响应的开发步骤。

在这里我们基于Window平台 Qt 5.14.2 给大家讲解如何进行安装和相关配置。

5.14

Qt官方下载地址:https://download.qt.io/archive/qt/

通过网址可以打开QT官方的下载页面,如下:

QT官方页面

注:不用过分的去追求高版本 qt在 5.15 以上的版本已经不直接给安装包了 需要自己对源码进行编译,或者使用在线安装

我们给大家的资料包是 5.9.9 和 5.14.2,如果大家还是使用 5.9.9 或者 5.14.2版本 则可以不用去官网下载,通过我给大家的资料包即可。

QT软件下载

2、在线安装包

在线安装需要去下载一个下载器

下载在线安装器:https://download.qt.io/archive/online_installers/4.3/

image-20250211215553539

登录 Qt 账户

如果没有 Qt 账户,点击 【注册】按钮,根据提示,注册一个即可

2.1.2 离线安装

QT的安装方式分为两种 离线安装 以及 在线安装

离线安装

​ 当我们需要安装的是 5.14 以内的版本 需要使用离线安装 自己下载官方提供的安装包。

在线安装

​ 当我们需要安装5.15的版本时,就需要使用在线安装的方式了,在线安装需要先下载一个安装器,有点类似于 visual studio 的安装。

注:在进行安装前 如果你不想注册 则需要先进行断网

双击安装包 ,开始进行安装

QT安装_1

选择安装路径, 需要注意的是,路径内部不能有中文

下面的勾选是问你是否需要安装qt自带的IDE工具,这里我们一定要勾选上

QT安装_2

选择编译工具,以及模块等内容

QT安装_3

首先是选择编译套件

QT安装_4.png

选择编译工具,如果电脑空间足够 ,可以全选,如果空间不够,请看下面的分析

这里我们推荐使用 ==Ming W5.3.0 32bit==

  • MSVC2015 64-bit: Visual Studio 2015 使用的64位编译套件

  • MSVC2017 32-bit: Visual Studio 2017 使用的32位编译套件

  • MSVC2017 64-bit: Visual Studio 2017 使用的64位编译套件

  • MinGW7.3.0 32-bit: QtCreator 使用的32位编译套件

  • MinGW7.3.0 64-bit: QtCreator 使用的64位编译套件

  • UWP –> Universal Windows Platform: 用于window平台应用程序开发的编译套件

[!NOTE]

UWP 即Windows通用应用平台,在Windows 10 Mobile/Surface(Windows平板电脑)/ PC/Xbox/HoloLens(眼镜)等平台上运行,uwp不同于传统pc上的exe应用,也跟只适用于手机端的app有本质区别。它并不是为某一个终端而设计,而是可以在所有Windows10设备上运行。

关于套件

在这个窗口中除了选择必要的编译套件,还有一些非必要组件,常用的有以下两个:

| 内容 | 解释 |
| ———————— | ———————————————————— |
| Android x86 | 适用于 x86 架构的 Android 平台相关内容。 |
| Android ARMv7 | 适用于 ARMv7 架构的 Android 平台相关内容。 |
| Sources | C++源码 |
| Qt Charts | Qt 中的第三方模块,主要用于绘制各种图表,如折线图、柱状图等。 |
| Qt Data Visualization | Qt 中用于数据可视化的模块,三维柱状图等。 |
| Qt Purchasing | 提供了应用内购买的功能 |
| Qt Virtual Keyboard | Qt 中的虚拟键盘模块,用于在特定场景下提供虚拟键盘输入功能。 |
| Qt WebEngine | Qt 提供的 Web 浏览器引擎,可用于在应用中嵌入网页浏览功能。 |
| Qt Network Authorization | 与网络授权相关的模块,用于处理网络访问的授权问题。 |
| Qt Remote Objects (TP) | Qt 远程对象模块,可能用于实现不同设备之间的对象通信。 |
| Qt Speech (TP) | Qt 语音模块,可能用于语音相关的功能开发。 |
| Qt Script (Deprecated) | Qt 脚本模块,已过时,曾经可能用于在 Qt 应用中执行脚本。 |

  • Source: Qt源码, 另外Qt的一些模块运行需要的驱动没有提供现成的动态库需要自己编译, 建议安装==(占用空间较大)==

  • Qt Charts: 用于绘制统计数据对应的图表, 比如: 折线图/曲线图等

同意许可证开源协议

QT安装_5

等待安装完成

QT安装_6

2.1.3 在线安装

下载在线安装器:https://download.qt.io/archive/online_installers/4.3/

1、登陆QT账户

如果没有 Qt 账户,点击 【注册】按钮,根据提示,注册一个即可

image-20250211220712313

2、开源义务

同意协议,并勾选个人用户,否则需要输入公司/企业名称

image-20250211220915296

3、禁用信息收集

通常直接选择第二项,禁止向 Qt 官方发送统计信息

image-20250211221018346

4、设定安装路径

选择安装文件夹,并选择【Custom installation】自定义安装

image-20250211221125193

5、选择安装组件

image-20250211221828649

关于组件的说明

- Archive
    All Supported Release
    所有的 Qt 发布版本

- Latest releases
    Latest Supported release
    最新的正式发布版

- Preview
    Latest unofficial release previews, including snapshots, alpha, beta, and RC release
    预览版,包括 alpha 预览版,beta 测试版,RC(Release Candidate)发行候选版

- LTS
    Latest Long-Term Support Releases
    长期支持版本

编译器

- MSVC
    MSVC 编译器(Microsoft Visual C++),是微软提供的 VC 编译器
    需要 Visual Studio 环境的支持
- MinGW
    MinGW 编译器(Minimalist GNU for Windows),也就是 GCC 编译器
    它只不过在 Windows 下作了封装而已,这个版本不需要 VS 环境的支持,可以独立生成 Windows 平台的应用程序。

其他选项

- Android
    可用于 android 的开发。
    不过 android 的开发,通常直接使用谷歌的集成开发环境 Android Studio,使用 kotlin 语言进行开发
    以前使用 Java 开发 android 程序

- Source
  Qt 的源码,如果有需要查看源码的需求,可以将这个勾选,不过会多占用至少 3GB 的磁盘控件

- Qt charts 等
  这些时 Qt 一些高级的开发组件,比如 charts 进行图表的开发,WebEngine 进行 Web 相关的开发

6、许可协议

当然需要同意,否则无法下一步

image-20250211222108246

7、等待安装

image-20250211222219815

8、增加组件

点击系统左下角的【开始】菜单,找到【Qt】,然后选择【Qt Maintenance Tool】或者【Uninstall Qt

2.1.4 环境变量设置

如果可以使用则不需要进行这一步的配置

当我们编写一个Qt程序,并且生成了可执行程序,这个可执行程序运行的时候默认需要加载相关的Qt动态库(因为默认是动态链接,静态链接则不需要)。为了保证可执行程序在任何目录执行都能链接到对应的动态库,我们可以将Qt模块对应的动态库目录设置到系统的环境变量中(这一点对于Linux系统也是一样的)。

在桌面找到我的电脑(此电脑)图标,鼠标右键,打开属性窗口

QT安装_环境配置_1

在属性窗口中选择 “高级系统设置”

image-20241018103440742

点击系统属性->高级 下面的 环境变量

image-20241018103540383

找到系统变量下的 Path 属性并双击打开

QT安装_环境配置_4

现在可以讲QT中的目录添加到环境变量中

​ 环境变量路径说明

1、找到自己的QT安装路径 如果不记得了,可以通过右键点击 QT 软件 然后打开 ==打开文件所在位置==

路径如下:
D:\IDE_App\Qt_5.9\Tools\mingw530_32\bin
D:\IDE_App\Qt_5.9\5.9.9\mingw53_32\bin

QT安装_环境配置_5.png

环境变量配置完毕之后,不会马上生效,需要注销或者重启计算机。

2.3 软件介绍

2.3.1 使用技巧

1、编码格式设置

在使用QT Creator 工具前 ,我们需要先对编码格式进行设定

修改QtCreator的编码, 菜单栏 -> 工具

QT安装_编码格式_1

设定编码格式为UTF-8

QT设置_编码格式

2、编辑器主题设置

默认情况下,编辑器的背景色是白的,使用时间久了很刺眼。我们可以通过改变颜色来缓解。启动Qt Creator ,依次单击主菜单的菜单选项 “工具→选项” ,在 “选项” 对话框的左边选择 “文本编辑器” ,如图所示。

image-20241112093942009

上面是用于修改编辑器页面的样式,如果我们想修改软件的主体,则点击”环境“ 然后进行选择主题即可,注意这种方式是要重启软件后才能生效。

image-20241112094136258

3、设置中英文

【工具】->【选项】->【环境】

4、启动鼠标缩放

还可以设置鼠标滚轮,来放大和缩小字体

方法:【工具】->【选项】->【文本编辑器】->【Behavior

很实用和方便的功能,尤其是你在给同事讲解代码时,可以方便地放大代码区域

image-20250211222635052

5、显示行号、高亮显示当前行

方法:【工具】->【选项】->【文本编辑器】->【Display】

显示行号:方便代码行数的定位

高亮显示当前行:方便快速定位当前光标所在的行。这个默认时未勾选的,建议勾选

显示文件编码:界面上直观地显示文件编码。这个默认时未勾选的,建议勾选,这样文件编码显示在打开文件的右上角。

image-20250211222726706

6、保存时清理

就是在保存文件时,清除多余的空白字符,使代码简洁,并且占用的文件大小也会缩小

VSCode 以及 Source Insight 中都有这种设置

方法:【工具】->【选项】->【文本编辑器】->【Behavior】

2.3.2 软件介绍

主界面介绍

QT介绍

帮助文档

QT官方页面——1.png

2.4 创建第一个项目

2.4.1 创建工程

1、点击新建工程

QT_新建工程

2、选择创建工程的类型

QT_新建工程_选择类型

3、工程名

QT_新建工程_工程名和路径

4、选择系统构建工具

QT_新建工程_系统构建工具

5、选择开发所用的类

QT_新建工程_开发所用类

2.4.4 QT的运行模式

在 Qt 中,Debug(调试)、Profile(分析)和 Release(发布)是三种不同的运行模式,各有其特点和用途:

Debug : 用于开发和调试阶段,帮助开发者找出程序中的错误和问题。

包含大量的调试信息,如变量的值、函数调用栈等,方便开发者进行跟踪和分析。

运行速度相对较慢,因为有额外的调试代码和检查。

通常会进行一些额外的内存检查和错误检测,以帮助发现潜在的内存错误和逻辑错误。

Profile:用于分析程序的性能,找出程序中的性能瓶颈。

会收集程序运行时的各种性能数据,如函数执行时间、内存使用情况等。

运行速度比调试模式快,但比发布模式慢。

可以使用性能分析工具来查看收集到的数据,帮助开发者优化程序的性能。

Release:用于生成最终的可发布版本,供用户使用。

经过优化编译,不包含调试信息,运行速度快,占用资源少。

通常会进行一些优化,如去除未使用的代码、内联函数等,以提高程序的性能和减小程序的体积。

2.5.1 文件介绍

1、demo.pro

# 指定项目需要 Qt 的 core 和 gui 模块
# core 模块包含 Qt 的基本类,而 gui 模块包含图形界面相关的类
QT       += core gui

# 如果 Qt 主版本号大于 4(即 Qt5 或更高版本),
# 则将 widgets 模块加入项目,以便使用图形界面控件
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

# 将项目配置为使用 C++11 标准编译,
# C++11 引入了很多现代编程特性,如 lambda 表达式等
CONFIG += c++11

# 启用 Qt 废弃 API 的警告
# 如果代码中使用了已标记为废弃的功能,编译器会发出警告
DEFINES += QT_DEPRECATED_WARNINGS

# 使编译器在使用废弃 API 时报错(此行被注释掉)
# 可以通过指定版本号来禁用在该版本之前废弃的 API
# 例如,设置为 0x060000 禁用 Qt 6.0.0 之前的废弃 API
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

# 定义项目的源文件
SOURCES += \
    main.cpp \    # 主程序入口
    widget.cpp    # Widget 类的实现

# 定义项目的头文件
HEADERS += \
    widget.h      # Widget 类的声明

# 定义项目的 UI 界面文件
FORMS += \
    widget.ui     # Widget 界面设计文件

# 部署路径配置
# 如果目标系统是 QNX,二进制文件将安装到 /tmp/目标名称/bin
qnx: target.path = /tmp/$${TARGET}/bin

# 否则在 Unix 系统上(非安卓),二进制文件安装路径为 /opt/目标名称/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin

# 如果 target.path 不为空,则将其加入 INSTALLS,
# 以便在执行 `make install` 时自动安装
!isEmpty(target.path): INSTALLS += target

2、main.cpp

#include "widget.h"  // 包含自定义窗口类 Widget 的头文件

#include <QApplication>  // 包含 QApplication 类的头文件,用于管理应用程序

int main(int argc, char *argv[])
{
    // 解决 Qt 高分辨率屏幕显示错误问题
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);    // 启用高 DPI 缩放支持
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);       // 启用高 DPI 位图支持

    QApplication a(argc, argv);  // 创建 QApplication 对象 a,管理应用程序的控制流和全局设置
    Widget w;                    // 创建自定义窗口 Widget 类的对象 w
    w.show();                    // 显示窗口 w,使其出现在屏幕上
    return a.exec();             // 启动应用程序事件循环,等待用户交互
}

3、Widget.h

这个文件是窗口界面对应的类的头文件。
```c++
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>  // 包含 QWidget 类的头文件,QWidget 是所有窗口部件的基类

// Qt 的命名空间宏,用于处理 Qt 生成的代码
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }  // 声明 Ui 命名空间下的 Widget 类
QT_END_NAMESPACE

class Widget : public QWidget  // 定义 Widget 类,继承自 QWidget
{
    Q_OBJECT  // Q_OBJECT 宏是所有使用 Qt 的信号和槽机制的类的必备宏

public:
    Widget(QWidget *parent = nullptr);  // 构造函数,允许传入父窗口指针,默认值为 nullptr
    ~Widget();  // 析构函数

private:
    Ui::Widget *ui;  // 指向 Ui::Widget 类的指针,用于访问 UI 界面元素
};

#endif // WIDGET_H

4、Widget.cpp

这个文件是窗口界面对应的类的源文件。
```c++
#include "widget.h"    // 包含 Widget 类的头文件
#include "ui_widget.h" // 包含由 Qt 设计器生成的界面文件 ui_widget.h

// 构造函数定义
Widget::Widget(QWidget *parent)
    : QWidget(parent)                 // 调用基类 QWidget 的构造函数,设置父窗口
    , ui(new Ui::Widget)              // 创建一个 Ui::Widget 对象的实例
{
    ui->setupUi(this);                // 设置 UI,关联界面文件中的控件
}

// 析构函数定义
Widget::~Widget()
{
    delete ui;                        // 释放由 new 分配的 ui 对象内存
}

2.4.4 日志输出

由于我们现在学习的QT和我们原来学习C/C++ 不同 QT并不是终端开发的形式,也就是说,我们已经无法使用的printf和cout 进行打印输出,所以 QT 就给我们提供打印日志的 方式进行输出。

那么在QT我们就不叫格式化输出了 我们就称为 日志输出

1、 应用程序输出窗口

需要添加的头文件如下

Header:#include <QDebug> 
qmake:QT += core

使用实例

// 包含了QDebug头文件, 直接通过全局函数 qDebug() 就可以进行日志输出了

int num = 66;

qDebug() << "日志输出";
qDebug() << "打印字符串:" << QString("字符串") << Qchar('6') << num;



// 和全局函数 qDebug() 类似的日志函数还有: qWarning(), qInfo(), qCritical()
int num = 123;
float i = 11.11;
qWarning() << "Number:" << number << "Other value:" << i;
qInfo() << "Number:" << number << "Other value:" << i;
qCritical() << "Number:" << number << "Other value:" << i;

从 “应用程序输出” 中打印

QT打印日志

2、外部窗口输出

前面的方式是在QT软件中输出日志信息, 但是如果当我们不使用IDE工具的时候 ,或者 该程序打包成 可执行文件时 就没有这个窗口的输出了,所以我们需要让这个信息打印在终端上。

操作方式为:

在项目文件中 .pro 找到配置项 config 添加 console 控制台属性

CONFIG += C++ console

在运行前需要进行重构才能进行显示

image-20241023194958706

2.5 认识基础类

2.5.1 QObject类

QObject类是所有Qt类的基类,是Qt对象模型的核心。它最主要的特征是关于对象间无缝通信的机制:信号与槽(槽就是信号处理函数,后面会讲到)。

任何对象都要实现信号与槽机制,Q_OBJECT宏是强制的。不管是否真正用到信号与槽机制,最好在所有QObject子类中都使用Q_OBJECT宏,以免出现一些不必要的错误。

所有的Qt Widgets都是基础的QObject类。如果一个对象是Widget,那么isWidgetType()函数就能判断出。

QObject类既没有复制构造函数也没有赋值操作符,实际上它们使用宏Q_DISABLE_COPY()声明为私有的。所有派生自QObject类的对象都使用这个宏声明复制构造函数和赋值操作符为私有的。

2.5.2 基础窗口类

在前面创建工程的时候,发现我们需要选择窗口类,下拉菜单中有三个选项, 分别为: ==QMainWindow==、==QDialog==、==QWidget==如下图:

QT窗口_1

基础窗口类

常用的窗口类有3个

在创建Qt窗口的时候, 需要让自己的窗口类继承上述三个窗口类的其中一个

1、QWidget

  • 所有窗口类的基类

  • Qt中的控件(按钮, 输入框, 单选框…)也属于窗口, 基类都是QWidget

  • 可以内嵌到其他窗口中: 没有边框

  • 可以不内嵌单独显示: 独立的窗口, 有边框

2、QDialog

  • 对话框类

  • 特点:具有模态和非模态显示方式

  • 不能内嵌到其他窗口中

模态窗口:当打开模态窗口时,用户必须先处理该窗口中的内容(如填写表单或确认操作),才能返回到主窗口。这通常用于需要用户立即作出决策的情况,例如警告消息或确认对话框。

非模态窗口:非模态窗口可以在不阻碍主窗口的情况下独立打开,用户可以在主窗口和非模态窗口之间自由切换。这适用于需要同时查看多个信息或执行多个任务的场景,如工具箱或属性编辑器。

3、QMainWindow

  • 有工具栏, 状态栏, 菜单栏, 后边的章节会具体介绍这个窗口

  • 不能内嵌到其他窗口中

menubar : 菜单栏

statusbar : 状态栏

toolBar:工具栏

菜单栏 和 状态栏只能有一个 工具栏可以有多个

QMainWindow_介绍

2.5.2 添加界面类

1、右键点击 .pro 文件,选择

QT_添加界面类_1

2、按图选择

QT_添加类_2

3、选择你想创建的窗口类

QT_添加类_3

2.5.2 窗口的显示

内嵌显示

​ 内嵌显示就是将一个小窗口依附于另一个大窗口

​ 这里 大窗口 就是 父窗口 , 小窗口 就是子窗口

​ 当父窗口显示的时候子窗口也会备显示出来

如何内嵌

// 在创建窗口的时候,指定父对象
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    // 创建窗口是给子窗口创建指定父对象
    Form * F = new Form(this);

}

由于内嵌窗口是有指定父对象的 所以内嵌窗口不用使用函数就可以显示

不内嵌显示

有独立的窗口和边框和标题栏

不内嵌窗口必须使用函数方法才能被显示

显示函数

// QWidget是所有窗口类的基类, 调用这个提供的 show() 方法就可以显示将任何窗口显示出来
// 非模态显示
void QWidget::show();   // 显示当前窗口和它的子窗口

// 对话框窗口的非模态显示: 还是调用show() 方法
// 对话框窗口的模态显示
[virtual slot] int QDialog::exec();

示例

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    Form * F = new Form;
    F->show();
}

2.6 坐标体系

2.6.1 窗口坐标原点

原点 : 窗口左上角

X轴向右递增

Y轴向下递增

窗口坐标原点

2.6.2 窗口内嵌坐标

在一个Qt窗口中一般都有很多子窗口内嵌到这个父窗口中,其中每个窗口都有自己的坐标原点,子窗口的位置也就是其使用的坐标点就是它的父窗口坐标体系中的坐标点。

窗口内嵌坐标

2.6.3 设定窗口坐标

// 移动窗口位置 (窗口 按钮)
void QWidget::move(int x, int y);
void QWidget::move(const QPoint &);

// 设置窗口大小 (窗口 按钮) 
void QWidget::setFixedSize(int w, int h);

示例程序

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置位置
    this->move(200 , 200);
    // 设置大小 固定大小
    this->setFixedSize(500 , 500);
}

2.7 对象树机制 ==(重点内容)==

对象树机制是qt中很重要的一个自动回收机制。

在 Qt 中,QObject 类提供了一个父子关系的机制,用于管理对象的生命周期。这种机制形成了一个对象树,父对象负责管理其子对象的内存,当父对象被销毁时,会自动销毁所有子对象。这有助于避免内存泄漏,简化内存管理。

2.7.1关键点

  • 父子关系:通过在创建子对象时,将父对象指针传递给子对象的构造函数来建立。
  • 自动回收:当父对象被销毁时,Qt 会自动调用子对象的析构函数,递归地销毁所有子孙对象。
  • 注意事项:如果子对象被重新分配了父对象,需要确保父对象之间的关系正确,否则可能导致未定义的行为。

2.7.2实例程序

我们通过 C++ 来模拟一下QT中的对象树回收机制, 通过这个示例,希望大家可以更加深刻的理解这个对象树回收机制。

#include <iostream>
#include <list>

using namespace std;

// 前向声明
class Object;

// 定义一个孩子列表
typedef list<Object *> ObjectList;

// 定义一个父类
class Object {
public:
    // 孩子列表
    ObjectList children;

public:
    Object(Object * parent = nullptr) {
        if (parent != nullptr) {
            parent->children.push_back(this);
        }
    }

    virtual ~Object() {
        // 删除所有子对象
        for (Object * p : children) {
            delete p;
        }
    }
};

class A : public Object {
public:
    int * p;

public:
    A(Object * parent = nullptr)
            : Object(parent) {
        p = new int[1024]; // 动态分配内存
        cout << "A的构造" << endl;
    }

    ~A() {
        delete[] p; // 释放动态内存
        cout << "A的析构" << endl;
    }
};

int main() {
    Object obj; // 创建根对象

    A * a = new A(&obj); // 创建 A 的实例并将其设置为 obj 的子对象
    // delete &obj; // 这会导致 obj 的析构,自动释放 a

    return 0;
}

第三章 QT基础数据类型

3.1 QT 基础数据类型

在QT中也有和 C/C++ 类似的基础类型 起始就是将C/C++中的基础类型进行了封装,一般不用,但是我们要知道有这么个内容。

要使用QT中的基础类型 我们就要导入以下的这个库

#include <QtGlobal>

1、有符号整数

qint8:8位有符号整数,对应 signed char。
qint16:16位有符号整数,对应 signed short。
qint32:32位有符号整数,对应 signed int。
qint64:64位有符号整数,对应 long long int 或 __int64(Windows系统下定义为 __int64)。
qintptr:指针大小的整数类型,32位系统对应 qint32,64位系统对应 qint64。根据系统不同会自动调整。
qlonglong:特定于 Windows 系统的 __int64 类型,对应 long long int。
qptrdiff:指针差值类型,32位系统对应 qint32,64位系统对应 qint64。根据系统不同会自动调整。

2、无符号整数

quint8:8位无符号整数,对应 unsigned char。
quint16:16位无符号整数,对应 unsigned short。
quint32:32位无符号整数,对应 unsigned int。
quint64:64位无符号整数,对应 unsigned long long int 或 unsigned __int64(Windows系统下定义为 unsigned __int64)。
quintptr:指针大小的无符号整数类型,32位系统对应 quint32,64位系统对应 quint64。根据系统不同会自动调整。
qulonglong:特定于 Windows 系统的 unsigned __int64 类型,对应 unsigned long long int。

3、字符类型

uchar:无符号字符类型,对应 unsigned char。

4、浮点数

qreal:浮点类型,默认是 double,如果配置了 -qreal float 选项,则为 float。

3.3 字符串

在qt中是支持 c / c++ 的字符串类型,同时在qt中还定义自己的字符串类型

C语言  char *  char []
C++     string
qt      QString QByteArray

在qt 中 常用的类型就是QString QByteArray两种,这两种我们在调用的时候,他们内置的API几乎完全相同

3.3.1 QByteArray

QByteArray 是 Qt 框架中用于处理字节数组的类,专门设计用于操作字节级的数据。它提供了对二进制数据和 ASCII 字符串的高效管理,与 C 风格的字符数组(char*)和标准库的 std::string 类似,但拥有更多的功能和更好的性能。

字节数组类QByteArray提供一个字节数组,用于存储原始字节。使用QByteArray类比使用char *更方便。该类在串口通信中经常被使用,因为串口通信数据都是一个一个的8位字节流。

1、构造函数

// 默认构造函数
QByteArray::QByteArray();
// 从字符指针构造
QByteArray::QByteArray(const char *data, int size = -1);
// 指定长度和填充值构造
QByteArray::QByteArray(int size, char ch);
// 拷贝构造函数
QByteArray::QByteArray(const QByteArray &other);

2、元素访问

// 获取指定位置的字符
char QByteArray::at(int i) const;
char QByteArray::operator[](int i) const;
// 获取内部数据指针
char* QByteArray::data();
const char* QByteArray::data() const;

3、迭代器

// 获取迭代器
QByteArray::iterator begin();
QByteArray::iterator end();

4、容量相关

// 获取长度和大小
int QByteArray::length() const;
int QByteArray::size() const;
int QByteArray::count() const;
// 检查是否为空
bool QByteArray::isEmpty() const;

5、修改器

追加数据
// 在尾部追加
QByteArray& QByteArray::append(const QByteArray &ba);
QByteArray& QByteArray::append(int count, char ch);
QByteArray& QByteArray::append(const char *str);
QByteArray& QByteArray::append(const char *str, int len);
QByteArray& QByteArray::append(char ch);
QByteArray& QByteArray::append(const QString &str);

void QByteArray::push_back(const QByteArray &other);
void QByteArray::push_back(const char *str);
void QByteArray::push_back(char ch);
前置数据
// 在头部添加
QByteArray& QByteArray::prepend(const QByteArray &ba);
QByteArray& QByteArray::prepend(int count, char ch);
QByteArray& QByteArray::prepend(const char *str);
QByteArray& QByteArray::prepend(const char *str, int len);
QByteArray& QByteArray::prepend(char ch);

void QByteArray::push_front(const QByteArray &other);
void QByteArray::push_front(const char *str);
void QByteArray::push_front(char ch);
插入数据
// 在指定位置插入
QByteArray& QByteArray::insert(int i, const QByteArray &ba);
QByteArray& QByteArray::insert(int i, int count, char ch);
QByteArray& QByteArray::insert(int i, const char *str);
QByteArray& QByteArray::insert(int i, const char *str, int len);
QByteArray& QByteArray::insert(int i, char ch);
QByteArray& QByteArray::insert(int i, const QString &str);
移除数据
// 删除指定范围的数据
QByteArray& QByteArray::remove(int pos, int len);
// 从尾部移除
void QByteArray::chop(int n);
// 截断数据
void QByteArray::truncate(int pos);
// 清空数据
void QByteArray::clear();
替换数据
// 替换指定范围的数据
QByteArray& QByteArray::replace(int pos, int len, const QByteArray &after);
QByteArray& QByteArray::replace(int pos, int len, const char *after, int alen);
QByteArray& QByteArray::replace(int pos, int len, const char *after);
// 替换字符或子字符串
QByteArray& QByteArray::replace(char before, const char *after);
QByteArray& QByteArray::replace(char before, const QByteArray &after);
QByteArray& QByteArray::replace(const char *before, const char *after);
QByteArray& QByteArray::replace(const char *before, int bsize, const char *after, int asize);
QByteArray& QByteArray::replace(const QByteArray &before, const QByteArray &after);
QByteArray& QByteArray::replace(const QByteArray &before, const char *after);
QByteArray& QByteArray::replace(const char *before, const QByteArray &after);
QByteArray& QByteArray::replace(char before, char after);
QByteArray& QByteArray::replace(const QString &before, const char *after);
QByteArray& QByteArray::replace(char before, const QString &after);
QByteArray& QByteArray::replace(const QString &before, const QByteArray &after);

6、查找与判断

// 包含检查
bool QByteArray::contains(const QByteArray &ba) const;
bool QByteArray::contains(const char *ba) const;
bool QByteArray::contains(char ch) const;
// 开始匹配
bool QByteArray::startsWith(const QByteArray &ba) const;
bool QByteArray::startsWith(const char *ba) const;
bool QByteArray::startsWith(char ch) const;
// 结束匹配
bool QByteArray::endsWith(const QByteArray &ba) const;
bool QByteArray::endsWith(const char *ba) const;
bool QByteArray::endsWith(char ch) const;
// 计数子字符串出现次数
int QByteArray::count(const QByteArray &ba) const;
int QByteArray::count(const char *ba) const;
int QByteArray::count(char ch) const;

7、类型转换

// 转换为数字
int QByteArray::toInt(bool *ok = Q_NULLPTR, int base = 10) const;
short QByteArray::toShort(bool *ok = Q_NULLPTR, int base = 10) const;
long QByteArray::toLong(bool *ok = Q_NULLPTR, int base = 10) const;
float QByteArray::toFloat(bool *ok = Q_NULLPTR) const;
double QByteArray::toDouble(bool *ok = Q_NULLPTR) const;

// 从数字设置内容
QByteArray& QByteArray::setNum(int n, int base = 10);
QByteArray& QByteArray::setNum(short n, int base = 10);
QByteArray& QByteArray::setNum(qlonglong n, int base = 10);
QByteArray& QByteArray::setNum(float n, char f = 'g', int prec = 6);
QByteArray& QByteArray::setNum(double n, char f = 'g', int prec = 6);

static QByteArray QByteArray::number(int n, int base = 10);
static QByteArray QByteArray::number(qlonglong n, int base = 10);
static QByteArray QByteArray::number(double n, char f = 'g', int prec = 6);

// 大小写转换
QByteArray QByteArray::toUpper() const;
QByteArray QByteArray::toLower() const;

// 与 std::string 相互转换
static QByteArray QByteArray::fromStdString(const std::string &str);

std::string QByteArray::toStdString() const;

8、操作符重载

// 赋值操作符
QByteArray& QByteArray::operator=(const QByteArray &other);
// 比较操作符
bool QByteArray::operator==(const QByteArray &other) const;
bool QByteArray::operator!=(const QByteArray &other) const;
// 索引操作符
char QByteArray::operator[](int i) const;
char& QByteArray::operator[](int i);

9、其他

// 清空数据
void QByteArray::clear();
// 截断与裁剪
void QByteArray::truncate(int pos);
void QByteArray::chop(int n);
// 获取容量
int QByteArray::capacity() const;

3.3.2 QString

QString 是 Qt 中用于处理 Unicode 字符串的类,提供了高效的字符串操作方法和丰富的功能。它支持 UTF-16 编码,能够兼容各种语言的字符处理需求。QString 提供了字符串的拼接、分割、替换、查找等功能,并支持与标准的 C++ 字符串类型(如 std::string)的转换。此外,它还具有高效的内存管理机制,能够自动调整内存,适用于需要频繁修改字符串的场景。

好的,下面对 QString 的常用 API 进行分类整理,包括构造函数、数据操作、字符串查找与判断等多个方面:

1. 构造函数

用于创建 QString 对象的不同方式。

// 构造一个空字符串对象
QString::QString();

// 将 char* 字符串转换为 QString 类型
QString::QString(const char *str);

// 将 QByteArray 转换为 QString 类型
QString::QString(const QByteArray &ba);

// 从 QChar 数组构造 QString
QString::QString(const QChar *unicode, int size = -1);

// 使用单个 QChar 构造 QString
QString::QString(QChar ch);

// 使用指定大小和填充字符构造 QString
QString::QString(int size, QChar ch);

// 使用 QLatin1String 构造 QString
QString::QString(QLatin1String str);

// 拷贝构造函数
QString::QString(const QString &other);

// 移动构造函数
QString::QString(QString &&other);

2. 数据操作

用于修改字符串内容的函数,如追加、插入、删除等。

// 尾部追加数据
QString &QString::append(const QString &str);
QString &QString::append(const char *str);
QString &QString::append(const QByteArray &ba);
void QString::push_back(const QString &other);

// 头部添加数据
QString &QString::prepend(const QString &str);
QString &QString::prepend(const char *str);
QString &QString::prepend(const QByteArray &ba);
void QString::push_front(const QString &other);

// 插入数据
QString &QString::insert(int position, const QString &str);
QString &QString::insert(int position, const char *str);
QString &QString::insert(int position, const QByteArray &str);

// 删除数据
QString &QString::remove(int position, int n);
void QString::chop(int n);
void QString::truncate(int position);
void QString::clear();

// 字符串替换
QString &QString::replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);

3. 字符串查找和判断

用于查找子字符串或判断字符串特性的函数。

// 判断字符串中是否包含子字符串 str
bool QString::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 判断字符串是否以指定字符串开头
bool QString::startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 判断字符串是否以指定字符串结尾
bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 查找字符或子字符串的位置
int QString::indexOf(QChar ch, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int QString::lastIndexOf(QChar ch, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 判断字符串是否为空
bool QString::isEmpty() const;

// 获取字符串长度
int QString::length() const;

4. 转换函数

用于在不同类型之间转换字符串内容。

// 将 QString 转换为 std::string
std::string QString::toStdString() const;

// 将 QString 转换为 QByteArray
QByteArray QString::toUtf8() const;
QByteArray QString::toLatin1() const;
QByteArray QString::toLocal8Bit() const;

// 将 QString 转换为整数
int QString::toInt(bool *ok = nullptr, int base = 10) const;

// 将 QString 转换为浮点数
double QString::toDouble(bool *ok = nullptr) const;

// 将 QString 转换为其他类型,可以参考 Qt 帮助文档

5. 比较函数

用于比较字符串内容的函数。

// 比较两个字符串是否相等
bool QString::operator==(const QString &other) const;

// 按指定大小写敏感性比较字符串
int QString::compare(const QString &other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 不等于操作符
bool QString::operator!=(const QString &other) const;

// 其他比较相关的函数可参考 Qt 帮助文档

6. 分割和连接

用于分割字符串和连接多个字符串的函数。

// 按分隔符分割字符串,返回字符串列表
QStringList QString::split(const QString &sep, Qt::SplitBehaviorFlags flags = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

// 连接字符串列表为一个字符串
QString QString::join(const QStringList &list, const QString &sep);

7. 大小写转换

用于转换字符串大小写的函数。

// 将字符串转换为大写
QString &QString::toUpper();

// 将字符串转换为小写
QString &QString::toLower();

// 其他大小写相关的函数

8. 修剪和填充

用于修剪空白字符和填充字符串的函数。

// 去除字符串首尾的空白字符
QString QString::trimmed() const;

// 去除字符串左边的空白字符
QString QString::trimmedLeft() const;

// 去除字符串右边的空白字符
QString QString::trimmedRight() const;

// 填充字符串到指定长度
QString &QString::fill(QChar ch, int size);

9. 子字符串和截取

用于获取子字符串的函数。

// 获取子字符串,从 position 开始,长度为 length
QString QString::mid(int position, int length = -1) const;

// 从左边截取指定长度的子字符串
QString QString::left(int length) const;

// 从右边截取指定长度的子字符串
QString QString::right(int length) const;

10. 格式化

用于格式化字符串的函数。

// 使用格式化字符串
QString QString::arg(const QString &a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const;

// 其他格式化相关的函数

11. 其他辅助函数

包含一些辅助性的实用函数。

// 获取字符串的第一个字符
QChar QString::at(int position) const;

// 检查字符串是否以数字开头
bool QString::isNumber() const;

// 转换为大写首字母
QString QString::capitalize() const;

// 其他辅助功能函数

3.4 QVariant

模板

QVariant 类非常独特且实用。在很多情况下,我们需要传递多种不同类型的数据,使用结构体并不方便,而容器通常只支持单一类型的数据。QVariant 的出现则很好地解决了这个问题。

QVariant 类可以视为多种常用数据类型的集合。它能够存储多种 Qt 数据类型,包括 QBrush、QColor、QCursor、QDateTime、QFont、QKeySequence、QPalette、QPen、QPixmap、QPoint、QRect、QRegion、QSize 和 QString,此外还支持基本的 C++ 数据类型,比如 int 和 float。

模版

在新版本中,QVariant 类型已经被废弃了,实际上我们所使用的类型是 QMetaType 类型

3.4.1 API 介绍

1、构造函数

QVariant::QVariant()                      // 默认构造一个空的 QVariant。
QVariant::QVariant(Type type)             // 构造指定类型的 QVariant,初始化为空值。
QVariant::QVariant(const T &value)        // 使用指定类型的值构造 QVariant。

2、类型检查

Type QVariant::type() const               // 返回 QVariant 当前存储的数据类型。
bool QVariant::isNull() const             // 检查 QVariant 是否为空。
bool QVariant::isValid() const            // 检查 QVariant 是否有效。
bool QVariant::canConvert(Type type) const// 检查 QVariant 是否可以转换为指定类型 用于自定义类型。

3、类型转换

QString QVariant::to<Type>() const        // 将数据转换为 Type 所指定的类型。

4、数据操作

void QVariant::clear()                    // 清空 QVariant 的数据,将其类型重置为 Invalid。
void QVariant::setValue(const T &value)   // 将 QVariant 设置为指定值,并更新其类型。
T QVariant::value() const                 // 获取 QVariant 中存储的值,返回类型为指定的模板类型 T。

5、从值构造

静态函数

QVariant QVariant::fromValue(const T &value)

6、自定义类型注册

Q_DECLARE_METATYPE(Type)        // 注册自定义类型,使其可以存储在 QVariant 中。

3.4.2 标准类型

设定类型的方式,示例

// 1、通过 有参构造函数设定    
    QVariant var1(42);                 // 设定为 int 类型
    QVariant var2(QString("Hello"));    // 设定为 QString 类型

// 2、通过 setValue 设定     适用于更新为该值的类型
    QVariant var;
    var.setValue(42);                  // 设定为 int 类型
    var.setValue(QString("Hello"));    // 设定为 QString 类型

// 3、通过 fromValue 设定    适用于自定义类型的数据
    QVariant var = QVariant::fromValue(42);                   // 设定为 int 类型
    QVariant var = QVariant::fromValue(QString("Hello"));     // 设定为 QString 类型

示例程序

#include <QVariant>
#include <QString>
#include <QDebug>

class Widget {
public:
    QVariant add(const QVariant &a, const QVariant &b);  // 定义加法函数
};

QVariant Widget::add(const QVariant &a, const QVariant &b) {
    QVariant result;  // 用于存储返回结果

    // 判断 a 和 b 是否为 int 类型
    if (a.type() == QVariant::Int && b.type() == QVariant::Int) {
        result = a.toInt() + b.toInt();  // 如果都是 int 类型,则相加
    }
    // 判断 a 和 b 是否为 QString 类型
    else if (a.type() == QVariant::String && b.type() == QVariant::String) {
        result = a.toString() + b.toString();  // 如果都是 QString 类型,则拼接
    } else {
        qDebug() << "类型不匹配,无法相加";  // 如果类型不匹配,打印错误信息
    }

    return result;  // 返回结果(如果类型不匹配,将返回空的 QVariant)
}

int main() {
    Widget widget;

    // 测试 int 类型的相加
    QVariant intResult = widget.add(10, 20);
    qDebug() << "整数相加结果:" << intResult.toInt();  // 输出:30

    // 测试 QString 类型的拼接
    QVariant strResult = widget.add(QString("张三"), QString("你好"));
    qDebug() << "字符串拼接结果:" << strResult.toString();  // 输出:"张三你好"

    // 测试不同类型的相加
    QVariant mismatchResult = widget.add(10, QString("你好"));
    qDebug() << "类型不匹配的结果:" << mismatchResult;  // 输出:空的 QVariant

    return 0;
}

3.4.3 自定义类型

在前面我们提到,QVariant 的类型设定方法有三种,但对于自定义类型,由于其特殊性,我们只能使用其中的两种,即 setValuefromValue

此外,因自定义类型无法使用 type 方法进行类型判定,因此我们需要使用另一个判定函数 canConvert 来检查 QVariant 是否可以转换为该自定义类型。之后,可以通过 value 函数来获取存储的自定义类型的值。这两个函数的使用示例在 Qt 帮助文档中也有详细说明。

使用示例如下

#include <QCoreApplication>
#include <QVariant>
#include <QString>
#include <QDebug>

// 定义自定义类型
struct CustomType {
    int id;
    QString name;
};

// 注册自定义类型,使其可以被 QVariant 使用
Q_DECLARE_METATYPE(CustomType)

int main(int argc, char *argv[]) {

    // 创建并初始化自定义类型的对象
    CustomType customData{1, "张三"};

    // 将自定义类型的对象存储到 QVariant 中
    QVariant var = QVariant::fromValue(customData);

    // 使用 canConvert 检查 QVariant 是否可以转换为 CustomType
    if (var.canConvert<CustomType>()) {
        // 如果可以转换,则使用 value 获取存储的自定义类型值
        CustomType retrievedData = var.value<CustomType>();

        // 输出 retrievedData 的属性
        qDebug() << "ID:" << retrievedData.id;
        qDebug() << "Name:" << retrievedData.name;
    } else {
        qDebug() << "QVariant 中的类型无法转换为 CustomType";
    }

    return 0;
}

3.5 几何类

在QT开发中,我们经常会遇到设定窗口位置 、 设定窗口大小等问题问题,为了我们方便的进行对这些内容的开发,QT为我们封装了 坐标类、直线类、尺寸类、矩形类等。

3.5.1 坐标类-QPoint

QPoint 是 Qt 中的坐标类,主要用于表示二维空间中的点,通常与 GUI 开发中的图形和窗口布局相关。在 Qt 的图形系统中,QPoint 用于指定屏幕、窗口或图像上的位置,适用于像素坐标。它有两个整数属性 xy 分别表示点的水平和垂直坐标。

1、构造函数

// 构造一个零点,即坐标为(0,0)
QPoint::QPoint();
// 构造一个具有给定坐标(xpos, ypos)的点。
QPoint::QPoint(int xpos, int ypos);
// 构造给定点的副本。
QPointF::QPointF(const QPoint &point)

2、设定坐标

// 设定x坐标值
void QPoint::setX(int x)
// 设定y坐标值
void QPoint::setY(int y)

3、获取坐标

// 返回该点的x坐标
qreal QPointF::x() const;
// 返回该点的y坐标
qreal QPointF::y() const;

// 返回对该点的x坐标的引用
qreal &QPointF::rx();
// 返回对该点的y坐标的引用
qreal &QPointF::ry();

4、计算坐标

// 
QPoint &QPoint::operator*=(float factor);
QPoint &QPoint::operator*=(double factor);
QPoint &QPoint::operator*=(int factor);
QPoint &QPoint::operator+=(const QPoint &point);
QPoint &QPoint::operator-=(const QPoint &point);
QPoint &QPoint::operator/=(qreal divisor);

5、实例程序

输出坐标

void Widget::QPoint_test_func()
{
    // 构造函数
    QPoint pos_1(10 , 10);
    qDebug() << "pos_1 =" << pos_1;
    //  拷贝构造
    QPoint pos_2(pos_1);
    qDebug() << "pos_2 =" << pos_2;

    // 设定坐标
    pos_1.setX(20);
    pos_1.setY(20);
    qDebug() << "pos_1 =" << pos_1;

    // 获取坐标
    pos_2.setX(pos_1.x());
    pos_2.setY(pos_1.y());
    qDebug() << "pos_2 =" << pos_2;

    // 获取坐标
    int & my_x = pos_1.rx();
    int & my_y = pos_1.ry();

    my_x = 80;
    my_y = 80;
    qDebug() << "pos_1 =" << pos_1;
}

移动窗口

运行结果

pos_1 = QPoint(10,10)
pos_2 = QPoint(10,10)
pos_1 = QPoint(20,20)
pos_2 = QPoint(20,20)
pos_1 = QPoint(80,80)

3.5.2 直线类-QLine

QLine 是 Qt 中用于表示二维平 面上直线段的类。它的两个主要属性是起点和终点,分别由 QPoint 表示。直线段在 GUI 中常用于绘制简单线条或定义边界。

QT_直线类

1、构造函数

// 构造空线
QLine::QLine();
// 构造一个表示p1和p2之间的线对象
QLine::QLine(const QPoint &p1, const QPoint &p2)
// 构造一个线对象,表示(x1, y1)和(x2, y2)之间的线。
QLine::QLine(int x1, int y1, int x2, int y2)

2、设置直线坐标

// 将这一行的起始点设置为p1。
void QLine::setP1(const QPoint &p1);
// 将该行的结束点设置为p2。
void QLine::setP2(const QPoint &p2);
// 设置这条线的起始点为x1, y1,结束点为x2, y2。
void QLine::setLine(int x1, int y1, int x2, int y2);
// 将该行的起点设置为p1,将该行的终点设置为p2。
void QLine::setPoints(const QPoint &p1, const QPoint &p2);

3、获取直线坐标

// 返回线段起始点坐标
QPoint QLine::p1() const
// 返回线段结束点坐标
QPoint QLine::p2() const
// 返回线段起始点的 x 坐标
int QLine::x1() const
// 返回该线段起始点的 y 坐标
int QLine::y1() const
// 返回线段终止点的 x 坐标
int QLine::x2() const
// 返回该线段终止点的 y 坐标
int QLine::y2() const
// 返回该线段的中心点。这个值等同于 (p1() + p2()) / 2,但不会发生溢出。
QPoint QLine::center() const

4、比较直线坐标

// 如果线段的起始点和终止点未设置为有效值,则返回 true;否则返回 false。
bool QLine::isNull() const
// 如果给定的线段与当前线段不同,则返回 true。
// 线段之间的不同包括它们的起始点或终止点有任何差异,或者点的顺序不同。
bool QLine::operator!=(const QLine &line) const
// 如果给定的线段与当前线段相同,则返回 true。
// 线段相同的条件是它们的起始点和终止点完全相同,并且点的顺序也相同。
bool QLine::operator==(const QLine &line) const

5、平移直线坐标

// 将该线段按给定的偏移量进行平移。
void QLine::translate(const QPoint &offset);
// 这是一个重载函数。将该线段按 dx 和 dy 指定的距离进行平移。
void QLine::translate(int dx, int dy);
// 返回该线段按给定偏移量平移后的新线段。
QLine QLine::translated(const QPoint &offset) const
// 返回该线段按指定的水平偏移量 dx 和垂直偏移量 dy 平移后的新线段。
QLine QLine::translated(int dx, int dy) const

5、实例程序

void Widget::QLine_test_func()
{
    // 1. 创建线段
    QLine line1; // 空线
    QLine line2(QPoint(1, 2), QPoint(3, 4)); // 使用两个点创建线段
    QLine line3(0, 0, 5, 5); // 使用坐标创建线段

    // 2. 设置直线坐标
    line1.setP1(QPoint(2, 3)); // 设置起始点
    line1.setP2(QPoint(4, 5)); // 设置结束点
    line1.setLine(1, 1, 2, 2); // 设置起始和结束坐标
    line1.setPoints(QPoint(0, 0), QPoint(3, 3)); // 设置起始和结束点

    // 3. 获取直线坐标
    qDebug() << "Line1 起始点:" << line1.p1() << "结束点:" << line1.p2();
    qDebug() << "Line1 起始点 X:" << line1.x1() << "Y:" << line1.y1();
    qDebug() << "Line1 结束点 X:" << line1.x2() << "Y:" << line1.y2();
    qDebug() << "Line1 中心点:" << line1.center();

    // 4. 比较直线坐标
    qDebug() << "Line1 是否为空线?" << line1.isNull();
    qDebug() << "Line1 是否等于 Line2?" << (line1 == line2);
    qDebug() << "Line1 是否不等于 Line3?" << (line1 != line3);

    // 5. 平移直线坐标
    line1.translate(QPoint(1, 1)); // 按给定偏移量平移
    qDebug() << "Line1 平移后 (1, 1):" << line1.p1() << "到" << line1.p2();

    QLine translatedLine = line1.translated(2, 2); // 使用重载函数平移
    qDebug() << "平移后的线 (2, 2):" << translatedLine.p1() << "到" << translatedLine.p2();
}
```c++
Line1 起始点: QPoint(0,0) 结束点: QPoint(3,3)
Line1 起始点 X: 0 Y: 0
Line1 结束点 X: 3 Y: 3
Line1 中心点: QPoint(1,1)
Line1 是否为空线? false
Line1 是否等于 Line2? false
Line1 是否不等于 Line3? true
Line1 平移后 (1, 1): QPoint(1,1) 到 QPoint(4,4)
平移后的线 (2, 2): QPoint(3,3) 到 QPoint(6,6)

3.5.3 尺寸类-QSize

QSize 是 Qt 中用于表示二维空间中宽度和高度的类,常用于指定和管理控件、图像等的尺寸。它包含两个整数属性 widthheight,分别表示水平和垂直尺寸。

1、构造函数

// 构造一个宽度和高度无效的尺寸
QSize::QSize()  
// 构造一个具有给定宽度和高度的尺寸。
QSize::QSize(int width, int height)

2、设置尺寸

// 将高度设置为给定的高度。
void QSize::setHeight(int height)
// 将宽度设置为给定的宽度。
void QSize::setWidth(int width)

3、获取尺寸

// 返回宽度的引用。使用引用可以直接操作宽度。
int &QSize::rwidth()
// 返回高度的引用。使用引用可以直接操作高度。
int &QSize::rheight()
// 返回宽度。
int QSize::width() const
// 返回高度。
int QSize::height() const

4、宽 高 交换

// 交换宽度和高度的值。
void QSize::transpose()
// 返回一个宽度和高度交换的新 QSize 对象。
QSize QSize::transposed() const

6、比较尺寸

// 如果宽度或高度小于或等于 0,则返回 true;否则返回 false。
bool QSize::isEmpty() const
// 如果宽度和高度都为 0,则返回 true;否则返回 false。
bool QSize::isNull() const
// 如果宽度和高度都大于或等于 0,则返回 true;否则返回 false。
bool QSize::isValid() const
// 如果 s1 和 s2 不同,则返回 true;否则返回 false。
bool operator!=(const QSize &s1, const QSize &s2)
// 如果 s1 和 s2 相等,则返回 true;否则返回 false。
bool operator==(const QSize &s1, const QSize &s2)

7、尺寸计算

注意,结果会四舍五入到最接近的整数。

// 将宽度和高度都乘以给定的因子,并返回对尺寸的引用。
QSize &QSize::operator*=(qreal factor);

// 将宽度和高度都加上给定的尺寸,并返回对尺寸的引用。
QSize &QSize::operator+=(const QSize &size);

// 将宽度和高度都减去给定的尺寸,并返回对尺寸的引用。
QSize &QSize::operator-=(const QSize &size);

// 将宽度和高度都除以给定的因子,并返回对尺寸的引用。
QSize &QSize::operator/=(qreal divisor);

说明

乘法运算符 \*=:对当前尺寸的宽度和高度进行缩放。

加法运算符 +=:将当前尺寸与给定尺寸相加。

减法运算符 -=:将当前尺寸减去给定尺寸。

除法运算符 /=:将当前尺寸的宽度和高度按给定因子缩小。

3.5.4 矩形类-QRect

QRect 是 Qt 中用于表示二维空间中的矩形区域的类。一个矩形由左上角的坐标和宽度、高度定义,常用于描述控件、图像等的边界或区域。

// 构造函数
QRect();
QRect(const QPoint &topLeft, const QPoint &bottomRight);
QRect(const QPoint &topLeft, const QSize &size);
QRect(int x, int y, int width, int height);

// 尺寸获取
int width() const;
int height() const;
QSize size() const;

// 坐标获取
int left() const;
int right() const;
int top() const;
int bottom() const;
int x() const;
int y() const;

// 边界点
QPoint topLeft() const;
QPoint topRight() const;
QPoint bottomLeft() const;
QPoint bottomRight() const;
QPoint center() const;

// 包含检查
bool contains(const QPoint &point, bool proper = false) const;
bool contains(const QRect &rectangle, bool proper = false) const;
bool contains(int x, int y) const;
bool contains(int x, int y, bool proper) const;

// 位置设置
void setLeft(int x);
void setRight(int x);
void setTop(int y);
void setBottom(int y);
void setTopLeft(const QPoint &position);
void setTopRight(const QPoint &position);
void setBottomLeft(const QPoint &position);
void setBottomRight(const QPoint &position);
void setCoords(int x1, int y1, int x2, int y2);
void setRect(int x, int y, int width, int height);
void setX(int x);
void setY(int y);

// 移动矩形
void moveTo(int x, int y);
void moveTo(const QPoint &position);
void moveBottom(int y);
void moveLeft(int x);
void moveRight(int x);
void moveTop(int y);
void moveBottomLeft(const QPoint &position);
void moveBottomRight(const QPoint &position);
void moveCenter(const QPoint &position);
void moveTopLeft(const QPoint &position);
void moveTopRight(const QPoint &position);

// 大小调整
void setWidth(int width);
void setHeight(int height);
void setSize(const QSize &size);
void adjust(int dx1, int dy1, int dx2, int dy2);
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const;
QRect marginsAdded(const QMargins &margins) const;
QRect marginsRemoved(const QMargins &margins) const;

// 几何运算
QRect intersected(const QRect &rectangle) const;
bool intersects(const QRect &rectangle) const;
QRect united(const QRect &rectangle) const;
QRect operator&(const QRect &rectangle) const;
QRect &operator&=(const QRect &rectangle);
QRect operator|(const QRect &rectangle) const;
QRect &operator|=(const QRect &rectangle);

// 变换和翻转
void translate(int dx, int dy);
void translate(const QPoint &offset);
QRect translated(int dx, int dy) const;
QRect translated(const QPoint &offset) const;
QRect transposed() const;

// 信息和检查
bool isEmpty() const;
bool isNull() const;
bool isValid() const;
void getCoords(int *x1, int *y1, int *x2, int *y2) const;
void getRect(int *x, int *y, int *width, int *height) const;

// 其他操作
QRect normalized() const;
CGRect toCGRect() const;
QRect &operator+=(const QMargins &margins);
QRect &operator-=(const QMargins &margins);

1、构造函数

// 构造一个空矩形。
QRect::QRect()
// 构造一个具有给定左上角和右下角的矩形。
QRect::QRect(const QPoint &topLeft, const QPoint &bottomRight)
// 构造一个具有给定左上角和给定尺寸的矩形。
QRect::QRect(const QPoint &topLeft, const QSize &size)
// 构造一个以 (x, y) 作为左上角,并具有给定宽度和高度的矩形。
QRect::QRect(int x, int y, int width, int height)

2、设置矩形数据

// ******************************** 设置边 ********************************//
// 将矩形的左边缘设置为给定的 x 坐标。这可能会改变宽度,但不会改变矩形的右边缘。
void QRect::setX(int x)

// 将矩形的上边缘设置为给定的 y 坐标。这可能会改变高度,但不会改变矩形的下边缘。
void QRect::setY(int y)

// 将矩形的左边缘设置为给定的 x 坐标。可能会改变宽度,但永远不会改变矩形的右边缘。
void QRect::setLeft(int x)

// 将矩形的右边缘设置为给定的 x 坐标。可能会改变宽度,但永远不会改变矩形的左边缘。
void QRect::setRight(int x)

// 将矩形的下边缘设置为给定的 y 坐标。这可能会改变高度,但不会改变矩形的上边缘。
void QRect::setBottom(int y)

// 将矩形的上边设置为给定的 y 坐标。这可能会改变高度,但不会改变矩形的下边。
void QRect::setTop(int y)

// ******************************** 设置点 ********************************//

// 将矩形的左上角设置为给定的位置。这可能会改变尺寸,但不会改变矩形的右下角。
void QRect::setTopLeft(const QPoint &position)

// 将矩形的左下角设置为给定的位置。这可能会改变尺寸,但不会改变矩形的右上角。
void QRect::setBottomLeft(const QPoint &position)

// 将矩形的右上角设置为给定的位置。这可能会改变尺寸,但不会改变矩形的左下角。
void QRect::setTopRight(const QPoint &position)

// 将矩形的右下角设置为给定的位置。这可能会改变尺寸,但不会改变矩形的左上角。
void QRect::setBottomRight(const QPoint &position)

// ******************************* 设置尺寸 *******************************//
// 将矩形的尺寸设置为给定的尺寸。左上角的位置保持不变。
void QRect::setSize(const QSize &size)

// 将矩形的宽度设置为给定的宽度。右边缘会改变,但左边缘保持不变。
void QRect::setWidth(int width)

// 将矩形的高度设置为给定的高度。下边缘会改变,但上边缘保持不变。
void QRect::setHeight(int height)

// 将矩形的左上角坐标设置为 (x, y),并将其大小设置为给定的宽度和高度。
void QRect::setRect(int x, int y, int width, int height)

3、获取矩形数据

获取坐标

// ******************************** 获取边 ********************************//
// 返回矩形左边缘的 x 坐标。等同于 left()。
int QRect::x() const

// 返回矩形顶部边缘的 y 坐标。等同于 top()。
int QRect::y() const

// 返回矩形顶部边缘的 y 坐标。等同于 y()。
int QRect::top() const

// 返回矩形底边缘的 y 坐标。请注意,由于历史原因,此函数返回 top() + height() - 1;要获取真实的 y 坐标,请使用 y() + height()。
int QRect::bottom() const

// 返回矩形左边缘的 x 坐标。等同于 x()。
int QRect::left() const

// 返回矩形右边缘的 x 坐标。请注意,由于历史原因,此函数返回 left() + width() - 1;要获取真实的 x 坐标,请使用 x() + width()。
int QRect::right() const

// ******************************** 获取点 ********************************//
// 返回矩形左上角的坐标。
QPoint QRect::topLeft() const

// 返回矩形左下角的坐标。请注意,由于历史原因,此函数返回 QPoint(left(), top() + height() - 1)。
QPoint QRect::bottomLeft() const

//返回矩形右上角的坐标。请注意,由于历史原因,此函数返回 QPoint(left() + width() - 1, top())。
QPoint QRect::topRight() const

// 返回矩形右下角的坐标。请注意,由于历史原因,此函数返回 QPoint(left() + width() - 1, top() + height() - 1)。
QPoint QRect::bottomRight() const

// 返回矩形的中心点。
QPoint QRect::center() const

获取尺寸

// 返回矩形的大小。
QSize QRect::size() const

4、移动矩形

// ******************************** 移动边 ********************************//
// 垂直移动矩形,使矩形的底边位于给定的 y 坐标。矩形的大小保持不变。
void QRect::moveBottom(int y)

// 垂直移动矩形,使矩形的顶部边缘位于给定的 y 坐标。矩形的大小保持不变。
void QRect::moveTop(int y)

// 水平移动矩形,使矩形的左边缘位于给定的 x 坐标。矩形的大小保持不变。
void QRect::moveLeft(int x)

// 水平移动矩形,使矩形的右边缘位于给定的 x 坐标。矩形的大小保持不变。
void QRect::moveRight(int x)

// ******************************** 移动点 ********************************//

// 移动矩形,使左下角保持在给定的位置。矩形的大小保持不变。
void QRect::moveBottomLeft(const QPoint &position)

// 移动矩形,使右下角保持在给定的位置。矩形的大小保持不变。
void QRect::moveBottomRight(const QPoint &position)


// 移动矩形,使左上角保持在给定的位置。矩形的大小保持不变。
void QRect::moveTopLeft(const QPoint &position)

// 移动矩形,使右上角保持在给定的位置。矩形的大小保持不变。
void QRect::moveTopRight(const QPoint &position)

// 移动矩形,使中心点保持在给定的位置。矩形的大小保持不变。
void QRect::moveCenter(const QPoint &position)

3.6 时间类

3.6.1 时间类 - QTime

QTime 类是 Qt 中用于处理时间(时、分、秒)的类,常用于存储、操作和比较时间。它不包含日期信息。

// 构造函数:创建时间对象
QTime::QTime(int hour, int minute, int second, int msec = 0)   // 使用时、分、秒、毫秒构造时间对象

// 获取时间的小时、分钟、秒、毫秒
QTime::hour()
QTime::minute()
QTime::second()
QTime::msec()

// 设置时间
QTime::setHMS(int hour, int minute, int second, int msec = 0) // 设置时、分、秒、毫秒

// 时间相加与相减
QTime::addMSecs(int msec)  // 返回增加指定毫秒数后的时间
QTime::addSecs(int secs)   // 返回增加指定秒数后的时间

// 时间比较
QTime::operator<(const QTime &other)
QTime::operator>(const QTime &other)
QTime::operator==(const QTime &other)
QTime::operator!=(const QTime &other)

// 获取当前时间
[static] QTime::currentTime()  // 返回系统当前的时间

// 时间转字符串
QTime::toString(const QString &format = "HH:mm:ss")  // 转换为字符串,支持自定义格式

// 判断时间是否有效
QTime::isValid()

示例程序

#include <QCoreApplication>
#include <QTime>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建时间对象,设置为 10:30:45
    QTime time(10, 30, 45);

    // 输出当前时间
    qDebug() << "当前时间:" << time.toString("HH:mm:ss");

    // 获取小时、分钟、秒、毫秒
    qDebug() << "小时:" << time.hour();
    qDebug() << "分钟:" << time.minute();
    qDebug() << "秒:" << time.second();
    qDebug() << "毫秒:" << time.msec();

    // 增加 120 秒
    QTime newTime = time.addSecs(120);
    qDebug() << "增加 120 秒后的时间:" << newTime.toString("HH:mm:ss");

    // 时间比较
    QTime anotherTime(12, 0, 0);
    if (time < anotherTime) {
        qDebug() << "time 小于 anotherTime";
    }

    return a.exec();
}

3.6.1 日期类 - QDate

QDate 类用于处理日期信息,支持常见的日期操作,包括获取当前日期、日期格式化、日期计算等。

// 获取当前日期
[static] QDate QDate::currentDate()

// 创建指定日期
QDate QDate::fromString(const QString &string, const QString &format = "yyyy-MM-dd")

// 判断日期是否合法
bool QDate::isValid() const

// 获取年份、月份、日期
int QDate::year() const
int QDate::month() const
int QDate::day() const

// 获取星期几(1:周一,7:周日)
int QDate::dayOfWeek() const

// 获取日期的天数
int QDate::daysInMonth() const
int QDate::daysInYear() const

// 判断是否是闰年
bool QDate::isLeapYear() const

// 比较日期
bool QDate::operator<(const QDate &other) const
bool QDate::operator==(const QDate &other) const

// 日期加减
QDate QDate::addDays(int days) const
QDate QDate::addMonths(int months) const
QDate QDate::addYears(int years) const

// 日期转换为字符串
QString QDate::toString(const QString &format = "yyyy-MM-dd") const

// 获取该日期是该年的第几天
int QDate::dayOfYear() const

// 获取 Unix 时间戳(自1970年1月1日起的秒数)
int QDate::toJulianDay() const

示例程序

#include <QCoreApplication>
#include <QDate>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 获取当前日期
    QDate currentDate = QDate::currentDate();
    qDebug() << "当前日期:" << currentDate.toString("yyyy-MM-dd");

    // 创建指定日期
    QDate dateFromString = QDate::fromString("2024-11-13", "yyyy-MM-dd");
    qDebug() << "指定日期:" << dateFromString.toString("yyyy-MM-dd");

    // 获取年份、月份、日期
    qDebug() << "年份:" << currentDate.year();
    qDebug() << "月份:" << currentDate.month();
    qDebug() << "日期:" << currentDate.day();

    // 判断是否是闰年
    qDebug() << "是否是闰年:" << currentDate.isLeapYear();

    // 获取星期几(1:周一,7:周日)
    qDebug() << "星期几:" << currentDate.dayOfWeek();

    // 加减日期
    QDate newDate = currentDate.addDays(5);  // 当前日期加 5 天
    qDebug() << "当前日期加5天:" << newDate.toString("yyyy-MM-dd");

    // 日期比较
    if (currentDate < dateFromString) {
        qDebug() << "当前日期早于指定日期";
    } else if (currentDate == dateFromString) {
        qDebug() << "当前日期等于指定日期";
    } else {
        qDebug() << "当前日期晚于指定日期";
    }

    return a.exec();
}

结果

当前日期: 2024-11-13
指定日期: 2024-11-13
年份: 2024
月份: 11
日期: 13
是否是闰年: true
星期几: 3
当前日期加5天: 2024-11-18
当前日期等于指定日期

第四章 信号与槽

4.1 信号与槽机制

信号与槽(Signal and Slot)是 Qt 框架中用于实现对象间通信的核心机制,能够使代码更易于维护和解耦。

4.1.1 信号与槽的基本概念

1、信号(Signal)

信号是在特定事件(如按钮点击)发生时发出的消息,声明事件的发生,无需实现具体功能。

在计算机中,常见的事件如下:

  • 按钮点击
  • 鼠标输入
  • 键盘输入

2、槽(Slot)

槽是一个可以响应信号的函数,当一个信号被发出时,与之相连的槽函数会被调用。

槽函数定义:槽函数通常是类的成员函数,开发者只需要定义好槽函数的逻辑,确保其能够处理信号所代表的事件。

槽函数触发:当信号发出后,Qt 的信号与槽机制会自动触发所有连接到该信号的槽函数,从而实现对事件的响应。

例如:

  假设你和朋友约好去看电影,朋友准时敲门,这就是**信号**;你听到敲门声后立刻出门,这就是**槽的反应**。

  在这个例子中:

  **朋友敲门**:是信号的发出,相当于某个事件的发生。

  **你出门**:是对信号的响应,相当于槽函数对信号的处理。

槽和普通函数的区别

槽函数是一种特殊的成员函数,用于响应信号的调用。它们与普通成员函数的区别主要有以下几点:

触发方式:槽函数是由信号触发的,而不是由程序员显式调用。当信号发出时,Qt会自动调用相应的槽函数。

自动响应:通过槽函数,Qt可以在信号发出时自动执行特定的代码逻辑,从而提高程序的模块化和响应性。

普通成员函数:普通成员函数需要手动调用,不具备与信号直接关联的特性,因此它们在处理事件时相对更为被动。

4.1.2 信号与槽的关系

信号与槽的关系可以理解为一种“发布-订阅”模式。当一个对象(信号发出者)发出信号时,所有连接到该信号的槽函数都会被调用。

为了更好地理解这种关系,可以参考以下示意图:

+-------------+       发出信号        +---------------+
|  信号发出者  | --------------------> |   信号接收者   |
| (Publisher) |                       |  (Subscriber) |
+-------------+                       +---------------+
       ^                                         |
       |                连接                      v
+-------------+                       +---------------+
|    信号     |       -------->       |     槽       |
+-------------+                       +---------------+

在这个图中,信号发出者通过信号将消息发布给接收者,接收者通过槽函数响应信号,从而完成事件的处理。这种机制使得多个对象可以对一个事件做出响应,形成了灵活的通信模式。

在Qt中,信号发出后,不限定一个特定的槽函数进行响应,而是可以同时有多个槽与信号相连。信号与槽机制的灵活性体现在:

  1. 一对多连接:一个信号可以连接到多个槽,当信号发出时,所有连接的槽都会依次被调用。
  2. 多对一连接:多个信号可以连接到同一个槽函数,这样当任一信号被发出时,该槽函数都会被调用。
  3. 多对多连接:多个信号可以连接到多个槽,形成复杂的通信网络。

这种信号与槽的连接方式极大地降低了对象之间的耦合度,使代码更具灵活性和可维护性。它不仅适用于简单的用户界面交互,还非常适合处理复杂的事件驱动场景。

4.1.3 信号与槽的连接方式

Qt提供了connect()函数用于将信号与槽连接,以实现对象之间的通信。它的函数原型如下:

QMetaObject::Connection QObject::connect(
        const QObject *sender, PointerToMemberFunction signal, 
        const QObject *receiver, PointerToMemberFunction method, 
        Qt::ConnectionType type = Qt::AutoConnection);
参数:
    sender:发出信号的对象。
    signal:指向信号函数的指针。
    receiver:接收信号的对象。
    method:指向槽函数的指针,当信号发出时调用该方法。

//  参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:
connect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::method);

断开连接

disconnect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::method);

在原型中的 PointerToMemberFunction 是一个函数指针,传递的是类中的函数。例如:

class MyClass {
public:
    void myFunction() {
        // 成员函数逻辑
    }
};

void (MyClass::*funcPtr)() = &MyClass::myFunction;

在上述代码中,funcPtr 是一个指向 MyClass 类中 myFunction 成员函数的指针。可以通过这种方式来定义和使用成员函数指针,并在 connect() 函数中进行信号与槽的连接。

示例代码

下面是一个简单的例子,演示如何使用信号与槽机制。

#include "mainwindow.h"
#include <QPushButton>
#include <QApplication>
#include <QObject>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    // 创建一个按钮
    QPushButton close_Button("close");
    // 让这个按钮显示
    close_Button.show();
    // 连接按钮 的 信号 和 槽函数
    QObject::connect(&close_Button , &QPushButton::clicked , &w , &MainWindow::close);

    return a.exec();
}

示例

#include "widget.h"
#include "ui_widget.h"
using namespace std;
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(ui->Log_in_Button , &QPushButton::clicked , this , &QWidget::close);

}

信号定义:在这个例子中,我们创建了一个按钮,当按钮被点击时,会发出一个信号(clicked())。

槽连接:这个信号通过 connect() 函数连接到 QWidget::close 槽函数,表示当用户点击按钮时,应用程序将退出。

也就是说,当用户点击按钮时,应用程序将退出。这展示了如何使用信号与槽机制将用户的操作与程序的逻辑响应关联起来。

在这个例子中,当用户点击按钮时,QPushButtonclicked()信号被触发,而与之连接的QWidget::close()槽函数被调用,从而退出应用程序。

4.1.4 信号与槽的特性

低耦合:信号与槽使得对象之间的耦合度非常低,发出信号的对象不需要知道槽的具体实现,这使得代码更加模块化。

  • 实例:比如按钮发出点击信号,而具体的槽函数可以是打开新窗口或显示消息提示,按钮不需要了解具体的响应逻辑。

线程安全:Qt的信号与槽机制是线程安全的,允许跨线程连接信号与槽,简化了多线程编程中的通信。

  • 应用场景:例如,在后台线程中处理数据完成后,可以通过信号通知主线程更新界面,确保线程安全的通信。

自动断开:当一个对象销毁时,它发出的所有信号连接都会被自动断开,避免悬空指针的问题。

  • 实例:当窗口关闭时,与之相关的所有信号和槽的连接都会自动断开,防止程序崩溃。

4.2 标准信号/槽

4.2.1 标准信号/槽

在 Qt 中,信号与槽机制是实现对象之间通信的基础。Qt 提供了许多内置的标准信号和槽,方便开发者快速实现常见的功能,而无需自定义信号与槽。

标准信号与槽是 Qt 框架的一部分,通常与常用控件(如按钮、文本框、窗口等)关联。这些标准信号和槽可以被直接使用,使开发者能够专注于业务逻辑而不必重复实现基础功能。

那如果我们需要使用标准信号与槽,那么,我们就必须要使用QT中的帮助文档来进行查阅,接下来我们就开始学习帮助文档的使用。

1、帮助文档的使用

创建完成工程后,点击 ==帮助== 用于打开帮助文档,然后将搜索方式改成 ==索引== , 最后在搜索框中输入想要检索的内容

qt的检索

2、如何阅读标准文档

当我们搜索了一个类之后,这里以 QAbstractButton 标准按钮类为例,会看到下面的内容

QT帮助文档介绍

如果在文档中 并没有看到 ==公共成员函数== 或者 ==公共槽函数== 或 ==信号== , 就可以去他的父对象中去找,因为子对象是完全继承父对象的内容的, 例如QPushButton 中 就没有 ==信号== 的内容,因为QPushButton的信号是继承了他父对象的。

4.2.2 标准信号与槽的使用

这里我们用 QPushButton 这个类,来介绍使用标准信号槽使用的两种方式。

1、使用 cnnect() 函数

在前面已经介绍过这个函数,那么我们现在就来看这个函数如何使用。

功能分析: 按下按钮
    - 按钮: 信号发出者          -> QPushButton 类型
    - 窗口: 信号的接收者和处理者  -> QWidget 类型
信号 和 槽函数
    // 单击按钮发出的信号
    [signal] void QAbstractButton::clicked(bool checked = false)
    // 关闭窗口的槽函数
    [slot] bool QWidget::close();
连接信号与槽
    // 单击按钮关闭窗口
    connect(ui->closewindow, &QPushButton::clicked, this, &MainWindow::close);

2、快捷方式

按钮是可以直接通过UI设计中的 ==右键== -> ==转到槽== -> ==clicked== 就会在对应的对象文件中产生一个函数

image-20241029135044869 image-20241029135102809

4.3 自定义信号/槽

在QT中提供了很多的标准信号槽,但是这些标准信号槽在特定一些特定的地方无法满足我们的需求,因此我们需要去自己设计信号槽,并使用 connect() 进行连接。

4.3.1 自定义信号与槽的条件

在 Qt 中自定义信号和槽时,需要注意以下内容

条件

  1. 派生自 Qt 的标准类
    • 需要编写一个新的类,并且该类必须继承自 Qt 的某些标准类,这样可以获得信号槽功能的支持。
  2. 继承自 QObject 类
    • 自定义信号和槽的类必须从 QObject 类或其子类派生,因为 Qt 的信号和槽机制依赖于 QObject 提供的元对象系统。
  3. 包含 Q_OBJECT
    • 在类的头文件中加入 Q_OBJECT 宏。这个宏是使用 Qt 元对象系统的必要条件,确保信号和槽的元数据可以被正确生成和使用。

注意事项:

  • 头文件的包含
    • 确保在类的头文件中包含必要的头文件,如 <QObject>,以便使用信号槽功能。
  • 信号只声明不定义
    • 自定义的信号只需要在类的头文件中声明,不需要在类的实现文件中定义,因为 Qt 的元对象系统会自动处理信号的实现。
// 在头文件派生类的时候,首先像下面那样引入Q_OBJECT宏:
class MyMainWindow : public QWidget
{
    Q_OBJECT
    ......
}

4.3.2 自定义信号

在 Qt 中,信号的本质是事件,但在框架中也是以函数的形式存在的,只不过信号对应的函数只有声明,没有定义。如果 Qt 中的标准信号不能满足我们的需求,可以在程序中进行信号的自定义。当自定义信号对应的事件产生之后,只需人为地将这个信号发射出去即可(其实就是调用一下这个信号函数)。

自定义信号的要求和注意事项

信号是类的成员函数

  • 自定义信号是类的成员函数,通常在类的 signals 区域中进行声明。

返回值必须是 void 类型

  • 信号的返回值必须是 void,因为信号仅用于通知,而不需要返回值。

信号的名称

  • 信号的名称可以根据实际需求指定,应反映信号所代表的事件。

信号的参数

  • 信号可以有任意参数,用于在触发信号时传递数据。信号也支持重载,即可以定义多个同名信号,只是参数不同。

使用 signals 关键字声明

  • 信号需要使用 signals 关键字进行声明,类似于 public 等访问控制关键字。

信号函数只需声明,无需定义

  • 信号函数只需在类中声明,不需要在实现文件中定义(没有函数体实现),Qt 的元对象系统会自动处理信号的实现。

发射自定义信号

  • 在程序中发射信号时,实际上就是调用信号函数。通常在调用信号函数前使用 emit 关键字,例如:emit customSignal();
  • emit 关键字只是显式地声明信号被发射,并没有特殊含义。底层实现中,emit 实际上是通过 #define emit 进行的,因此即使省略 emit 关键字,也可以直接调用信号函数。但为了代码可读性,建议使用 emit

格式

// 自定义信号
signals:
    void signalName();             // 无参数信号
    void signalName(int a);        // 带参数信号(重载)

// 手动发射信号
emit signalName();                // 发射无参数信号
emit signalName(42);              // 发射带参数信号

4.3.3 自定义槽

在 Qt 中,槽是用来处理信号的函数。除了使用 Qt 提供的标准槽函数之外,我们还可以根据需要自定义槽函数,以处理特定的业务逻辑。

自定义槽的要求和注意事项:

槽是类的成员函数

  • 自定义槽是类的成员函数,可以放在 public slotsprivate slotsprotected slots 区域中,具体取决于访问权限的需求。

槽的返回值通常为 void

  • 槽函数通常没有返回值,即返回类型为 void,因为它们主要用于响应信号。

槽的参数需与信号匹配

  • 自定义槽的参数应与连接的信号的参数匹配,以便能够接收从信号传递过来的数据。

使用 slots 关键字声明

  • 自定义槽需要使用 slots 关键字进行声明,这样 Qt 的元对象系统才能识别它是一个槽函数。

槽函数支持多种形式

  • Qt 中的槽函数可以是类的成员函数、全局函数、静态函数,甚至可以是 Lambda 表达式(匿名函数),从而提供灵活的方式来处理信号。
#include <QObject>
#include <QDebug>

// 自定义信号和槽示例类
class Test : public QObject
{
    Q_OBJECT

public:
    Test(QObject *parent = nullptr) : QObject(parent) {}

    void triggerSignals() {
        emit testSignal();            // 发射无参数信号
        emit testSignal(42);          // 发射带参数信号
    }

signals:
    void testSignal();            // 无参数信号
    void testSignal(int a);       // 带参数信号(重载)

public slots:
    void handleSignal() {
        qDebug() << "Custom slot without parameters called!";
    }

    void handleSignal(int value) {
        qDebug() << "Custom slot with parameter called! Value:" << value;
    }
};

// 主函数示例
int main() {
    Test test;

    // 连接自定义信号到自定义槽
    QObject::connect(&test, &Test::testSignal, &test, &Test::handleSignal);
    QObject::connect(&test, &Test::testSignal, &test, &Test::handleSignal);

    // 触发信号
    test.triggerSignals();

    return 0;
}

4.4 Lambda表达式

在 Qt 中,除了使用类成员函数作为槽,还可以使用 Lambda 表达式(匿名函数)来处理信号。这种方式非常灵活,尤其适用于需要临时处理信号的场景。

4.4.1 语法格式

Lambda表达式就是一个匿名函数, 语法格式如下:

[capture](params) opt -> ret {body;};
    - capture: 捕获列表
    - params: 参数列表
    - opt: 函数选项
    - ret: 返回值类型
    - body: 函数体

4.4.1 定义和调用

QPushButton *button = new QPushButton("Click Me");

// 使用 Lambda 表达式作为槽函数
QObject::connect(button, &QPushButton::clicked, [=]() {
    qDebug() << "Button clicked!";
});

4.5 扩展信号/槽

在 Qt 中,信号与槽机制支持灵活的连接方式,使得一个信号可以连接多个槽、一个槽可以连接多个信号,甚至可以将信号连接到另一个信号。这种机制增强了程序的可扩展性和灵活性。

一个信号连接多个槽

QPushButton *button = new QPushButton("Click Me");

// 连接同一个信号到不同的槽  处理顺序是随机的
QObject::connect(button, &QPushButton::clicked, []() {
    qDebug() << "槽 1:按钮被点击";
});
QObject::connect(button, &QPushButton::clicked, []() {
    qDebug() << "槽 2:执行其他操作";
});

一个槽连接多个信号

QPushButton *button1 = new QPushButton("Button 1");
QPushButton *button2 = new QPushButton("Button 2");

// 将不同的信号连接到同一个槽
QObject::connect(button1, &QPushButton::clicked, this ,[]() {
    qDebug() << "通用槽:处理 Button 1 点击";
});
QObject::connect(button2, &QPushButton::clicked, this ,[]() {
    qDebug() << "通用槽:处理 Button 2 点击";
});

第五章 常用类

5.1 定时器类

5.1.1 常用API

// 启动定时器,设置时间间隔(单位:毫秒)
[slot] void QTimer::start()
[slot] void QTimer::start(int msec)  // 使用默认时间间隔启动定时器

// 停止定时器
[slot] void QTimer::stop()

// 获取定时器的时间间隔(单位:毫秒)
QTimer::interval() const

// 设置定时器的时间间隔(单位:毫秒)
void QTimer::setInterval(int msec)

// 连接定时器超时信号
[signal] void QTimer::timeout()

示例程序

#include <QCoreApplication>
#include <QTimer>
#include <QDebug>

class MyClass : public QObject {
    Q_OBJECT

public:
    MyClass() {
        // 创建 QTimer 对象
        timer = new QTimer(this);

        // 设置定时器时间间隔为1000毫秒(1秒)
        timer->setInterval(1000);

        // 连接定时器的 timeout 信号到槽函数
        connect(timer, &QTimer::timeout, this, &MyClass::onTimeout);

        // 启动定时器
        timer->start();
    }

public slots:
    void onTimeout() {
        qDebug() << "定时器超时!";
    }

private:
    QTimer *timer;
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    MyClass obj;

    return app.exec();
}

5.2 图片类

这三者的主要功能区别如下:

  • QIcon 主要用于图标的显示与管理。
  • QPixmap 适用于显示图像,特别是在 UI 中显示图像,支持图像缩放和转换。
  • QImage 更侧重于图像的处理和操作,特别是像素级别的修改。

5.2.1 QIcon 图标类

// 添加图标文件,支持不同尺寸和状态
void QIcon::addFile(const QString &fileName, const QSize &size = QSize(), QIcon::Mode mode = Normal, QIcon::State state = Off)

// 获取指定尺寸和状态的图标 QPixmap
QPixmap QIcon::pixmap(const QSize &size, QIcon::Mode mode = Normal, QIcon::State state = Off) const

// 绘制图标到指定区域
void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment = Qt::AlignCenter, QIcon::Mode mode = Normal, QIcon::State state = Off) const

// 获取图标的实际尺寸
QSize QIcon::actualSize(const QSize &size, QIcon::Mode mode = Normal, QIcon::State state = Off) const

// 清除所有的图标文件
void QIcon::clear()

示例程序

#include <QCoreApplication>
#include <QIcon>
#include <QPixmap>
#include <QPainter>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 创建 QIcon 对象
    QIcon icon;

    // 添加图标文件(可以是本地文件路径或资源文件)
    icon.addFile(":/icons/icon.png", QSize(64, 64), QIcon::Normal, QIcon::Off);

    // 获取指定尺寸和状态的 QPixmap
    QPixmap pixmap = icon.pixmap(QSize(64, 64), QIcon::Normal, QIcon::Off);
    qDebug() << "获取的图标尺寸:" << pixmap.size();

    // 获取图标的实际尺寸(根据图标的内容和设置)
    QSize actualSize = icon.actualSize(QSize(64, 64), QIcon::Normal, QIcon::Off);
    qDebug() << "图标的实际尺寸:" << actualSize;

    // 判断图标是否为空
    if (icon.isNull()) {
        qDebug() << "图标为空!";
    } else {
        qDebug() << "图标已加载!";
    }

    // 清除所有的图标文件
    icon.clear();
    qDebug() << "图标已清除!";

    return app.exec();
}

5.2.2 QPixmap 图片类

// 从文件加载图像。
QPixmap::load(const QString &fileName)

// 将图像保存到文件。
QPixmap::save(const QString &fileName)

// 缩放图像。
QPixmap::scaled(int width, int height, Qt::AspectRatioMode mode = Qt::KeepAspectRatio)

// 获取图像的宽度和高度。
QPixmap::width() / QPixmap::height()

// 判断图像是否为空。
QPixmap::isNull()

// 将 QPixmap 转换为 QImage,便于像素级操作。
QPixmap::toImage()

示例程序

#include <QApplication>
#include <QLabel>
#include <QPixmap>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建 QPixmap 对象并加载图像
    QPixmap pixmap(":/images/sample_image.png");

    // 检查图像是否加载成功
    if (pixmap.isNull()) {
        qDebug() << "图像加载失败";
        return -1;
    }

    // 缩放图像
    QPixmap scaledPixmap = pixmap.scaled(200, 200, Qt::KeepAspectRatio);

    // 创建一个 QLabel 显示图像
    QLabel label;
    label.setPixmap(scaledPixmap);
    label.show();

    return app.exec();  
}

5.2.3 QImge 图片类

// 从文件加载图像。
QImage::load(const QString &fileName)

// 将图像保存到文件。
QImage::save(const QString &fileName)

// 转换图像格式。
QImage::convertToFormat(int format)

// 获取指定位置的像素值。
QImage::pixel(int x, int y)

// 设置指定位置的像素值。
QImage::setPixel(int x, int y, QRgb c)

// 获取图像的宽度和高度。
QImage::width() / QImage::height()

// 判断图像是否为空。
QImage::isNull()

示例程序

#include <QImage>
#include <QDebug>

int main() {
    // 创建一个 QImage 对象
    QImage image(100, 100, QImage::Format_RGB888);

    // 设置图像的像素为红色
    for (int x = 0; x < image.width(); ++x) {
        for (int y = 0; y < image.height(); ++y) {
            image.setPixel(x, y, qRgb(255, 0, 0));  // 设置为红色
        }
    }

    // 保存图像
    if (image.save("red_image.png")) {
        qDebug() << "图像保存成功";
    } else {
        qDebug() << "图像保存失败";
    }

    // 获取指定位置的像素值
    QRgb pixelColor = image.pixel(50, 50);
    qDebug() << "像素颜色 (50,50):" << pixelColor;

    return 0;
}

5.3 菜单项类

5.3.1 QMenu 菜单

// QMenu 常用 API

// 构造函数
QMenu(QWidget *parent = nullptr);                          // 创建空菜单
QMenu(const QString &title, QWidget *parent = nullptr);    // 创建带标题的菜单

// 添加菜单项
QAction* addAction(const QString &text);                   // 添加一个菜单项(文本)
QAction* addAction(const QIcon &icon, const QString &text); // 添加带图标的菜单项
QAction* addAction(QAction *action);                       // 添加已有的QAction到菜单中

// 添加分隔符
void addSeparator();                                       // 添加分隔符

// 添加子菜单
QMenu* addMenu(const QString &title);                      // 添加子菜单(返回子菜单指针)
QMenu* addMenu(QMenu *menu);                                // 将已有QMenu添加为子菜单

// 设置菜单标题
void setTitle(const QString &title);                       // 设置菜单的标题

// 设置菜单图标
void setIcon(const QIcon &icon);                           // 设置菜单的图标

// 显示菜单
QAction* exec(const QPoint &pos);                          // 弹出菜单并在指定位置显示

// 显示菜单(全局位置)
QAction* exec(const QPoint &pos, QAction *atAction);       // 弹出菜单并在指定位置或指定动作处显示

// 检查菜单是否为空
bool isEmpty() const;                                      // 检查菜单是否为空

// 清空菜单
void clear();                                              // 清空菜单中的所有动作和子菜单

// 设置菜单的可见性
void setVisible(bool visible);                             // 显示或隐藏菜单

// 启用/禁用菜单
void setEnabled(bool enabled);                             // 启用或禁用菜单(禁用菜单项不可点击)

// 监听菜单项被触发的信号
Q_SIGNAL void triggered(QAction *action);                   // 当菜单项被选择时触发

// 监听菜单即将被隐藏的信号
Q_SIGNAL void aboutToHide();                               // 在菜单即将被隐藏时发出

// 监听菜单被显示的信号
Q_SIGNAL void aboutToShow();                               // 在菜单即将被显示时发出

5.3.2 QAction 菜单项

// QAction 常用 API

// 构造函数
QAction(QObject *parent = nullptr);                              // 构造一个没有文本和图标的动作
QAction(const QString &text, QObject *parent = nullptr);         // 构造一个带文本的动作
QAction(const QIcon &icon, const QString &text, QObject *parent = nullptr); // 构造一个带图标和文本的动作

// 设置和获取文本
void setText(const QString &text);                               // 设置菜单项的文本
QString text() const;                                            // 获取菜单项的文本

// 设置和获取图标
void setIcon(const QIcon &icon);                                 // 设置菜单项的图标
QIcon icon() const;                                              // 获取菜单项的图标

// 设置和获取快捷键
void setShortcut(const QKeySequence &shortcut);                  // 设置菜单项的快捷键
QKeySequence shortcut() const;                                   // 获取菜单项的快捷键

// 设置和获取提示文本(状态栏显示)
void setStatusTip(const QString &tip);                           // 设置状态栏提示文本
QString statusTip() const;                                       // 获取状态栏提示文本

// 设置和获取工具提示
void setToolTip(const QString &tip);                             // 设置工具提示文本
QString toolTip() const;                                         // 获取工具提示文本

// 触发动作
    void trigger();                                                  // 手动触发该动作

// 连接信号
Q_SIGNAL void triggered(bool checked = false);                   // 该信号在动作被触发时发出
void connectTriggered(const QObject *receiver, const char *method); // 连接触发信号到槽函数

// 设置和获取是否可见
void setVisible(bool visible);                                   // 设置动作是否可见
bool isVisible() const;                                          // 获取动作是否可见

// 设置和获取是否启用
void setEnabled(bool enabled);                                   // 启用或禁用动作
bool isEnabled() const;                                          // 获取动作是否启用

// 设置和获取检查状态
void setCheckable(bool checkable);                               // 设置动作是否为可检查(可以显示勾选框)
bool isCheckable() const;                                        // 获取动作是否为可检查
void setChecked(bool checked);                                   // 设置动作的检查状态
bool isChecked() const;                                          // 获取动作的检查状态

// 设置和获取动作的唯一标识符
void setData(const QVariant &data);                              // 设置动作的附加数据
QVariant data() const;                                           // 获取动作的附加数据

5.3.3 示例程序

// 创建菜单
QMenu *menu = new QMenu(this);

// 创建多个 QAction(菜单项)
QAction *openAction = new QAction("打开", this);
QAction *saveAction = new QAction("保存", this);
QAction *exitAction = new QAction("退出", this);

// 添加到菜单中
menu->addAction(openAction);
menu->addAction(saveAction);
menu->addAction(exitAction);

// 连接信号与槽函数
connect(openAction, &QAction::triggered, this, &MainWindow::onOpenClicked);
connect(saveAction, &QAction::triggered, this, &MainWindow::onSaveClicked);
connect(exitAction, &QAction::triggered, this, &MainWindow::onExitClicked);

// 弹出菜单 显示   QCursor::pos() 跟随鼠标位置
menu->exec(QCursor::pos());

5.4 文件类

5.4.1 QFile 文件类

QFile 是 Qt 中用于文件操作的类,继承自 QIODevice。它提供了对文本文件、二进制文件及资源文件的读写功能,支持跨平台操作(如 Windows、Linux、macOS)。

1、常用API

// 构造函数
QFile(const QString &name);  // 通过文件路径构造 QFile 对象

// 打开文件
bool open(QIODevice::OpenMode mode);  // 打开文件,需指定模式
    QIODevice::ReadOnly         只读
    QIODevice::WriteOnly        只写(覆盖原有内容)
    QIODevice::ReadWrite        读写
    QIODevice::Append           追加模式
    QIODevice::Text             以文本模式处理换行符(如 `\n` 转换为 `\r\n`)

// 读写操作
qint64 read(char *data, qint64 maxSize);    // 读取数据到缓冲区
QByteArray readAll();                       // 读取全部内容
qint64 write(const char *data, qint64 len); // 写入数据

// 关闭文件
void close();  // 显式关闭文件

// 文件信息查询
bool exists() const;          // 文件是否存在
QString fileName() const;     // 获取文件名
qint64 size() const;          // 获取文件大小

// 错误处理
QString errorString() const;  // 获取最后一次错误的描述

2、使用示例

示例 1:文本文件读写

// 写入文本文件
QFile file("test.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    QTextStream out(&file);
    out << "Hello, Qt!";
    file.close();
}

// 读取文本文件
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    QTextStream in(&file);
    QString content = in.readAll();
    qDebug() << "File content:" << content;
    file.close();
}

示例 2:二进制文件操作

QFile binFile("data.bin");
// 写入二进制数据
if (binFile.open(QIODevice::WriteOnly)) {
    QDataStream out(&binFile);
    out << 123 << 3.14 << "Binary Data";
    binFile.close();
}

// 读取二进制数据
if (binFile.open(QIODevice::ReadOnly)) {
    QDataStream in(&binFile);
    int num;
    double pi;
    QString str;
    in >> num >> pi >> str;
    qDebug() << "Read:" << num << pi << str;
    binFile.close();
}

示例 3:资源文件访问

// 访问 Qt 资源系统中的文件(需在 .qrc 中定义)
QFile resFile(":/files/icon.png");
if (resFile.open(QIODevice::ReadOnly)) {
    QByteArray data = resFile.readAll();
    // 处理图片数据...
    resFile.close();
}

第六章 QT窗口类

本章节主要是对QT中的一系列窗口类进行介绍,包括的内容有

6.1 QWidget

QWidget 是 Qt 框架中所有用户界面对象的基类,提供了基本的窗口和控件功能。QWidget 可以是一个窗口、容器或具体的 UI 控件,几乎所有的可视化控件类(如按钮、标签、文本框等)都直接或间接继承自 QWidget。它是构建用户界面的基础。

基础窗口类

6.1.1 设置父对象

在 Qt 中,控件可以通过设置父对象来建立层次结构,从而方便地管理控件的生命周期和事件传播。以下是与设置父对象相关的构造函数和成员函数:

// 构造函数
QWidget::QWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());

// 公共成员函数
// 设置当前控件的父对象
void QWidget::setParent(QWidget *parent);
void QWidget::setParent(QWidget *parent, Qt::WindowFlags f);

// 获取当前控件的父对象,如果没有父对象则返回 nullptr 
QWidget *QWidget::parentWidget() const;

6.1.2 窗口位置

//------------- 窗口位置 -------------
// 获取包含窗口边框的控件几何信息,相对于屏幕或父控件
QRect QWidget::frameGeometry() const;

// 获取不包含窗口边框的控件几何信息
const QRect &QWidget::geometry() const;

// 设置控件的几何信息(位置和尺寸),不包含窗口边框
void QWidget::setGeometry(int x, int y, int w, int h);
void QWidget::setGeometry(const QRect &rect);

// 移动控件到指定位置
void QWidget::move(int x, int y);
void QWidget::move(const QPoint &point);

6.1.3 窗口尺寸

//------------- 窗口尺寸 -------------

// 获取当前窗口的尺寸信息
QSize size() const;

// 获取当前窗口的宽度和高度
int width() const;
int height() const;

// 获取窗口的最小尺寸信息
QSize minimumSize() const;
int minimumWidth() const;
int minimumHeight() const;

// 获取窗口的最大尺寸信息
QSize maximumSize() const;
int maximumWidth() const;
int maximumHeight() const;

// 重新设置窗口的尺寸
void resize(int w, int h);
void resize(const QSize &size);

// 设置窗口的固定尺寸(无法调整)
void setFixedSize(int w, int h);
void setFixedSize(const QSize &size);

// 设置窗口的最小尺寸
void setMinimumSize(int minw, int minh);
void setMinimumSize(const QSize &size);
void setMinimumWidth(int minw);
void setMinimumHeight(int minh);

// 设置窗口的最大尺寸
void setMaximumSize(int maxw, int maxh);
void setMaximumSize(const QSize &size);
void setMaximumWidth(int maxw);
void setMaximumHeight(int maxh);

// 设置窗口的固定宽度和高度(分别)
void setFixedWidth(int w);
void setFixedHeight(int h);

6.1.4 标题和图标

//------------- 窗口图标 -------------
// 获取当前窗口的图标
QIcon windowIcon() const;

// 设置当前窗口的图标
void setWindowIcon(const QIcon &icon);

// 创建图标对象(参数为图片的路径)
QIcon::QIcon(const QString &fileName);

//------------- 窗口标题 -------------
// 获取当前窗口的标题
QString windowTitle() const;

// 设置当前窗口的标题
void setWindowTitle(const QString &title);

6.1.5 信号

//------------- 右键菜单策略 -------------
// 设置窗口的右键菜单策略
void QWidget::setContextMenuPolicy(Qt::ContextMenuPolicy policy);

// 获取窗口的右键菜单策略
Qt::ContextMenuPolicy QWidget::contextMenuPolicy() const;

// 当设置为 Qt::CustomContextMenu 时,按下鼠标右键会发射此信号
[signal] void QWidget::customContextMenuRequested(const QPoint &pos);

//------------- 窗口相关信号 -------------
// 当窗口图标发生变化时,发射此信号
[signal] void QWidget::windowIconChanged(const QIcon &icon);

// 当窗口标题发生变化时,发射此信号
[signal] void QWidget::windowTitleChanged(const QString &title);

6.1.6 槽函数

窗口显示

//------------- 窗口显示 -------------
// 关闭当前窗口
[slot] bool QWidget::close();

// 隐藏当前窗口
[slot] void QWidget::hide();

// 显示当前窗口及其子窗口
[slot] void QWidget::show();

// 全屏显示当前窗口
[slot] void QWidget::showFullScreen();

// 最大化显示当前窗口
[slot] void QWidget::showMaximized();

// 最小化显示当前窗口
[slot] void QWidget::showMinimized();

// 恢复窗口到正常状态(退出最大化或最小化)
[slot] void QWidget::showNormal();

窗口状态

//------------- 窗口状态 -------------
// 判断窗口是否启用
bool QWidget::isEnabled() const;

// 设置窗口是否启用,禁用的窗口无法接收和处理事件
// 参数 true 表示启用,false 表示禁用
[slot] void QWidget::setEnabled(bool enabled);

// 设置窗口是否禁用,禁用的窗口无法接收和处理事件
// 参数 true 表示禁用,false 表示启用
[slot] void QWidget::setDisabled(bool disabled);

// 设置窗口是否可见
// 参数 true 表示可见,false 表示不可见
[slot] virtual void QWidget::setVisible(bool visible);

// 判断窗口是否可见
bool QWidget::isVisible() const;

6.1.7 示例程序

1、窗口设置

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置图标
    setWindowIcon(QIcon(".\\img\\头像图标.png"));
    // 设置标题
    setWindowTitle("小道士");


    // 设置窗口最大尺寸
    setMaximumSize(1000 , 1000);
    // 设置窗口最小尺寸
    setMinimumSize(100 , 100);
    // 设置窗口固定尺寸
    setFixedSize(500 , 500);


}

Widget::~Widget()
{
    delete ui;
}

2、右键菜单

#include "widget.h"
#include "ui_widget.h"‘
#include <QDebug>
#include <QMenu>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget) 
{
    ui->setupUi(this);

    // 修改窗口图标信号
    connect(this , &QWidget::windowIconChanged , [](){
        qDebug() << "修改了图片";
    });
    // 修改窗口标题信号
    connect(this , &QWidget::windowIconChanged , [](){
        qDebug() << "修改了图片";
    });
    // 右键信号  展示菜单
    setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this , &QWidget::customContextMenuRequested , this , [=](const QPoint &pos){
        // 构建一个菜单对象
        QMenu menu;
        // 添加菜单项
        menu.addAction("添加");
        menu.addAction("删除");
        menu.addAction("重载");
        // 显示菜单项
        menu.exec(QCursor::pos());
    });


}

Widget::~Widget()
{
    delete ui;
}

// 修改图标按钮
void Widget::on_IconButton_clicked()
{
    // 修改图标
    setWindowIcon(QIcon(".\\img\\头像图标.png"));
}
// 修改标题按钮
void Widget::on_textButton_clicked()
{
    // 修改标题
    setWindowTitle("新图标");

}

保存

6.2 QMainWindow

QMainWindow中的结构较为复杂,一般用于创建应用程序的主界面。它提供了一个标准的窗口布局,包含以下预定义区域:

菜单栏:一个界面只能有一个,位于窗口的最上方,用于放置应用程序的菜单项。

状态栏:一个界面只能有一个,位于窗口的最下方,显示应用程序的状态信息。

工具栏:可以有多个,默认提供一个,可以在 上下左右 进行停靠 ,可添加常用操作的快捷按钮。

停靠窗口:可以有多个, 默认没有提供, 窗口的上下左右都可以停靠,用于承载辅助功能面板,如属性编辑器、导航栏等。

中央部件:一个界面只能有一个,位于窗口的中心区域。

具体分布如图所示

QMainWindow窗口介绍

6.2.1 菜单栏

1、添加菜单项

在QMainWindow 类中 可以通过双击点击的方式 创建菜单栏

image-20241112153236211

在下面的菜单项输入时,不能进行中文输入,这里就有几种方法进行解决

1、直接复制中文进入

(&F) : 增加快捷键提示 , 可以通过 Alt + F 进行快捷操作

2、创建QAction对象

image-20241112153722612

3、通过代码的方式添加菜单和菜单项

// 给菜单栏添加菜单
QAction *QMenuBar::addMenu(QMenu *menu);
QMenu *QMenuBar::addMenu(const QString &title);
QMenu *QMenuBar::addMenu(const QIcon &icon, const QString &title);

// 给菜单对象添加菜单项(QAction)
QAction *QMenu::addAction(const QString &text);
QAction *QMenu::addAction(const QIcon &icon, const QString &text);

// 添加分割线
QAction *QMenu::addSeparator();

2、触发事件

// 点击QAction对象发出该信号
[signal] void QAction::triggered(bool checked = false);

示例程序

// save_action 是某个菜单项对象名, 点击这个菜单项会弹出一个对话框
connect(ui->save_action, &QAction::triggered, this, [=]()
{
      QMessageBox::information(this, "Triggered", "我是菜单项, 你不要调戏我...");
});

3、使用示例

#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QMessageBox>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr)
        : QMainWindow(parent)
    {
        // 创建菜单栏
        QMenuBar *menuBar = this->menuBar(); // 获取 QMainWindow 的菜单栏

        // 创建"文件"菜单
        QMenu *fileMenu = new QMenu("文件", this); // 创建一个菜单,菜单名为"文件"

        // 创建菜单项(动作)
        QAction *newAction = new QAction("新建", this);
        QAction *openAction = new QAction("打开", this);
        QAction *exitAction = new QAction("退出", this);

        // 将动作添加到"文件"菜单
        fileMenu->addAction(newAction);
        fileMenu->addAction(openAction);
        fileMenu->addAction(exitAction);

        // 将"文件"菜单添加到菜单栏
        menuBar->addMenu(fileMenu);

        // 连接信号和槽
        connect(newAction, &QAction::triggered, this, &MainWindow::onNewClicked);
        connect(openAction, &QAction::triggered, this, &MainWindow::onOpenClicked);
        connect(exitAction, &QAction::triggered, this, &MainWindow::onExitClicked);
    }

private slots:
    void onNewClicked() {
        QMessageBox::information(this, "新建", "点击了新建菜单项");
    }

    void onOpenClicked() {
        QMessageBox::information(this, "打开", "点击了打开菜单项");
    }

    void onExitClicked() {
        QApplication::quit(); // 退出应用程序
    }
};

6.2.2 状态栏

1、添加控件

// 类型: QStatusBar

// 将指定的控件 widget 添加到状态栏的最右侧。
// 参数:
//   widget - 要添加的控件,例如 QLabel、QProgressBar 等。
//   stretch - 控件的伸缩因子,默认为 0。较大的值会占据更多空间。
void QStatusBar::addWidget(QWidget *widget, int stretch = 0);

// 在指定的索引位置 index 插入控件 widget。
// 参数:
//   index - 插入的位置索引,从 0 开始,0 表示最左侧。
//   widget - 要插入的控件。
//   stretch - 控件的伸缩因子,默认为 0。
int QStatusBar::insertWidget(int index, QWidget *widget, int stretch = 0);

// 从状态栏中移除指定的控件 widget。
// 参数:
//   widget - 要移除的控件。
void QStatusBar::removeWidget(QWidget *widget);

// 清除当前显示的状态栏消息。
// 此方法是一个槽函数,可以连接到信号以自动清除消息。
[slot] void QStatusBar::clearMessage();

// 在状态栏上显示指定的文本 message,持续时间为 timeout 毫秒。
// 参数:
//   message - 要显示的文本消息。
//   timeout - 消息显示的时间(毫秒),默认为 0 表示永久显示。
//   如果设置了超时,时间一到消息会自动清除。
[slot] void QStatusBar::showMessage(const QString &message, int timeout = 0);

2、示例程序

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 创建状态栏
    QStatusBar *statusBar = this->statusBar();

    // 创建一个标签控件,并设置初始文本
    QLabel *statusLabel = new QLabel("初始状态", this);
    statusBar->addWidget(statusLabel);  // 将标签添加到状态栏

    // 创建一个按钮控件
    QPushButton *statusButton = new QPushButton("点击我", this);
    statusBar->addWidget(statusButton); // 将按钮添加到状态栏

    // 连接按钮点击信号到槽函数,用于更改标签内容
    connect(statusButton, &QPushButton::clicked, this, [=]() {
        statusLabel->setText("按钮已点击"); // 更改标签文本
    });
}

6.2.3 工具栏

1、添加工具按钮

1、直接拖入

image-20241114021923791

2、通过API 构造

// 在QMainWindow窗口中添加工具栏
void QMainWindow::addToolBar(Qt::ToolBarArea area, QToolBar *toolbar);
void QMainWindow::addToolBar(QToolBar *toolbar);
QToolBar *QMainWindow::addToolBar(const QString &title);

// 将Qt控件放到工具栏中
// 工具栏类: QToolBar
// 添加的对象只要是QWidget或者启子类都可以被添加
QAction *QToolBar::addWidget(QWidget *widget);

// 添加QAction对象
QAction *QToolBar::addAction(const QString &text);
QAction *QToolBar::addAction(const QIcon &icon, const QString &text);

// 添加分隔线
QAction *QToolBar::addSeparator()

示例程序

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 创建工具栏
    QToolBar *toolBar = addToolBar("工具栏");  // 添加工具栏,名称为"工具栏"

    // 添加到菜单中
    // this->addToolBar(Qt::LeftToolBarArea, toolBar);

    // 创建 QAction(工具栏按钮)
    QAction *newAction = new QAction( "新建", this);  // 设置图标和文本
    QAction *openAction = new QAction( "打开", this);
    QAction *saveAction = new QAction( "保存", this);
    QAction *exitAction = new QAction( "退出", this);

    // 将 QAction 添加到工具栏
    toolBar->addAction(newAction);
    toolBar->addAction(openAction);
    toolBar->addAction(saveAction);
    toolBar->addAction(exitAction);

    //

    // 添加按钮组件
    toolBar->addWidget(new QPushButton("搜索"));
    // 单行输入组件
    QLineEdit* edit = new QLineEdit;
    edit->setMaximumWidth(200);
    edit->setFixedWidth(100);
    toolBar->addWidget(edit);
}

2、参数设置

在UI窗口的树状列表中, 找到工具栏节点, 就可以到的工具栏的属性设置面板了, 这样就可以根据个人需求对工具栏的属性进行设置和修改了。

image-20241114024326217

image-20241114024731230

6.2.4 停靠窗口

通过拖动停靠窗口 防止在我们的设计页面中就可以生成停靠窗口了

image-20241114030216837

浮动窗口的属性

image-20241114030529177

floating:是否作为浮动窗口显示。
features:设置允许的操作(如关闭、移动、浮动)。
allowedAreas:限制可停靠的区域(左、右、上、下)。
windowTitle:窗口的标题。
dockWidgetArea:当前停靠的区域(只读)。
docked:当前是否处于停靠状态。

6.3 QDialog

QDialog 是 Qt 中用于创建对话框窗口的基类。对话框通常用于短期任务和与用户的简短交互,例如获取用户输入、显示消息或询问确认等。QDialog 提供了丰富的接口来控制对话框的行为和外观。

6.3.1 模态

在 Qt 中,对话框可以是 模态(Modal) 的,也可以是 非模态(Modeless) 的。它们的区别在于模态对话框会阻塞用户对其他窗口的输入,而非模态对话框则不会。

1、模态对话框

模态对话框在显示时,会阻塞用户对其他窗口的输入,直到对话框被关闭。这通常用于需要用户立即处理的关键任务,例如确认删除操作、输入密码等。

创建方法

使用 exec() 方法:以模态方式显示对话框,阻塞调用线程,直到对话框关闭。

QDialog dialog(this);
dialog.setWindowTitle("模态对话框");
int result = dialog.exec();
// 根据 result 处理结果

2、非模态

非模态对话框在显示时,不会阻塞用户对其他窗口的输入。用户可以在对话框打开的同时与其他窗口进行交互。这通常用于需要长时间运行或不需要立即处理的任务。

创建方法

使用 show() 方法:以非模态方式显示对话框,调用后立即返回,程序继续执行。

QDialog *dialog = new QDialog(this);
dialog->setWindowTitle("非模态对话框");
dialog->show();

注意: 创建非模态对话框时,最好将对话框对象分配在堆上(使用 new),以防止对象在超出作用域后被销毁。

6.3.2 API介绍

1、构造函数

// 构造函数
QDialog::QDialog(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());

2、公共函数

// 判断尺寸调节柄是否启用 
bool QDialog::isSizeGripEnabled() const

// 设置是否启用尺寸调节柄   <不能用>
void QDialog::setSizeGripEnabled(bool)

// 判断 show 是否模态显示   exec
bool QDialog::isModal() const
// 设置 show 是否模态显示
void QDialog::setModal(bool modal)


// 设置模态对话框的结果代码为 i。
void QDialog::setResult(int i)

调节柄 : 表示是否可以通过鼠标调节大小

3、槽函数

// 模态显示窗口
[virtual slot] int QDialog::exec();
// 隐藏模态窗口, 并且解除模态窗口的阻塞, 将 exec() 的返回值设置为 QDialog::Accepted  接受
[virtual slot] void QDialog::accept();
// 隐藏模态窗口, 并且解除模态窗口的阻塞, 将 exec() 的返回值设置为 QDialog::Rejected  拒绝
[virtual slot] void QDialog::reject();
// 关闭对话框并将其结果代码设置为r。finished()信号将发出r;
// 如果r是QDialog::Accepted 或 QDialog::Rejected,则还将分别发出 accept() 或 Rejected()信号。
[virtual slot] void QDialog::done(int r);

4、信号

[signal] void QDialog::accepted();  // 接受
[signal] void QDialog::rejected();  // 拒绝
[signal] void QDialog::finished(int result);    // 自定义 done 方法控制

6.3.3 示例程序

image-20241112214708533

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::on_acceptButton_clicked()
{
    accept();
}

void Dialog::on_rejectButton_clicked()
{
    reject();
}
```c++
#include "widget.h"
#include "ui_widget.h"
#include "dialog.h"
#include <QDebug>
#include <QMenu>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 定义一个对话框
    Dialog D;
    // 模态显示对话框
    int i = D.exec();

    // 对话框结束的结果
    qDebug() << "结果:" << i;

}

Widget::~Widget()
{
    delete ui;
}

6.4 QDialog子类

QDialog是Qt框架中用于创建对话框窗口的基类。通过继承QDialog,Qt提供了多种预定义的对话框子类,方便开发者在应用中实现常见的对话框功能。

6.4.1 QColorDialog 颜色对话框

QColorDialog提供了一个标准的颜色选择对话框,允许用户从调色板中选择颜色或自定义颜色值,常用于需要用户指定颜色的场景。

1、Color颜色类

// 构造函数
QColor::QColor(Qt::GlobalColor color);
QColor::QColor(int r, int g, int b, int a = ...);
QColor::QColor();

// 参数设置 red, green, blue, alpha, 取值范围都是 0-255
void QColor::setRed(int red);       // 红色
void QColor::setGreen(int green);   // 绿色
void QColor::setBlue(int blue);     // 蓝色
void QColor::setAlpha(int alpha);   // 透明度, 默认不透明(255)
void QColor::setRgb(int r, int g, int b, int a = 255);

int QColor::red() const;
int QColor::green() const;
int QColor::blue() const;
int QColor::alpha() const;
void QColor::getRgb(int *r, int *g, int *b, int *a = nullptr) const;

2、QColorDialog颜色窗口类

  // 弹出颜色选择对话框, 并返回选中的颜色信息
/*
参数:
    - initial: 对话框中默认选中的颜色, 用于窗口初始化
    - parent: 给对话框窗口指定父对象
    - title: 对话框窗口的标题
    - options: 颜色对话框窗口选项, 使用默认属性即可, 一般不需要设置
*/
  [static] QColor QColorDialog::getColor(
        const QColor &initial = Qt::white, 
        QWidget *parent = nullptr, const QString &title = QString(), 
        QColorDialog::ColorDialogOptions options = ColorDialogOptions());

示例程序

    // 文件对话框
    // 让用户选择颜色
    QColor col = QColorDialog::getColor(Qt::white, this, "选择颜色");

    // 如果用户选择了有效颜色(点击了OK),则设置 QLabel 的字体颜色
    if (col.isValid()) {
        ui->label->setStyleSheet(QString("color: %1;").arg(col.name()));
    }

设置字体颜色

void MainWindow::on_colordlg_clicked()
{
    // 打开颜色选择对话框,用户可以选择颜色
    QColor color = QColorDialog::getColor();

    // 创建一个 QBrush 对象,填充所选颜色
    QBrush brush(color);

    // 创建一个矩形区域,尺寸与 ui->color 控件的尺寸相同
    QRect rect(0, 0, ui->color->width(), ui->color->height());

    // 创建一个 QPixmap 对象,用于在控件上绘制颜色
    QPixmap pix(rect.width(), rect.height());

    // 创建一个 QPainter 对象,开始在 QPixmap 上绘制
    QPainter p(&pix);

    // 使用填充的画刷填充矩形区域
    p.fillRect(rect, brush);

    // 设置 ui->color 控件的图片为填充后的 QPixmap
    ui->color->setPixmap(pix);

    // 创建一个包含颜色的 RGB 值和透明度的字符串
    QString text = QString("red: %1, green: %2, blue: %3, 透明度: %4")
            .arg(color.red())  // 获取红色分量
            .arg(color.green()) // 获取绿色分量
            .arg(color.blue())  // 获取蓝色分量
            .arg(color.alpha()); // 获取透明度(Alpha)分量

    // 设置 ui->colorlabel 控件的文本,显示颜色的详细信息
    ui->colorlabel->setText(text);
}

6.4.3 QFileDialog 文件对话框

QFileDialog提供了一个标准的文件打开和保存对话框,允许用户浏览文件系统,选择文件或目录,常用于文件操作相关的功能。

1、常用API

/*
通用参数:
  - parent: 当前对话框窗口的父对象也就是父窗口
  - caption: 当前对话框窗口的标题
  - dir: 当前对话框窗口打开的默认目录
  - options: 当前对话框窗口的一些可选项,枚举类型, 一般不需要进行设置, 使用默认值即可
  - filter: 过滤器, 在对话框中只显示满足条件的文件, 可以指定多个过滤器, 使用 ;; 分隔
    - 样式举例: 
    - Images (*.png *.jpg)
    - Images (*.png *.jpg);;Text files (*.txt)
  - selectedFilter: 如果指定了多个过滤器, 通过该参数指定默认使用哪一个, 不指定默认使用第一个过滤器
*/
// 打开一个目录, 得到这个目录的绝对路径
[static] QString QFileDialog::getExistingDirectory(
                  QWidget *parent = nullptr, 
                  const QString &caption = QString(), 
                  const QString &dir = QString(), 
                  QFileDialog::Options options = ShowDirsOnly);

// 打开一个文件, 得到这个文件的绝对路径
[static] QString QFileDialog::getOpenFileName(
                  QWidget *parent = nullptr, 
              const QString &caption = QString(), 
                  const QString &dir = QString(), 
                  const QString &filter = QString(), 
                  QString *selectedFilter = nullptr, 
                  QFileDialog::Options options = Options());

// 打开多个文件, 得到这多个文件的绝对路径
[static] QStringList QFileDialog::getOpenFileNames(
                  QWidget *parent = nullptr, 
                  const QString &caption = QString(), 
                  const QString &dir = QString(), 
                  const QString &filter = QString(), 
                  QString *selectedFilter = nullptr, 
                  QFileDialog::Options options = Options());

// 打开一个目录, 使用这个目录来保存指定的文件  保存
[static] QString QFileDialog::getSaveFileName(
              QWidget *parent = nullptr, 
                  const QString &caption = QString(), 
                  const QString &dir = QString(), 
                  const QString &filter = QString(), 
                  QString *selectedFilter = nullptr, 
                  QFileDialog::Options options = Options());

2、示例程序

打开一个存在本地的目录

void MainWindow::on_filedlg_clicked()
{
    QString dirName = QFileDialog::getExistingDirectory(this, "打开目录", "e:\\temp");
    QMessageBox::information(this, "打开目录", "您选择的目录是: " + dirName);
}

打开一个文件

void MainWindow::on_filedlg_clicked()
{
    QString arg("Text files (*.txt)");
    QString fileName = QFileDialog::getOpenFileName(
              this, "Open File", "e:\\temp",
              "Images (*.png *.jpg);;Text files (*.txt)", &arg);
    QMessageBox::information(this, "打开文件", "您选择的文件是: " + fileName);
}

打开多个文件

void MainWindow::on_filedlg_clicked()
{
    QStringList fileNames = QFileDialog::getOpenFileNames(
              this, "Open File", "e:\\temp",
              "Images (*.png *.jpg);;Text files (*.txt)");
    QString names;
    for(int i=0; i<fileNames.size(); ++i)
    {
        names += fileNames.at(i) + " ";
    }
    QMessageBox::information(this, "打开文件(s)", "您选择的文件是: " + names);
}

打开保存文件对话框

void MainWindow::on_filedlg_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, "保存文件", "e:\\temp");
    QMessageBox::information(this, "保存文件", "您指定的保存数据的文件是: " + fileName);
}

6.4.4 QFontDialog 字体对话框

QFontDialog提供了一个标准的字体选择对话框,用户可以通过它选择字体家族、样式和大小等属性,适用于需要用户设置字体的应用场景。

1、QFont 字体类

关于字体的属性信息, 在QT框架中被封装到了一个叫QFont的类中, 下边为大家介绍一下这个类的API, 了解一下关于这个类的使用。

// 构造函数
  QFont::QFont();
  /*
  参数:
    - family: 本地字库中的字体名, 通过 office 等文件软件可以查看
    - pointSize: 字体的字号
    - weight: 字体的粗细, 有效范围为 0 ~ 99
    - italic: 字体是否倾斜显示, 默认不倾斜
  */
  QFont::QFont(const QString &family, int pointSize = -1, int weight = -1, bool italic = false);

  // 设置字体
  void QFont::setFamily(const QString &family);
  // 根据字号设置字体大小
  void QFont::setPointSize(int pointSize);
  // 根据像素设置字体大小
  void QFont::setPixelSize(int pixelSize);
  // 设置字体的粗细程度, 有效范围: 0 ~ 99
  void QFont::setWeight(int weight);
  // 设置字体是否加粗显示
  void QFont::setBold(bool enable);
  // 设置字体是否要倾斜显示
  void QFont::setItalic(bool enable);

  // 获取字体相关属性(一般规律: 去掉设置函数的 set 就是获取相关属性对应的函数名)
  QString QFont::family() const;
  bool QFont::italic() const;
  int QFont::pixelSize() const;
  int QFont::pointSize() const;
  bool QFont::bold() const;
  int QFont::weight() const;


// QWidget 类
// 得到当前窗口使用的字体
const QWidget::QFont& font() const;
// 给当前窗口设置字体, 只对当前窗口类生效
void QWidget::setFont(const QFont &);

// QApplication 类
// 得到当前应用程序对象使用的字体
[static] QFont QApplication::font();
// 给当前应用程序对象设置字体, 作用于当前应用程序的所有窗口
[static] void QApplication::setFont(const QFont &font, const char *className = nullptr);

2、QFontDialog 字体对话框

/*
参数:
  - ok: 传出参数, 用于判断是否获得了有效字体信息, 指定一个布尔类型变量地址
  - initial: 字体对话框中默认选中并显示该字体信息, 用于对话框的初始化
  - parent: 字体对话框窗口的父对象
  - title: 字体对话框的窗口标题
  - options: 字体对话框选项, 使用默认属性即可, 一般不设置
*/

[static] QFont QFontDialog::getFont(
    bool *ok, 
    const QFont &initial, 
    QWidget *parent = nullptr, 
    const QString &title = QString(), 
    QFontDialog::FontDialogOptions options = FontDialogOptions());

[static] QFont QFontDialog::getFont(
      bool *ok, 
      QWidget *parent = nullptr);

3、示例程序

void MainWindow::on_fontdlg_clicked()
{
#if 1
    // 方式1
    bool ok;
    QFont ft = QFontDialog::getFont(
                &ok, QFont("微软雅黑", 12, QFont::Bold), this, "选择字体");
    qDebug() << "ok value is: " << ok;
#else
    // 方式2
    QFont ft = QFontDialog::getFont(NULL);
#endif
    // 将选择的字体设置给当前窗口对象
    this->setFont(ft);
}

6.4.5 QInputDialog 输入对话框

QInputDialog是一个简易的输入对话框,用于从用户处获取简单的文本、整数或浮点数输入,适合于需要用户输入单一值的情况。

1、API介绍

// 得到一个可以输入浮点数的对话框窗口, 返回对话框窗口中输入的浮点数
/*
参数:
  - parent: 对话框窗口的父窗口
  - title: 对话框窗口显示的标题信息
  - label: 对话框窗口中显示的文本信息(用于描述对话框的功能)
  - value: 对话框窗口中显示的浮点值, 默认为 0
  - min: 对话框窗口支持显示的最小数值
  - max: 对话框窗口支持显示的最大数值
  - decimals: 浮点数的精度, 默认保留小数点以后1位
  - ok: 传出参数, 用于判断是否得到了有效数据, 一般不会使用该参数
  - flags: 对话框窗口的窗口属性, 使用默认值即可
*/
[static] double QInputDialog::getDouble(
            QWidget *parent, const QString &title, 
            const QString &label, double value = 0, 
            double min = -2147483647, double max = 2147483647, 
            int decimals = 1, bool *ok = nullptr, 
            Qt::WindowFlags flags = Qt::WindowFlags());

// 得到一个可以输入整形数的对话框窗口, 返回对话框窗口中输入的整形数
/*
参数:
  - parent: 对话框窗口的父窗口
  - title: 对话框窗口显示的标题信息
  - label: 对话框窗口中显示的文本信息(用于描述对话框的功能)
  - value: 对话框窗口中显示的整形值, 默认为 0
  - min: 对话框窗口支持显示的最小数值
  - max: 对话框窗口支持显示的最大数值
  - step: 步长, 通过对话框提供的按钮调节数值每次增长/递减的量
  - ok: 传出参数, 用于判断是否得到了有效数据, 一般不会使用该参数
  - flags: 对话框窗口的窗口属性, 使用默认值即可
*/
[static] int QInputDialog::getInt(
            QWidget *parent, const QString &title, 
            const QString &label, int value = 0, 
            int min = -2147483647, int max = 2147483647, 
            int step = 1, bool *ok = nullptr, 
            Qt::WindowFlags flags = Qt::WindowFlags());

// 得到一个带下来菜单的对话框窗口, 返回选择的菜单项上边的文本信息
/*
参数:
  - parent: 对话框窗口的父窗口
  - title: 对话框窗口显示的标题信息
  - label: 对话框窗口中显示的文本信息(用于描述对话框的功能)
  - items: 字符串列表, 用于初始化窗口中的下拉菜单, 每个字符串对应一个菜单项
  - current: 通过菜单项的索引指定显示下拉菜单中的哪个菜单项, 默认显示第一个(编号为0)
  - editable: 设置菜单项上的文本信息是否可以进行编辑, 默认为true, 即可以编辑
  - ok: 传出参数, 用于判断是否得到了有效数据, 一般不会使用该参数
  - flags: 对话框窗口的窗口属性, 使用默认值即可
  - inputMethodHints: 设置显示模式, 默认没有指定任何特殊显示格式, 显示普通文本字符串
    - 如果有特殊需求, 可以参数帮助文档进行相关设置
*/
[static] QString QInputDialog::getItem(
            QWidget *parent, 
            const QString &title, 
            const QString &label, 
            const QStringList &items, 
            int current = 0, bool editable = true, bool *ok = nullptr, 
            Qt::WindowFlags flags = Qt::WindowFlags(), 
            Qt::InputMethodHints inputMethodHints = Qt::ImhNone);

// 得到一个可以输入多行数据的对话框窗口, 返回用户在窗口中输入的文本信息
/*
参数:
  - parent: 对话框窗口的父窗口
  - title: 对话框窗口显示的标题信息
  - label: 对话框窗口中显示的文本信息(用于描述对话框的功能)
  - text: 指定显示到多行输入框中的文本信息, 默认是空字符串
  - ok: 传出参数, 用于判断是否得到了有效数据, 一般不会使用该参数
  - flags: 对话框窗口的窗口属性, 使用默认值即可
  - inputMethodHints: 设置显示模式, 默认没有指定任何特殊显示格式, 显示普通文本字符串
    - 如果有特殊需求, 可以参数帮助文档进行相关设置
*/
[static] QString QInputDialog::getMultiLineText(
            QWidget *parent, 
            const QString &title, 
            const QString &label, 
            const QString &text = QString(), 
            bool *ok = nullptr, 
            Qt::WindowFlags flags = Qt::WindowFlags(), 
            Qt::InputMethodHints inputMethodHints = Qt::ImhNone);

// 得到一个可以输入单行信息的对话框窗口, 返回用户在窗口中输入的文本信息
/*
参数:
  - parent: 对话框窗口的父窗口 
  - title: 对话框窗口显示的标题信息
  - label: 对话框窗口中显示的文本信息(用于描述对话框的功能)
  - mode: 指定单行编辑框中数据的反馈模式, 是一个 QLineEdit::EchoMode 类型的枚举值
    - QLineEdit::Normal: 显示输入的字符。这是默认值
    - QLineEdit::NoEcho: 不要展示任何东西。这可能适用于连密码长度都应该保密的密码。
    - QLineEdit::Password: 显示与平台相关的密码掩码字符,而不是实际输入的字符。
    - QLineEdit::PasswordEchoOnEdit: 在编辑时按输入显示字符,否则按密码显示字符。
  - text: 指定显示到单行输入框中的文本信息, 默认是空字符串
  - ok: 传出参数, 用于判断是否得到了有效数据, 一般不会使用该参数
  - flags: 对话框窗口的窗口属性, 使用默认值即可
  - inputMethodHints: 设置显示模式, 默认没有指定任何特殊显示格式, 显示普通文本字符串
     - 如果有特殊需求, 可以参数帮助文档进行相关设置
*/
[static] QString QInputDialog::getText(
            QWidget *parent, const QString &title, const QString &label,
            QLineEdit::EchoMode mode = QLineEdit::Normal, 
            const QString &text = QString(), bool *ok = nullptr, 
            Qt::WindowFlags flags = Qt::WindowFlags(), 
            Qt::InputMethodHints inputMethodHints = Qt::ImhNone);

2、示例程序

整形输入

void MainWindow::on_inputdlg_clicked()
{
    // 打开一个整型输入对话框,获取用户输入的年龄
    int ret = QInputDialog::getInt(this, "年龄", "您的当前年龄: ", 10, 1, 100, 2);

    // 弹出信息框显示用户输入的年龄
    QMessageBox::information(this, "年龄", "您的当前年龄: " + QString::number(ret));
}

浮点型输入

void MainWindow::on_inputdlg_clicked()
{
    // 打开一个浮点型输入对话框,获取用户输入的工资
    double ret = QInputDialog::getDouble(this, "工资", "您的工资: ", 2000, 1000, 6000, 2);

    // 弹出信息框显示用户输入的工资
    QMessageBox::information(this, "工资", "您的当前工资: " + QString::number(ret));
}

带下拉的输入框

void MainWindow::on_inputdlg_clicked()
{
    // 创建一个字符串列表,包含多个水果选项
    QStringList items;
    items << "苹果" << "橙子" << "橘子" << "葡萄" << "香蕉" << "哈密瓜";

    // 打开一个带下拉框的输入对话框,用户选择一个水果
    QString item = QInputDialog::getItem(this, "请选择你喜欢的水果", "你最喜欢的水果:", items, 1, false);

    // 弹出信息框显示用户选择的水果
    QMessageBox::information(this, "水果", "您最喜欢的水果是: " + item);
}

多行字符串输入框

void MainWindow::on_inputdlg_clicked()
{
    // 打开一个多行文本输入对话框,获取用户的输入
    QString info = QInputDialog::getMultiLineText(this, "表白", "您最想对漂亮小姐姐说什么呢?", "呦吼吼...");

    // 弹出信息框显示用户输入的表白内容
    QMessageBox::information(this, "知心姐姐", "您最想对小姐姐说: " + info);
}

单行字符串输入框

void MainWindow::on_inputdlg_clicked()
{
    // 打开一个单行文本输入对话框,获取用户输入的密码
    QString text = QInputDialog::getText(this, "密码", "请输入新的密码", QLineEdit::Password, "helloworld");

    // 弹出信息框显示用户输入的密码
    QMessageBox::information(this, "密码", "您设置的密码是: " + text);
}

6.4.6 QMessageBox 消息对话框

QMessageBox用于显示信息、警告、错误或询问等消息的对话框,支持多种预定义的按钮,便于与用户进行简单的交互。

1、常用API

// 显示一个模态对话框, 将参数 text 的信息展示到窗口中
[static] void QMessageBox::about(QWidget *parent, const QString &title, const QString &text);

/*
参数:
- parent: 对话框窗口的父窗口
- title: 对话框窗口的标题
- text: 对话框窗口中显示的提示信息
- buttons: 对话框窗口中显示的按钮(一个或多个)
- defaultButton
    1. defaultButton指定按下Enter键时使用的按钮。
    2. defaultButton必须引用在参数 buttons 中给定的按钮。
    3. 如果defaultButton是QMessageBox::NoButton, QMessageBox会自动选择一个合适的默认值。
*/
// 显示一个信息模态对话框
[static] QMessageBox::StandardButton QMessageBox::information(
           QWidget *parent, const QString &title, 
           const QString &text, 
           QMessageBox::StandardButtons buttons = Ok,
           QMessageBox::StandardButton defaultButton = NoButton);

// 显示一个错误模态对话框
[static] QMessageBox::StandardButton QMessageBox::critical(
           QWidget *parent, const QString &title, 
           const QString &text, 
           QMessageBox::StandardButtons buttons = Ok,
           QMessageBox::StandardButton defaultButton = NoButton);

// 显示一个问题模态对话框
[static] QMessageBox::StandardButton QMessageBox::question(
           QWidget *parent, const QString &title, 
           const QString &text, 
           QMessageBox::StandardButtons buttons = StandardButtons(Yes | No), 
           QMessageBox::StandardButton defaultButton = NoButton);

// 显示一个警告模态对话框
[static] QMessageBox::StandardButton QMessageBox::warning(
           QWidget *parent, const QString &title, 
           const QString &text, 
           QMessageBox::StandardButtons buttons = Ok,
           QMessageBox::StandardButton defaultButton = NoButton);

示例程序

#include <QMessageBox>
#include <QWidget>
#include <QPushButton>
#include <QCoreApplication>

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 创建一个父窗口
    QWidget parentWidget;

    // 显示关于窗口
    QMessageBox::about(&parentWidget, "About My Application", "This is a sample Qt application.");

    // 显示关于 Qt 窗口
    QMessageBox::aboutQt(&parentWidget);

    // 显示错误信息弹窗
    QMessageBox::critical(&parentWidget, "Error", "An unexpected error occurred!");

    // 显示信息弹窗
    QMessageBox::information(&parentWidget, "Information", "This is an information message.");

    // 显示询问弹窗
    QMessageBox::StandardButton reply = QMessageBox::question(&parentWidget, "Confirm", "Do you want to continue?");
    if (reply == QMessageBox::Yes) {
        qDebug() << "User chose Yes";
    } else {
        qDebug() << "User chose No";
    }

    // 显示警告信息弹窗
    QMessageBox::warning(&parentWidget, "Warning", "This is a warning message!");

    return app.exec();
}

2、示例程序

void MainWindow::on_msgbox_clicked()
{
    QMessageBox::about(this, "about",  "这是一个简单的消息提示框!!!");
    QMessageBox::critical(this, "critical", "这是一个错误对话框-critical...");
    int ret = QMessageBox::question(this, "question", 
             "你要保存修改的文件内容吗???",                                 
              QMessageBox::Save|QMessageBox::Cancel, 
              QMessageBox::Cancel);
    if(ret == QMessageBox::Save)
    {
        QMessageBox::information(this, "information", "恭喜你保存成功了, o(* ̄︶ ̄*)o!!!");
    }
    else if(ret == QMessageBox::Cancel)
    {
        QMessageBox::warning(this, "warning", "你放弃了保存, ┭┮﹏┭┮ !!!");
    }
}

6.4.7 QProgressDialog 进度对话框

QProgressDialog提供了一个进度条对话框,常用于显示长时间任务的执行进度,并可选择性地提供取消操作。

1、API介绍

// 构造函数
/*
参数:
  - labelText: 对话框中显示的提示信息
  - cancelButtonText: 取消按钮上显示的文本信息
  - minimum: 进度条最小值
  - maximum: 进度条最大值
  - parent: 当前窗口的父对象
  - f: 当前进度窗口的flag属性, 使用默认属性即可, 无需设置
*/
QProgressDialog::QProgressDialog(
    QWidget *parent = nullptr, 
    Qt::WindowFlags f = Qt::WindowFlags());

QProgressDialog::QProgressDialog(
    const QString &labelText, 
    const QString &cancelButtonText, 
    int minimum,
    int maximum,
    QWidget *parent = nullptr,
    Qt::WindowFlags f = Qt::WindowFlags());


// 设置取消按钮显示的文本信息
[slot] void QProgressDialog::setCancelButtonText(const QString &cancelButtonText);

// 公共成员函数和槽函数
QString QProgressDialog::labelText() const;                 // 获取对话框中显示的提示信息
void QProgressDialog::setLabelText(const QString &text);    // 设置对话框中显示的提示信息

// 得到进度条最小值
int QProgressDialog::minimum() const;
// 设置进度条最小值
void QProgressDialog::setMinimum(int minimum);

// 得到进度条最大值
int QProgressDialog::maximum() const;
// 设置进度条最大值
void QProgressDialog::setMaximum(int maximum);

// 设置进度条范围(最大和最小值)
[slot] void QProgressDialog::setRange(int minimum, int maximum);

// 得到进度条当前的值
int QProgressDialog::value() const;
// 设置进度条当前的值
void QProgressDialog::setValue(int progress);


bool QProgressDialog::autoReset() const;
// 当value() = maximum()时,进程对话框是否调用reset(),此属性默认为true。
void QProgressDialog::setAutoReset(bool reset);


bool QProgressDialog::autoClose() const;
// 当value() = maximum()时,进程对话框是否调用reset()并且隐藏,此属性默认为true。
void QProgressDialog::setAutoClose(bool close);

// 判断用户是否按下了取消键, 按下了返回true, 否则返回false
bool wasCanceled() const;


// 重置进度条
// 重置进度对话框。wascancelled()变为true,直到进程对话框被重置。进度对话框被隐藏。
[slot] void QProgressDialog::cancel();
// 重置进度对话框。如果autoClose()为真,进程对话框将隐藏。
[slot] void QProgressDialog::reset();   

// 信号
// 当单击cancel按钮时,将发出此信号。默认情况下,它连接到cancel()槽。
[signal] void QProgressDialog::canceled();

// 设置窗口的显示状态(模态, 非模态)
/*
参数:
    Qt::NonModal  -> 非模态
    Qt::WindowModal -> 模态, 阻塞父窗口
    Qt::ApplicationModal -> 模态, 阻塞应用程序中的所有窗口
*/
void QWidget::setWindowModality(Qt::WindowModality windowModality);

2、示例程序

void MainWindow::on_progressdlg_clicked()
{
    // 1. 创建进度条对话框窗口对象
    QProgressDialog *progress = new QProgressDialog(
                "正在拷贝数据...", "取消拷贝", 0, 100, this);
    // 2. 初始化并显示进度条窗口
    progress->setWindowTitle("请稍后");
    progress->setWindowModality(Qt::WindowModal);
    progress->show();

    // 3. 更新进度条
    static int value = 0;
    QTimer *timer = new QTimer;
    connect(timer, &QTimer::timeout, this, [=]()
    {
         progress->setValue(value);
         value++;
         // 当value > 最大值的时候
         if(value > progress->maximum())
         {
             timer->stop();
             value = 0;
             delete progress;
             delete timer;
         }
    });

    connect(progress, &QProgressDialog::canceled, this, [=]()
    {
        timer->stop();
        value = 0;
        delete progress;
        delete timer;
    });

    timer->start(50);
}

6.5 修改窗口背景

6.5.1 简单方案

1、显示静态图片

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    // 解决 Qt 高分辨率屏幕显示错误问题
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);    // 启用高 DPI 缩放支持
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);       // 启用高 DPI 位图支持

    QApplication a(argc, argv);
    MainWindow w;
// HTML CSS JS 前段技术    
    // 方案一 : 通过AI 直接帮你写
    // 方案二 : 通过查看帮助文档
    // 设置背景图片及大小
    w.setStyleSheet(
        "MainWindow {"
        "   background-image: url(:/img/img_11.png);"       // 图片路径
        "   background-repeat: no-repeat;"                  // 不重复显示图片
        "   background-position: center;"                   // 居中显示
        "   background-size: cover;"                       // 背景图片适配窗口
        "}"
    );
    // "   background-size: 1000px 1000px;"                  // 背景图片适配窗口 <不能用>


    w.show();
    return a.exec();
}

2、显示动态图片和静态图片自适应

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMovie>
#include <QLabel>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    QLabel *backgroundLabel;        // 增加一个 QLabel 的类

protected:
    void resizeEvent(QResizeEvent *event) override; // 重写 resizeEvent
private:
    Ui::MainWindow *ui;

};
#endif // MAINWINDOW_H
```c++
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QMovie>
#include <QLabel>
#include <QPixmap>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

//    // 创建背景 QLabel 和 GIF 动画
//    backgroundLabel = new QLabel(this);
//    QMovie *movie = new QMovie(":/img/gif-1.gif");

//    // 设置 GIF 动画到 QLabel
//    backgroundLabel->setMovie(movie);
//    backgroundLabel->setGeometry(this->rect()); // 填满整个窗口
//    backgroundLabel->setScaledContents(true);  // 自动拉伸适配窗口大小
//    backgroundLabel->lower();                  // 将背景设置到最底层

//    // 启动 GIF 动画
//    movie->start();

        // 创建背景 QLabel 和 图片
        backgroundLabel = new QLabel(this);
        QPixmap pix(":/img/img_11.png");

        // 设置 GIF 动画到 QLabel
        backgroundLabel->setPixmap(pix);
        backgroundLabel->setGeometry(this->rect()); // 填满整个窗口
        backgroundLabel->setScaledContents(true);  // 自动拉伸适配窗口大小
        backgroundLabel->lower();                  // 将背景设置到最底层


}

MainWindow::~MainWindow()
{
    delete ui;
}

// 重写 resizeEvent 函数   事件函数
void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);           // 调用基类的 resizeEvent 方法
    backgroundLabel->setGeometry(this->rect()); // 根据窗口大小调整背景 QLabel 的尺寸
}

6.5.2 复杂方案<不推荐 不稳定>

backgroundmanager.h

#ifndef BACKGROUNDMANAGER_H
#define BACKGROUNDMANAGER_H

#include <QWidget>
#include <QMovie>
#include <QPixmap>
#include <QPainter>

class BackgroundManager {
public:
    explicit BackgroundManager(QWidget *targetWidget); // 绑定目标窗口
    ~BackgroundManager();

    // 设置动态背景
    void setGifBackground(const QString &gifPath);

    // 设置静态背景
    void setStaticBackground(const QString &imagePath);

    // 设置固定宽度并保持宽高比
    void setFixedWidthWithAspectRatio(int fixedWidth);

    // 绘制背景
    void paintBackground(QPainter &painter);

private:
    QWidget *targetWidget;  // 目标窗口
    QPixmap background;     // 静态背景图片
    QMovie *movie;          // 动态背景动图
    double aspectRatio;     // 背景图片宽高比
};

#endif // BACKGROUNDMANAGER_H

backgroundmanager.h

#include "backgroundmanager.h"

BackgroundManager::BackgroundManager(QWidget *targetWidget)
    : targetWidget(targetWidget), movie(nullptr), aspectRatio(16.0 / 9.0) {
    targetWidget->setAttribute(Qt::WA_NoSystemBackground); // 禁用系统背景
    targetWidget->setAutoFillBackground(false);            // 禁用自动填充背景
}

BackgroundManager::~BackgroundManager() {
    if (movie) {
        delete movie;
    }
}

// 设置动态背景
void BackgroundManager::setGifBackground(const QString &gifPath) {
    if (movie) {
        delete movie; // 清理之前的动图对象
        movie = nullptr;
    }

    movie = new QMovie(gifPath);
    if (movie->isValid()) {
        movie->start();
        aspectRatio = static_cast<double>(movie->currentPixmap().width()) / movie->currentPixmap().height();

        // 动态更新每一帧
        QObject::connect(movie, &QMovie::frameChanged, targetWidget, [this]() {
            targetWidget->repaint(); // 强制刷新窗口
        });
    } else {
        delete movie;
        movie = nullptr;
        qWarning("Invalid GIF file: %s", qPrintable(gifPath));
    }
}

// 设置静态背景
void BackgroundManager::setStaticBackground(const QString &imagePath) {
    if (movie) {
        delete movie; // 如果之前加载了动图,清理它
        movie = nullptr;
    }

    QPixmap pixmap(imagePath);
    if (!pixmap.isNull()) {
        background = pixmap;
        aspectRatio = static_cast<double>(background.width()) / background.height();
    } else {
        qWarning("Invalid static image file: %s", qPrintable(imagePath));
    }
    targetWidget->update(); // 强制重绘
}

// 设置固定宽度并保持宽高比
void BackgroundManager::setFixedWidthWithAspectRatio(int fixedWidth) {
    int calculatedHeight = static_cast<int>(fixedWidth / aspectRatio);
    targetWidget->setFixedSize(fixedWidth, calculatedHeight); // 设置固定宽度和高度
}

// 绘制背景
void BackgroundManager::paintBackground(QPainter &painter) {
    // 清除之前的内容,用背景色填充整个窗口
    painter.fillRect(targetWidget->rect(), Qt::white);

    // 绘制背景到窗口的底层,不影响子控件
    if (movie && movie->isValid()) {
        QPixmap currentFrame = movie->currentPixmap();
        painter.drawPixmap(0, 0, targetWidget->width(), targetWidget->height(), currentFrame);
    } else if (!background.isNull()) {
        painter.drawPixmap(0, 0, targetWidget->width(), targetWidget->height(), background);
    }
}

使用方法

.h

  • 引入背景管理器类
  • 重写 paintEvent
  • 背景管理器指针
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "backgroundmanager.h" // 引入背景管理器类

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void paintEvent(QPaintEvent *event) override; // 重写 paintEvent

private:
    Ui::MainWindow *ui;
    BackgroundManager *backgroundManager; // 背景管理器指针
};

#endif // MAINWINDOW_H

.c

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "backgroundmanager.h" // 引入背景管理器

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{

    ui->setupUi(this);

    backgroundManager = new BackgroundManager(this); // 初始化背景管理器

    // 设置动态背景(GIF 文件路径根据实际资源调整)
    backgroundManager->setGifBackground(":/img/gif-1.gif");

    // 如果需要静态背景,可使用如下代码:
    // backgroundManager->setStaticBackground(":/img/img_1.png");
    // 设置固定宽度(例如 800 像素),保持宽高比
    backgroundManager->setFixedWidthWithAspectRatio(800);
}

MainWindow::~MainWindow()
{
    delete ui;
    delete backgroundManager; // 清理背景管理器
}

// 重写 paintEvent 以绘制背景
void MainWindow::paintEvent(QPaintEvent *event) {
    QPainter painter(this);

    // 使用背景管理器绘制背景
    backgroundManager->paintBackground(painter);

    // 调用父类的 paintEvent,以确保子控件正常显示
    QMainWindow::paintEvent(event);
}

第七章 窗口布局

image-20241114132125923

7.1 UI 布局操作

在UI中是可以通过布局操作来实现布局的,可以分为两种方法,如下

7.1.1 控件布局

1、工具箱

直接从工具箱中找到布局,然后直接拖到UI窗口中,再将控件放入到控件中,如下

image-20241114132125923

2、右键菜单

直接布局

右键布局设置

修改布局

右键布局设置_2

此外窗口布局会有一些属性,如下

image-20241117123358680

布局约束参数

// Qt 布局大小约束参数说明

// 1. SetDefaultConstraint
// 默认约束:布局不会施加额外的大小限制,控件会使用自己的 sizeHint()。
QLayout::SetDefaultConstraint;

// 2. SetNoConstraint
// 无约束:布局对控件的大小不施加任何限制,完全自由调整。
QLayout::SetNoConstraint;

// 3. SetMinimumSize
// 最小约束:布局会确保控件的大小至少为其 minimumSize()。
QLayout::SetMinimumSize;

// 4. SetFixedSize
// 固定尺寸:布局会强制控件保持固定的大小,无法调整。
QLayout::SetFixedSize;

// 5. SetMaximumSize
// 最大约束:布局会限制控件的大小不超过其 maximumSize()。
QLayout::SetMaximumSize;

// 6. SetMinAndMaxSize
// 同时设置最小和最大约束:控件的大小被锁定在 minimumSize() 和 maximumSize() 范围内。
QLayout::SetMinAndMaxSize;

7.1.2 容器布局

布局方式如下

容器布局设置_1

7.2 UI 间隔器操作

image-20241117121747572

参数说明

image-20241117121926127

image-20241117122257168

7.3 API 布局操作

除了通过UI 来进行布局 我们还会通过API 操作的方式 进行布局,所用的类如下

QHBoxLayout     // 水平布局
QVBoxLayout     // 垂直布局
QGridLayout     // 网格(栅格)布局

继承关系如下

image-20241117124232271

7.3.1 水平和垂直

1、API 说明

// 在布局最后面添加一个窗口
void QLayout::addWidget(QWidget *w);
// 将某个窗口对象从布局中移除, 窗口对象如果不再使用需要自己析构
void QLayout::removeWidget(QWidget *widget);
// 设置布局的四个边界大小, 即: 左、上、右和下的边距。
void QLayout::setContentsMargins(int left, int top, int right, int bottom);
// 设置布局中各个窗口之间的间隙大小
void setSpacing(int);

2、示例程序 - 水平布局 QHBoxLayout

// 创建符窗口对象
QWidget *window = new QWidget;
// 创建若干个子窗口对象
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");

// 创建水平布局对象
QHBoxLayout *layout = new QHBoxLayout;
// 将子窗口添加到布局中
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
layout->addWidget(button4);
layout->addWidget(button5);

// 将水平布局设置给父窗口对象
window->setLayout(layout);
// 显示父窗口
window->show();

2、示例程序 - 水平布局 QVBoxLayout

// 创建符窗口对象
QWidget *window = new QWidget;
// 创建若干个子窗口对象
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");

// 创建垂直布局对象
QVBoxLayout *layout = new QVBoxLayout;
// 将子窗口添加到布局中
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
layout->addWidget(button4);
layout->addWidget(button5);

// 将水平布局设置给父窗口对象
window->setLayout(layout);
// 显示父窗口
window->show();

7.3.2 网格

1、API说明

// 构造函数
QGridLayout::QGridLayout();
QGridLayout::QGridLayout(QWidget *parent);

// 添加窗口对象到网格布局中
/*
参数:
  - widget: 添加到布局中的窗口对象
  - row: 添加到布局中的窗口对象位于第几行 (从0开始)
  - column: 添加到布局中的窗口对象位于第几列 (从0开始)
  - alignment: 窗口在布局中的对齐方式, 没有特殊需求使用默认值即可
*/
void QGridLayout::addWidget(
    QWidget *widget, int row, int column, 
Qt::Alignment alignment = Qt::Alignment());

/*
参数:
  - widget: 添加到布局中的窗口对象
  - fromRow: 添加到布局中的窗口对象位于第几行 (从0开始)
  - fromColumn: 添加到布局中的窗口对象位于第几列 (从0开始)
  - rowSpan: 添加的窗口从 fromRow 行开始跨越的行数
  - columnSpan: 添加的窗口从 fromColumn 列开始跨越的列数
  - alignment: 窗口在布局中的对齐方式, 没有特殊需求使用默认值即可
*/
void QGridLayout::addWidget(
QWidget *widget, int fromRow, int fromColumn, 
int rowSpan, int columnSpan, 
Qt::Alignment alignment = Qt::Alignment());

// 设置 column 对应的列的最新宽度, 单位: 像素
void QGridLayout::setColumnMinimumWidth(int column, int minSize);

// 设置布局中水平方向窗口之间间隔的宽度
void QGridLayout::setHorizontalSpacing(int spacing);

// 设置布局中垂直方向窗口之间间隔的宽度
void QGridLayout::setVerticalSpacing(int spacing);

2、示例程序

// 创建父窗口对象
QWidget* window = new QWidget;
// 创建子窗口对象
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");
QPushButton *button6 = new QPushButton("Six");
// 多行文本编辑框
QTextEdit* txedit = new QTextEdit;
txedit->setText("我占用了两行两列的空间哦。");

QGridLayout* layout = new QGridLayout;
// 按钮起始位置: 第1行, 第1列, 该按钮占用空间情况为1行1列
layout->addWidget(button1, 0, 0);
// 按钮起始位置: 第1行, 第2列, 该按钮占用空间情况为1行1列
layout->addWidget(button2, 0, 1);
// 按钮起始位置: 第1行, 第3列, 该按钮占用空间情况为1行1列
layout->addWidget(button3, 0, 2);
// 编辑框起始位置: 第2行, 第1列, 该按钮占用空间情况为2行2列
layout->addWidget(txedit, 1, 0, 2, 2);
// 按钮起始位置: 第2行, 第3列, 该按钮占用空间情况为1行1列
layout->addWidget(button4, 1, 2);
// 按钮起始位置: 第3行, 第3列, 该按钮占用空间情况为1行1列
layout->addWidget(button5, 2, 2);
// 按钮起始位置: 第4行, 第1列, 该按钮占用空间情况为1行3列
layout->addWidget(button6, 3, 0, 1, 3);

// 网格布局设置给父窗口对象
window->setLayout(layout);
// 显示父窗口
window->show();  

第八章 常用的操作

8.1 资源文件

创建资源文件的方式

image-20241114030911767

image-20241114030947600

创建完成后就可以开始去添加文件了