
🎬 个人主页 :艾莉丝努力练剑
❄专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:

文章目录
- [1 ~> 创建Qt的Hello World程序](#1 ~> 创建Qt的Hello World程序)
-
- [1.1 使用"按钮"实现](#1.1 使用“按钮”实现)
-
- [1.1.1 纯代码方式实现](#1.1.1 纯代码方式实现)
- [1.1.2 可视化操作实现](#1.1.2 可视化操作实现)
- [1.2 使用"标签"实现](#1.2 使用“标签”实现)
-
- [1.2.1 纯代码方式实现](#1.2.1 纯代码方式实现)
- [1.2.2 可视化操作实现](#1.2.2 可视化操作实现)
- [1.3 最佳实践](#1.3 最佳实践)
-
- [1.3.1 使用输入框的方式实现](#1.3.1 使用输入框的方式实现)
- [1.3.2 纯代码方式实现hello world](#1.3.2 纯代码方式实现hello world)
- [1.3.3 按钮方式实现](#1.3.3 按钮方式实现)
-
- [1.3.3.1 通过图形化的方式实现按钮版本的hello world](#1.3.3.1 通过图形化的方式实现按钮版本的hello world)
- [1.3.3.2 通过纯代码的方式实现按钮版本的hello world](#1.3.3.2 通过纯代码的方式实现按钮版本的hello world)
- [1.4 内存泄漏问题](#1.4 内存泄漏问题)
- [1.5 浅解对象树问题](#1.5 浅解对象树问题)
- [1.6 中文乱码问题](#1.6 中文乱码问题)
- [1.7 小结一下](#1.7 小结一下)
- [2 ~> 项目文件解析](#2 ~> 项目文件解析)
-
- [2.1 .pro文件解析](#2.1 .pro文件解析)
- [2.2 widget.h文件解析](#2.2 widget.h文件解析)
- [2.3 main.cpp文件解析](#2.3 main.cpp文件解析)
- [2.4 widget.cpp 文件解析](#2.4 widget.cpp 文件解析)
- [2.5 widget.ui文件解析](#2.5 widget.ui文件解析)
- [2.6 最佳实践](#2.6 最佳实践)
-
- [2.6.1 纯代码的方式实现](#2.6.1 纯代码的方式实现)
- [2.6.2 按钮的方式实现](#2.6.2 按钮的方式实现)
- [2.6.3 对比两种实现按钮版本hello world的方式](#2.6.3 对比两种实现按钮版本hello world的方式)
- [2.6.4 实际开发中,是通过代码的方式构造界面为主,还是通过图形化界面的方式构造界面为主](#2.6.4 实际开发中,是通过代码的方式构造界面为主,还是通过图形化界面的方式构造界面为主)
- [3 ~> 初识Qt收尾:Qt编程注意事项](#3 ~> 初识Qt收尾:Qt编程注意事项)
-
- [3.1 变量命名风格](#3.1 变量命名风格)
-
- [3.1.1 理论](#3.1.1 理论)
- [3.1.2 最佳实践](#3.1.2 最佳实践)
- [3.2 快捷键](#3.2 快捷键)
- [3.3 查询文档的方式](#3.3 查询文档的方式)
-
- [3.3.1 使用帮助文档](#3.3.1 使用帮助文档)
- [3.3.2 注意事项](#3.3.2 注意事项)
- [3.4 认识Qt坐标系](#3.4 认识Qt坐标系)
-
- [3.4.1 Qt坐标系](#3.4.1 Qt坐标系)
- [3.4.2 术语扫盲:像素](#3.4.2 术语扫盲:像素)
- [3.5 详解对象树问题](#3.5 详解对象树问题)
-
- [3.5.1 Qt 对象模型(对象树)核心知识点总结](#3.5.1 Qt 对象模型(对象树)核心知识点总结)
- [3.5.2 Qt 对象树析构机制对比与注意事项](#3.5.2 Qt 对象树析构机制对比与注意事项)
- [3.5.3 核心总结与最佳实践](#3.5.3 核心总结与最佳实践)
- [3.5.4 对象树演示](#3.5.4 对象树演示)
- 结尾

1 ~> 创建Qt的Hello World程序
1.1 使用"按钮"实现
1.1.1 纯代码方式实现

效果如下所示:

1.1.2 可视化操作实现
(1)双击:"widget.ui"文件;

(2)拖拽控件至ui界面窗口并修改内容;

(3)构建并运行,效果如下所示:

1.2 使用"标签"实现
1.2.1 纯代码方式实现

实际演示效果:

1.2.2 可视化操作实现
(1)双击:"widget.ui"文件;

(2)拖拽"标签"至UI设计界面中,并双击修改标签内容;

(3)实现效果如下图所示:

1.3 最佳实践





label"标签":界面上一个用来显示内容的字符串控件。

Qt有自己实现的一套标准库("自己造轮子"):



1.3.1 使用输入框的方式实现

1.3.2 纯代码方式实现hello world

1.3.3 按钮方式实现
1.3.3.1 通过图形化的方式实现按钮版本的hello world

1.3.3.2 通过纯代码的方式实现按钮版本的hello world

1.4 内存泄漏问题




1.5 浅解对象树问题

前端开发(网页开发)也涉及到类似的对象树(DOM),本质上也是一个树形结构(N叉树),通过树形结构把界面上的各种元素组织起来。
Qt中也是类似,也是搞了一个对象树------也是N又树,把界面上的各种元素组织起来。





1.6 中文乱码问题


这里有一个查找字符编码的网站,大家可以尝试一下:utf8

演示结果如下所示:




-
Qt中有一个东西,QString,是可以帮助我们自动的处理编码方式的。
-
不止是QString,Qt也提供了专门用来打印日志的工具,也能自动处理编码方式。

使用qDebug,还有一个好处:

1.7 小结一下
两张图小结一下:


2 ~> 项目文件解析
2.1 .pro文件解析
工程新建好之后,在工程目录列表中有一个后缀为".pro"的文件,".pro"文件就是工程文件(project),它是qmake自动生成的用于生产makefile的配置文件。如图所示:

双击进入该文件,该文件的核心内容如下:
| 配置项 | 说明 | 内容/值 |
|---|---|---|
QT += core gui |
包含 Qt 的 core 和 gui 模块 | core, gui |
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets |
如果 Qt 主版本大于 4,则额外包含 widgets 模块 | 条件包含 widgets |
TARGET = QtFirst |
生成的应用程序名称 | QtFirst.exe |
TEMPLATE = app |
项目模板类型为应用程序 | app |
SOURCES += main.cpp\ widget.cpp |
项目中包含的源文件 | main.cpp, widget.cpp |
HEADERS += widget.h |
项目中包含的头文件 | widget.h |
".pro"文件的写法如下:
-
1、注释:从
"#"开始,到这一行结束; -
2、QT += core gui // Qt包含的模块(Qt5包含的模块)如下图所示:

-
3、greaterThan(QT_MAJOR_VERSION , 4):QT += widgets这条语句的含义是,如果QT_MAJOR_VERSION大于4(也就是当前使用的Qt5及更高版本)需要增加
widgets模块。如果项目仅需支持Qt5,也可以直接添加"QT += widgets"一句。不过为了保持代码兼容,最好还是按照QtCreator生成的语句编写。 -
4、指定生成的应用程序名:
TARGET = QtDemo -
5、TEMPLATE = app (// 模板)。告诉qmake为这个应用程序生成哪种makefile。下面是可供选择的模板:
| 模板类型 | 说明 |
|---|---|
| app | 建立一个应用程序的 makefile。这是默认值,所以如果模板没有被指定,这个将被使用。 |
| lib | 建立一个库的 makefile。 |
| vcapp | 建立一个应用程序的 VisualStudio 项目文件。 |
| vclib | 建立一个库的 VisualStudio 项目文件。 |
| subdirs | 这是一个特殊的模板,它可以创建一个能够进入特定目录的 makefile 并且为它调用 make 的 makefile。 |
-
6、工程中包含的源文件:SOURCES += main.cpp/widget.cpp
-
7、工程中包含的头文件:HEADERS += widget.h
-
8、工程中包含的资源文件:RESOURCES += painter.qrc
-
9、工程中包含的"ui" 设计文件:FORMS += widget.ui
-
10、配置信息:CONFIG += C++11(使用c++11的特性)CONFIG用来告诉qmake关于应用程序的配置信息。
2.2 widget.h文件解析
在Qt中,如果要使用信号与槽(signal 和 slot)的机制就必须加入Q_OBJECT宏;
**Ui::Widget *ui;**这个指针是用前面声明的namespaceUi里的Widget类定义的,所以指针ui是指向可视化设计的界面,后面要访问界面上的组件,都需要通过这个指针ui去访问。

2.3 main.cpp文件解析
使用**Qt Creator**新建任意工程之后,main.cpp文件中都会自动生成如下代码:

| 要点 | 说明 |
|---|---|
| Qt 标准类头文件 | 系统提供的标准类名声明头文件没有 .h 后缀 |
| Qt 类与头文件关系 | 一个类对应一个头文件,类名就是头文件名 |
| QApplication 类 | 应用程序类,有且仅有一个应用程序对象,管理 GUI 应用程序的控制流和主要设置,包含主事件循环 |
| 窗口对象实例化 | myWidget w; // 实例化窗口对象 |
| 显示窗口 | w.show(); // 调用 show 函数显示窗口 |
| 消息循环 | a.exec(); // 程序进入消息循环,Qt 处理事件并传递给窗口部件,当应用程序退出时 exec() 返回值 |
2.4 widget.cpp 文件解析
widget.cpp文件是类Widget的实现代码,所有在窗体上要实现的功能添加在此文件中:

2.5 widget.ui文件解析

widget.ui 是窗体界面定义文件,是一个XML文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用UI设计器可视化设计的界面都由Qt自动解析,并以XML文件的形式保存下来。在设计界面时,只需在UI设计器里进行可视化设计即可,而不用管widget.ui文件是怎么生成的。
2.6 最佳实践
完成Hello World可以通过很多种控件来实现:

2.6.1 纯代码的方式实现


2.6.2 按钮的方式实现


Qt中的信号槽机制:



2.6.3 对比两种实现按钮版本hello world的方式

2.6.4 实际开发中,是通过代码的方式构造界面为主,还是通过图形化界面的方式构造界面为主

3 ~> 初识Qt收尾:Qt编程注意事项
3.1 变量命名风格
3.1.1 理论
| 名称类型 | 命名规则 |
|---|---|
| 类名 | 首字母大写,单词和单词之间首字母大写 |
| 函数名及变量名 | 首字母小写,单词和单词之间首字母大写 |
Qt偏好驼峰命名法,这一点不像咱们之前的内容中一直是偏好蛇形命名方法的。
3.1.2 最佳实践

3.2 快捷键
| 功能 | 快捷键 |
|---|---|
| 注释/取消注释当前行或选中行 | Ctrl + / |
| 运行项目 | Ctrl + R |
| 编译项目 | Ctrl + B |
| 缩放编辑器字体 | Ctrl + 鼠标滚轮 |
| 查找文本 | Ctrl + F |
| 向上/向下移动当前行 | Ctrl + Shift + ↑ / ↓ |
| 查看光标所在符号的帮助文档 | F1 |
| 自动对齐代码 | Ctrl + I |
| 在同名的头文件(.h)与源文件(.cpp)之间切换 | F4 |
| 快速为函数生成对应的定义(在声明处使用) | Alt + Enter |
3.3 查询文档的方式
3.3.1 使用帮助文档
打开帮助文档有三种方式,实际编程中使用哪种都可以。
- 1、光标放到要查询的类名/方法名上,
直接按F1:

- 2、Qt Creator左侧边栏中直接用鼠标单击
"帮助"按钮:

点击"帮助"之后,出现如下图示界面:


- 3、找到
Qt Creator的安装路径,在"bin"目录下找到assistant.exe这个程序,双击打开:



还可以进行检索:

使用示例:
-
1、新建项目,在新建的项目中使用Qt中的"QpushButton"控件。
-
2、打开帮助手册,在"索引"里面输入"QpushButton"。

3.3.2 注意事项

不要使用中文文档!阅读英文文档是每个程序员必备的专业技能,必须要练,不能退缩,Qt的文档从通俗易懂的角度来说,是技术类文档中非常出类拔萃的,只要大家稍微有点耐心,基本都能读懂个八九不离十。
咱们在后续的学习和工作中,也会经常翻阅文档。
3.4 认识Qt坐标系
3.4.1 Qt坐标系
坐标体系:以左上角为原点(0,0),X向右增加,Y向下增加。


对于嵌套窗口,其坐标是 相对于父窗口来说 的。

示例:使用Qt中的坐标系设置控件的位置:

运行结果如下图示:


3.4.2 术语扫盲:像素

3.5 详解对象树问题

3.5.1 Qt 对象模型(对象树)核心知识点总结
| 核心概念 | 说明与机制 |
|---|---|
| 组织方式 | Qt 中的 QObject 以对象树的形式组织。 |
| 父对象指针 (parent) | 创建 QObject 对象时,可通过构造函数传入一个父对象指针。 |
| 自动管理 | 子对象会自动添加到父对象的 children() 列表中。父对象析构时,其所有子对象也会被自动析构。 |
| GUI 应用 | QWidget(所有可视化组件的基类)继承自 QObject,因此也遵循对象树规则。子组件会显示在父组件的坐标系中,并受其边界裁剪。 |
| 内存管理 | 对象树机制自动处理关联对象的内存释放,极大减少了内存泄漏的风险。 • 删除父对象 → 自动删除其所有子对象。 • 删除子对象 → 自动从其父对象的子对象列表中移除。 |
| 析构保证 | Qt 保证没有 QObject 会被删除两次,这是由对象树的析构顺序保证的。 |
| 设计意义 | 使 GUI 程序设计更直观、安全(例如,删除一个窗口时,其内部的按钮、标签等子部件会自动被清理)。 |
简而言之,Qt 的对象树让你在创建对象时指定一个 "爹"(parent) 。当你删掉这个"爹"时,它所有的 "儿子们"(children) 都会被自动清理掉,省心又安全。
栈上局部对象的析构顺序与对象树机制
| 情境 | 析构顺序 | 关键机制 | 结果 |
|---|---|---|---|
| 父子对象均为栈上局部对象 | 按创建顺序的逆序 析构 (后创建的先析构,先创建的后析构) | 子对象(quit)析构时,会自动从父对象(window)的 children() 列表中移除 |
父对象析构时,其子对象列表已更新,不会再次删除该子对象,从而避免双重删除(double delete) |
核心要点总结:
- 栈上对象同样受对象树管理:即使对象在栈上创建(局部对象),父子关系依然有效。
- C++标准析构顺序 :局部对象的析构顺序与创建顺序相反,这保证了子对象先于父对象析构。
- 安全的自动管理 :
- 子对象析构时,会自动通知父对象,将自己从父对象的子对象列表中移除。
- 父对象随后析构时,由于子对象已不在其列表中,因此不会尝试再次删除它。
- 结论 :Qt 的对象树机制与 C++ 的标准析构顺序相结合,确保了无论对象在堆上还是栈上创建,都能安全地避免内存泄漏和双重删除。
简单理解:先出生的(父对象)后死亡,后出生的(子对象)先死亡。在子对象"死亡"时,它会主动从父对象的"家庭成员名单"中注销,这样父对象"死亡"时就不会再处理这个已注销的子对象了。
但是,如果我们使用下面的代码:

3.5.2 Qt 对象树析构机制对比与注意事项
为了清晰理解 Qt 对象树在不同情况下的行为,避免程序崩溃,现将正常情况 与问题情况对比如下:
| 对比项 | 正常情况 (前文所述) | 问题情况 (本文所述) |
|---|---|---|
| 对象创建方式 | 父对象 (window) 与子对象 (quit) 均在栈上创建。 |
父对象 (window) 与子对象 (quit) 均在栈上 创建,但创建顺序相反。 |
| 关键前提 | 子对象 (quit) 的创建晚于 父对象 (window)。 即:先创建 window,后创建 quit 并指定 window 为其父对象。 |
父对象 (window) 的创建晚于 子对象 (quit)。 即:先创建 quit,后创建 window 并(通过 setParent 或后续构造)成为 quit 的父对象。 |
| C++ 析构顺序 | 按创建顺序的逆序:先析构 quit (子),后析构 window (父)。 |
按创建顺序的逆序:先析构 window (父),后析构 quit (子)。 |
| 对象树行为 | 1. quit 析构时,自动从 window 的 children() 列表中移除。 2. window 析构时,其子对象列表已为空。 |
1. window 先析构,触发其析构函数自动删除 children() 列表中的所有对象(即 quit)。 2. quit 作为局部变量,在后续超出作用域时,会第二次被析构。 |
| 最终结果 | 安全。每个对象仅被析构一次,符合 C++ 标准。 | 程序崩溃 。因 quit 被析构两次,违反 C++ 规则。 |
3.5.3 核心总结与最佳实践
总结问题根源: Qt 对象树提供的自动内存管理 ,其安全性依赖于一个前提:父对象的生命周期应完全覆盖其子对象 。当父子对象同为栈上局部变量时,必须严格保证父对象晚于所有子对象被析构,否则就会引发"双重删除"的崩溃问题。
为避免此类难以调试的析构顺序问题,在 Qt 开发中应养成以下习惯:
-
1、 在构造时指定 Parent:尽可能在创建对象时,通过构造函数参数直接指定其父对象。
-
2、 大胆在堆上创建 :对于具有父子关系的对象,优先使用
new在堆(heap) 上创建,并由 Qt 对象树统一管理生命周期。只需保证父对象被正确删除,其所有子对象便会自动安全释放。
一句话指南 :对于 Qt 界面对象,用
new创建并指定好 Parent,把析构的麻烦事交给对象树。
3.5.4 对象树演示
Qt对象树如图所示:

- 1、创建一个新工程并编译运行,生成如下窗口:

- 2、选中工程名,鼠标右键---->"add new..."(或"添加新文件"):


- 3、选择"choose...",弹出如下界面:

- 4、点击"下一步",弹出如下对话框:

- 5、点击"完成"之后,手动创建类的头文件以及源文件会自动添加到目标工程中:

- 6、修改头文件:

- 7、编写源文件:

- 8、编译并运行:

- 9、当关闭弹出的对话框时,就会自动调用按钮的析构函数:

- 10、观察析构函数的执行顺序:

- 11、执行结果如下所示:

- 12、执行结果分析:
注意:调用析构函数和释放内存并非是同一件事情。
(1)内存释放顺序:对象树中,内存释放遵循"先子节点、后父节点"的顺序。
(2)析构函数调用顺序:与内存释放顺序不一定一致,有时子节点的析构函数可能在父节点之后执行。
(3)重要区分:调用析构函数与实际释放内存是两个不同的过程,不应混淆。
一句话总结:在对象树中,虽然内存释放总是从子节点到父节点,但析构函数的调用顺序可能与内存释放顺序不同,二者是分离的操作。
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
结语:希望对学习QT相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა
