初识Qt——创建第一个Qt项目

1.Qt环境搭建

Qt开发环境,需要安装3个部分:

  1. C++编译器(gcc,cl.exe...)。Qt SDK中也会有,需要在安装过程中勾选上。

  2. Qt SDK ------软件开发工具包。Windows版本的Qt SDK 里已经内置了C++编译器(内置的编译器是mingw,Windows版本的gcc/g++)。要是想用VS内置的cl.exe作为编译器,需要配置很多额外的东西,容易出错,这里就不做介绍了。

  3. 需要有一个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_NAMESPACE

namespace 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这个函数来设置按钮的位置(单位是像素):

相关推荐
祈禾2 小时前
计算机组成原理之编译、汇编、链接、解释
开发语言·汇编·笔记·学习
吴声子夜歌2 小时前
正则指引——Ruby
开发语言·正则表达式·ruby
nnerddboy2 小时前
Rust教程06:ESP32-rust环境搭建
开发语言·后端·rust
nnerddboy3 小时前
Rust教程03:函数,控制流与所有权
开发语言·后端·rust
linux修理工3 小时前
内存占用 99% 且 Java 程序较多的优化建议
java·开发语言
weixin_460443563 小时前
企业考试系统如何对接OA、钉钉和企业微信?SSO单点登录、组织同步与权限一致性设计
java·开发语言·数据库
nnerddboy3 小时前
Rust教程05:结构体,枚举与模式匹配
开发语言·网络·rust
小小尚@3 小时前
AE脚本-AE Actions v1.1.8 操作动作记录器
开发语言·前端·javascript·jupyter·postman
程序员雷欧3 小时前
Java 反射深度解析:从原理到源码的全面剖析
java·开发语言·python