1.Qt环境搭建
Qt开发环境,需要安装3个部分:
-
C++编译器(gcc,cl.exe...)。Qt SDK中也会有,需要在安装过程中勾选上。
-
Qt SDK ------软件开发工具包。Windows版本的Qt SDK 里已经内置了C++编译器(内置的编译器是mingw,Windows版本的gcc/g++)。要是想用VS内置的cl.exe作为编译器,需要配置很多额外的东西,容易出错,这里就不做介绍了。
-
需要有一个Qt的集成开发环境(IDE)。
(1)Qt 官方的Qt Creator------最容易入门,容易上手(Qt SDK 中也有)
(2)Visual Studio------功能更强,但是需要额外的配置,容易出错。有些公司开发商业Qt程序的时候可能会使用VS
(3)Eclipse------并非只是Java IDE,其本身是一个IDE平台,可以搭配不同的插件构成不同的IDE
虽然理论上来说是应该有三个东西,但其实只要安装一个Qt SDK,另外两个也就都有了。
安装Qt SDK
Try Qt | Develop Applications and Embedded Systems | Qt
这是Qt SDK在线安装器下载的位置,官方推荐的方法
Index of /official_releases/qt这个是离线安装包现在的位置,但是只有Qt6版本
Index of /archive/qt 这里包含了Qt5
在线安装器 :这是官方推荐的方式。你需要先下载一个轻量级的安装器。运行后,它会让你登录Qt账户,然后你可以按需选择安装需要的Qt版本、编译器和模块,适合网络稳定的开发者。
离线安装包:可以直接访问获取完整的离线安装包,但体积会比较大,可能会下载失败
具体的安装教程网上有很多资料,大家可以按需查找,我这里就不赘述了。
大家在成功下载Qt Creator后一定不要忘记把Qt的bin目录加入到Path环境变量中
2. 创建第一个Qt项目
下载好Qt Creator之后,我们就可以开始创建第一项目了(我下载的是Qt5.15.2)
创建新项目:
左侧我们选择Application(Qt)就是使用C++语言写一个GUI程序。
我们常使用的是传统的开发GUI方式Qt Widgets Application,一个使用 C++ 和 Qt Widgets 构建的传统桌面应用程序。
Qt Quick Application (Qt):使用 QML 语言 和 C++ 混合编程的现代应用程序。界面用 QML(一种类似 JSON 的声明式语言)编写,逻辑用 C++ 实现。
Qt Quick Application (compat):兼容模式 的 Qt Quick 项目,用于支持旧版本 Qt Quick 的语法和模块。
Qt Console Application:创建控制台(命令行)程序,没有图形界面。
点击选择后就会来到这个界面,这里可以修改项目名称以及项目路径,然后点击下一步
这里要选择构建系统,Qt 构建系统就是一套将你的源代码(.cpp / .h / .qml / .ui 等)编译、链接成最终可执行程序(.exe / .app)的自动化工具和规则集合。
qmake:Qt 自带的专用构建工具;配置文件.pro 文件,语法对 Qt 开发者很友好;生成 Makefile,再调用 make 等工具执行编译(我们选择这个)
Cmake:行业标准的通用跨平台构建系统;配置文件CMakeLists.txt 文件,功能强大但语法稍复杂;生成平台原生的构建文件(如 Makefile),再调用编译
Qbs:Qt 曾推出的下一代全功能构建工具;配置文件.qbs 文件,基于 JavaScript 的声明式语法;一体化工具,直接生成依赖图并执行构建,跳过了生成 Makefile 的中间步骤;但是现在官方已经没有在维护了

使用QtCreator 创建项目,会自动的生成一些代码出来,生成的代码就包含一个类,此处就是要选择这个自动生成的类的父类是谁。
QMainWindows ------ 完整的应用程序窗口(可以包含菜单栏,工具栏,状态栏...)
QWidget ------ 表示一个控件.(窗口上的一个具体的元素.输入框,按钮,下拉框,单选按钮,复选按钮....)。(我们选择这个)
QDialog ------ 表示一个用于短暂交互的对话框
注意:这里的Generate form,勾选后创建一个form file,这个form file 非常关键!
Qt中创建图形化界面的程序,有两种方式.
1.直接通过c++代码的方式创建界面.
2.通过form file,以图形化的方式来生成界面.
有了这个form file,就可以使用 Qt Designer 或者直接使用 Qt Creator 来编辑这个ui 文件
从而以图形化的方式快速方便的生成图形界面。

这里是选择翻译文件和对应的翻译语言,让项目可以国际化,这里我们先不考虑。

这里是选择一下基于哪个编译器的QtSDK来构建后续代码,按需选择即可

选择完成即可
3. 详解项目初始代码

创建好项目后,我们会发现项目初始状态下就有一些代码文件
3.1 main.cpp
cpp
//main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return QApplication::exec();
}
这是main.cpp文件中的内容:
main的形参就是命令行参数;
编写一个Qt 的图形化界面程序,一定要有且只有一个QApplication 对象!
QApplication a(argc, argv); ------ 这行代码就是创建一个 QApplication对象,命名为 a;
Widget w; ------ 这个Widget对象w代表应用程序的主窗口
w.show(); ------ 调用 Widget对象的show() 方法,让窗口显示在屏幕上。show方法是非阻塞的,它调用后立即返回,不会卡在这里等待窗口关闭。
return QApplication::exec(); ------ 启动 Qt 的事件循环(Event Loop),并进入阻塞状态,直到应用程序退出。
事件循环是 GUI 程序的"心脏":它不停地从系统消息队列里取事件(鼠标点击、键盘按键、定时器超时、窗口重绘等),并分发给对应的窗口去处理。
3.2 widget.h
cpp
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget() override;
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#ifndef WIDGET_H
#define WIDGET_H
防止头文件被重复包含,也可以用#pragma once替代
QT_BEGIN_NAMESPACEnamespace Ui {
class Widget;
}
QT_END_NAMESPACE
声明一个名为Ui::Widget的类,但这个类不在当前文件中定义,它的定义在ui_widget.h中(由 UIC 编译器从.ui文件自动生成)。
这是一种前置声明 ,告诉编译器"Ui::Widget这个类存在,但具体定义你稍后再去找"。这样可以在widget.h中声明Ui::Widget *ui
;指针,而不需要 #include"ui_widget.h",从而减少编译依赖,加快编译速度。
class Widget : public QWidget这里继承的QWidget是在创建项目时选择的父类
Q_OBJECT这是 Qt 的元对象编译器的标记宏。
任何需要信号与槽功能的类,都必须把这个宏放在类的最开始(private区域之前)。它会展开成一系列元对象代码,让这个类支持 Qt 的反射机制。
explicit Widget(QWidget *parent = nullptr);~Widget() override;
构造函数和析构函数声明。explicit是防止隐式类型转换
parent = nullptr:默认父指针为空。如果传入了父对象,Qt 的内存管理机制会让父对象在销毁时自动销毁子对象。
析构函数用override关键字,明确表示这是重写基类QWidget的析构函数,同时必须在这里释放
ui指针。
private:Ui::Widget *ui;
这个ui指针是连接 C++ 代码 和 .ui 界面文件的桥梁。所有的界面控件(按钮、标签、输入框等)都通过 ui->控件名 来访问。
3.3 widget.cpp
cpp
//main.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
Widget::Widget(QWidget *parent)
: QWidget(parent) // 调用基类 QWidget 的构造函数,传入 parent
, ui(new Ui::Widget) // 初始化 ui 指针,创建一个 Ui::Widget 对象
{
ui->setupUi(this); // 调用 setupUi,将界面布局和控件"安装"到当前窗口上
}
Widget::~Widget(){
delete ui;
}
因为ui是用new动态分配的,如果不手动delete释放ui指针指向的内存,会导致内存泄漏
ui指向的对象不是Qt对象树中的一员,所以不会自动释放
3.4 界面文件

在Qt中,.ui 文件是使用Qt Widgets Designer这个可视化设计工具生成的界面定义文件。
它的核心作用,就是让你能用"所见即所得"的拖拽方式设计界面,从而更加方便我们设计界面布局。

双击这个界面文件就可以来到这个界面,在这个界面中就可以拖拽控件进行页面设计了。
4. 创建HelloWorld按钮
现在我们已经大致了解了项目的结构,现在我们来试着创建一个hello world按钮:

拖拽过来后,可以调整按钮的各种属性,我们把按钮上的显示内容可以改为HelloWorld:

运行结果如下图所示:

我们也可以通过代码来实现:
cpp
//widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton> //包含相关的头文件
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* hw = new QPushButton(this);//创建一个按钮,并且挂到对象树上
hw->setText("HelloWorld");//设置按钮上显示的文字
}
Widget::~Widget()
{
delete ui;
}
这样编写代码之后也可以在界面上实现一个HelloWorld按钮:

5. 对象树
Qt对象树是一个基于QObject类的、通过父子关系组织起来的树形数据结构。
在纯C++中,你需要记住每个new出来的对象在何时delete。在复杂的GUI程序中,控件之间层层嵌套,手动管理极易出错。
Qt对象树解决这个问题的思路是:
一个对象的所有权归它的父对象所有。父对象销毁时,递归地销毁所有子对象。
这意味着你只需要管理"根节点"的生命周期------当根节点被销毁时,整棵树自动清理。这极大地降低了内存泄漏的风险。
前面我们用代码new了一个QPushButton对象出来,就通过this指针挂到对象树上了,所以可以不用手动释放。
6. 认识Qt坐标系
说到坐标系,我们第一时间可能想到的是数学中的坐标系(y轴向上------右手坐标系):
但是在计算机世界中的坐标系一般是这种(y轴向下------左手坐标系):

在Qt中,坐标原点一般是屏幕左上角或者窗口左上角,给Qt的某个控件,设置位置,就需要指定坐标.对于这个控件来说,坐标系原点就是父窗口/控件的左上角。

我们用代码生成的按钮位置默认就是原点,我们可以通过move这个函数来设置按钮的位置(单位是像素):
