目录
1. 什么是Qt
2. Qt中的模块
3. 下载安装
4. QtCreator
4. Hello Qt
解释 .pro
解释 main.cpp
解释 mainwindow.ui
解释 mainwindow.h
解释 mainwindow.cpp
5. Qt 中的窗口类
5.1 基础窗口类
5.2 窗口的显示
6. Qt 的坐标体系
7. 内存回收
1. 什么是Qt
是一个跨平台的C++应用程序开发框架
- 具有短平快的优秀特质: 投资少、周期短、见效快、效益高
- 几乎支持所有的平台, 可用于桌面程序开发以及嵌入式开发
- 有属于自己的事件处理机制
- 可以搞效率的开发基于窗口的应用程序
Qt是标准 C++ 的扩展, C++的语法在Qt中都是支持的
- 良好封装机制使得 Qt 的模块化程度非常高,可重用性较好,可以快速上手
- Qt 提供了一种称为 signals/slots 的安全类型来替代 callback(回调函数),这使得各个元件 之间的协同工作变得十分简单
2. Qt中的模块
Qt类库里大量的类根据功能分为各种模块,这些模块又分为以下几大类:
- Qt 基本模块(Qt Essentials):提供了 Qt 在所有平台上的基本功能。
- Qt 附加模块(Qt Add-Ons):实现一些特定功能的提供附加价值的模块。
- 增值模块(Value-AddModules):单独发布的提供额外价值的模块或工具。
- 技术预览模块(Technology Preview Modules):一些处于开发阶段,但是可以作为技术预览使用的模块。
- Qt 工具(Qt Tools):帮助应用程序开发的一些工具。
以下是官方对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++ 图形组件类
3. 下载安装
Qt官方下载地址
:Index of /archive/qt文章基于 qt5.14.2 及以上版本学习。
对于安装的一些解锁:
MSVC2015 64-bit: Visual Studio 2015 使用的64位编译套件
MinGW7.3.0 64-bit: QtCreator 使用的32位编译套件
UWP –> Universal Windows Platform: 用于window平台应用程序开发的编译套件
在这个窗口中除了选择必要的编译套件,还有一些非必要组件,常用的有以下两个:
Source: Qt源码, 另外Qt的一些模块运行需要的驱动没有提供现成的动态库需要自己编译, 建议安装
Qt Charts: 用于绘制统计数据对应的图表, 比如: 折线图/曲线图等
作者安装了
MinGW7.3.0 64-bit
和Source
两部分环境变量设置
当我们编写一个Qt程序,并且生成了可执行程序,这个可执行程序运行的时候默认需要加载相关的Qt动态库(因为默认是动态链接,静态链接则不需要)。为了保证可执行程序在任何目录执行都能链接到对应的动态库,我们可以将Qt模块对应的动态库目录设置到系统的环境变量中(这一点对于Linux系统也是一样的)
->在桌面找到我的电脑(此电脑)图标,鼠标右键,打开属性窗口
->在属性窗口中选择 “高级系统设置”
->打开环境变量窗口
->新建环境变量
->Path
将Qt的相关目录添加到系统环境变量中
环境变量说明:
找到Qt的安装目录:
C:
在安装目录中找到Qt库的bin目录:
C:\Qt\Qt5.14.2\5.14.2\mingw73_32\bin
在安装目录中找到编译套件的bin目录:
C:\Qt\Qt5.14.2\Tools\mingw730_32\bin
把上面两个路径添加进去。
4. QtCreator
QtCreator是编写Qt程序默认使用的一款 IDE,使用VS写Qt程序也是可以的,在此不做介绍。
使用QtCreator创建的项目目录中不能包含中文
QtCreator默认使用Utf8格式编码对文件字符进行编码
(vs写Qt程序默认使用的本地编码 -> gbk)
修改QtCreator的编码, 菜单栏 -> 工具->选项
->在弹出的选项窗口中设置文件编码, 默认为
utf8
默认的编译套件
MinGW
->Minimalist GNU for Windows
- MinGW 提供了一套简单方便的Windows下的基于GCC 程序开发环境。MinGW 收集了一系列免费的Windows 使用的头文件和库文件;
- 整合了GNU的工具集,特别是GNU 程序开发工具,如经典gcc, g++, make等。
- MinGW是完全免费的自由软件,它在Windows平台上模拟了Linux下GCC的开发环境,为C++ 的跨平台开发提供了良好基础支持,为了在Windows下工作的程序员熟悉Linux下的C++工程组织提供了条件。
4. Hello Qt
创建基于窗口的应用程序项目
选择编译套件, 编译套件用于项目文件的编译, 如果安装了多个编译套件, 在这里选择其中一个就可以了。
这就创建完毕了。
解释 .pro
在创建的Qt项目中自动生成了一个后缀为
.pro
的项目文件,该文件中记录着项目的一些属性信息,具体信息如下:# 在项目文件中, 注释需要使用 井号(#) # 项目编译的时候需要加载哪些底层模块 QT += core gui # 如果当前Qt版本大于4, 会添加一个额外的模块: widgets # Qt 5中对gui模块进行了拆分, 将 widgets 独立出来了 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets # 使用c++11新特性 CONFIG += c++11 #如果在项目中调用了废弃的函数, 项目编译的时候会有警告的提示 DEFINES += QT_DEPRECATED_WARNINGS # 项目中的源文件 SOURCES += \ main.cpp \ mainwindow.cpp # 项目中的头文件 HEADERS += \ mainwindow.h # 项目中的窗口界面文件 FORMS += \ mainwindow.ui
解释 main.cpp
#include "mainwindow.h" // 生成的窗口类头文件 #include <QApplication> // 应用程序类头文件 int main(int argc, char *argv[]) { // 创建应用程序对象, 在一个Qt项目中实例对象有且仅有一个 // 类的作用: 检测触发的事件, 进行事件循环并处理 QApplication a(argc, argv); // 创建窗口类对象 MainWindow w; // 显示窗口 w.show(); // 应用程序对象开始事件循环, 保证应用程序不退出 return a.exec(); }
解释 mainwindow.ui
在Qt中每一个窗口都对应一个可编辑的可视化界面(*.ui), 这个界面对应的是一个xml格式的文件, 一般情况下不需要在xml格式下对这个文件进行编辑, 关于这个文件结构了解即可。
<!-- 双击这个文件看到的是一个窗口界面, 如果使用文本编辑器打开看到的是一个XML格式的文件 --> <!-- 看不懂这种格式没关系, 我们不需要在这种模式下操作这个文件。 --> <!-- 这里只是给大家介绍这个文件的本质 --> <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"/> <widget class="QMenuBar" name="menubar"/> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>
解释 mainwindow.h
这个文件是窗口界面对应的类的头文件。
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> // Qt标准窗口类头文件 QT_BEGIN_NAMESPACE // mainwindow.ui 文件中也有一个类叫 MainWindow, 将这个类放到命名空间 Ui 中 namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT // 这个宏是为了能够使用Qt中的信号槽机制 public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; // 定义指针指向窗口的 UI 对象 }; #endif // MAINWINDOW_H
解释 mainwindow.cpp
这个文件是窗口界面对应的类的源文件。
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) // 基于mainwindow.ui创建一个实例对象 { // 将 mainwindow.ui 的实例对象和 当前类的对象进行关联 // 这样同名的连个类对象就产生了关联, 合二为一了 ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; }
其上的作用就是为了让可以让ui界面直接和我们的代码相关联!
5. Qt 中的窗口类
5.1 基础窗口类
- 常用的窗口类有3个
- 在创建Qt窗口的时候, 需要让自己的窗口类继承上述三个窗口类的其中一个
QWidget
- 所有窗口类的基类
- Qt中的控件(按钮, 输入框, 单选框…)也属于窗口, 基类都是
QWidget
- 可以内嵌到其他窗口中: 没有边框
- 可以不内嵌单独显示: 独立的窗口, 有边框
QDialog
- 对话框类, 后边的章节会具体介绍这个窗口
- 不能内嵌到其他窗口中
QMainWindow
- 有工具栏, 状态栏, 菜单栏, 后边的章节会具体介绍这个窗口
- 不能内嵌到其他窗口中
5.2 窗口的显示
内嵌窗口
- 依附于某一个大的窗口, 作为了大窗口的一部分
- 大窗口就是这个内嵌窗口的父窗口
父窗口显示的时候, 内嵌的窗口也就被显示出来了
不内嵌窗口
这类窗口有边框, 有标题栏
需要调用函数才可以显示
// QWidget是所有窗口类的基类, 调用这个提供的 show() 方法就可以显示将任何窗口显示出来 // 非模态显示 void QWidget::show(); // 显示当前窗口和它的子窗口 // 对话框窗口的非模态显示: 还是调用show() 方法 // 对话框窗口的模态显示 [virtual slot] int QDialog::exec();
6. Qt 的坐标体系
在Qt关于窗口的显示是需要指定位置的,这个位置是通过坐标来确定的,所有坐标的选取又都是基于坐标原点来确定的。
所有坐标的确定都需要先找到坐标原点,
Qt的坐标原点在窗口的左上角
在一个Qt窗口中一般都有很多子窗口内嵌到这个父窗口中,其中每个窗口都有自己的坐标原点,子窗口的位置也就是其使用的坐标点就是它的父窗口坐标体系中的坐标点。
在Qt的某一个窗口中有可能有若干个控件, 这个控件都是嵌套的关系
- A窗口包含B窗口, B窗口包含C窗口
每个窗口都有坐标原点, 在左上角
- 子窗口的位置是基于父窗口的坐标体系来确定的, 也就是说通过父窗口左上角的坐标点来确定自己的位置
Qt中窗口显示的时候使用的相对坐标, 相对于自己的父窗口
将子窗口移动到父窗口的某个位置
// 所有窗口类的基类: QWidget // QWidget中提供了移动窗口的 API函数 // 参数 x, y是要移动的窗口的左上角的点, 窗口的左上角移动到这个坐标点 void QWidget::move(int x, int y); void QWidget::move(const QPoint &);
7. 内存回收
在Qt中创建对象的时候会提供一个
Parent对象指针
(可以查看类的构造函数)QObject是以对象树的形式组织起来的。
当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针
。这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!
)QWidget是能够在屏幕上显示的一切组件的父类。QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
Qt 引入对象树的概念,在一定程度上解决了内存问题。
当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。(而且如果多次free,也是安全的,Qt不会放任其发生)
综上所述, 我们可以得到一个结论:
Qt中有内存回收机制, 但是不是所有被new出的对象被自动回收, 满足条件才可以回收
, 如果想要在Qt中实现内存的自动回收, 需要满足以下两个条件:
创建的对象必须是QObject类的子类(间接子类也可以)
QObject类是没有父类的, Qt中有很大一部分类都是从这个类派生出去的
- Qt中使用频率很高的窗口类和控件都是 QObject 的直接或间接的子类
- 其他的类可以自己查阅Qt帮助文档
创建出的类对象, 必须要指定其父对象是谁, 一般情况下有两种操作方式:
// 方式1: 通过构造函数 // parent: 当前窗口的父对象, 找构造函数中的 parent 参数即可 QWidget::QWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()); QTimer::QTimer(QObject *parent = nullptr); // 方式2: 通过setParent()方法 // 假设这个控件没有在构造的时候指定符对象, 可以调用QWidget的api指定父窗口对象 void QWidget::setParent(QWidget *parent); void QObject::setParent(QObject *parent);
学习Qt推荐小破站--爱编程的大丙!