QT图形界面开发

安装

进入网站

Download Qt OSS: Get Qt Online Installer

进入这个网站,一定要先注册,注册之后要打开邮箱做邮箱验证,然后才可以使用。

下载

image-20250111175702039

选择正确的版本,点击按钮就自动下载了

切换镜像开启安装(重要)

下载完成之后一定要使用power shell打开下载文件所在的文件夹

image-20250111175917787

image-20250111180016897

然后输入

1
.\ (连括号整个替换成下载下来的文件名) --mirror https://mirrors.ustc.edu.cn/qtproject/

然后就自动切换镜像并且开始了安装流程

如果你出现“无法将“.\qt-online-installer-windows-x64-4.8.0.exe”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。”这样的错误,那90%概率你替换有误

安装过程

输入账号密码开始安装,基本上一直点下一步就行
(懒得重新截图了,下面的几张图来自csdn 文章编号:132645054)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这里要选择安装路径(不能有中文)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

等待安装完成就结束了安装。

创建项目

创建项目随便选一个,基于这里创建的类型不同可能会有不同,但是基本上差别不大。

后记:这里如果选第一个就是用C++的方式去编写程序,如果选第二个就是编写控制台程序
只有选第三个和第四个才是用QML编写程序

image-20250111183731110

进去之后 直接点左下角运行一下
image-20250111183830421

如果出现这个可以拖动的helloword就是创建成功了
image-20250111183849888

代码学习(基于QML的方式)

认识QT

qt是一个图形框架,基于C++开发
可以做什么?
windows linux mac软件,安卓,ios,鸿蒙
qt两大派系
QML C++
QML的语法更加简单 适合没学过C++的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import QtQuick
/*相当于C语言的包含头文件 引入库
QtQuick是一个库*/
/*下面的windows就是一个基本数据类型*/
/*在QT里面 数据类型分为两大类
一种叫做对象类型:Window
另一种叫值类型:整形 浮点型 字符串 布尔型
如何区分?
凡是对象类型的 都会有一个花括号{}来标示它是个对象
后面没有 带花括号的都是值类型
*/
/*根对象 在每个源文件中只允许存在一个根对象
类似c++和java中的main函数 只能有一个*/
Window {
/*声明自己的属性 通过property关键字声明
property 数据类型 名称 : 值
可以不赋值 通过换行分隔*/
property int a
property string str1 :"hello world QML"

/*括号中的部分都是window这个对象的属性
通过冒号给属性赋值,下面的属性都是window里面自带的属性*/
width: 640
height: 480
visible: true
// title: qsTr("Hello World")
/*上面分别对应窗口的长宽 是否可见和标题*/
title: str1
/*id是给上个面的window根对象取一个名字
QT中赋值的操作在对象中 不在定义的时候
同时对象的名字可以为空*/
id:root
/*子对象:矩形*/
Rectangle{
x:100
y:100
width:root.width/3 /*设置矩形的宽度为窗口宽度的三分之一*/
/*这种哦绑定的方式类似动态绑定*/
height:200
color:"blue"
/*把这个子对象赋给矩形
文本的坐标轴就从矩形(父对象 )左上角开始为0*/
Text{
x:20
y:100
text:"第二个文本"
}
}

/*子对象:文本 */
Text{
text:"你好 123"
}
/*正常情况下直接加下面的文本对象会重叠
QT使用笛卡尔坐标系 坐标原点在左上角*/
// Text{
// text:"第二个文本"
// }

}

笛卡尔坐标系

image-20250111193656537

登陆界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import QtQuick
import QtQuick.Controls


Window {
property string str1:"登陆界面"

width: 320
height: 480
visible: true
title: str1
id:root


Image{
id:redrabbit
x:(root.width-redrabbit.width)/2
width:120
height:140
source: "https://spjblogimg-1329562662.cos.ap-shanghai.myqcloud.com/img/5eea8644b528184bef8380be5fb36de9.jpg"
}

TextField{
x:30
y:200
width:250
height: 45
font.pixelSize: 20/*设置字体大小*/
verticalAlignment:Text.AlignVCenter/*水平对齐*/
horizontalAlignment: Text.AlignHCenter/*垂直对其*/
placeholderText: "请输入账号"
/*前面的是属性*/
}

TextField{
x:30
y:270
width:250
height: 45
font.pixelSize: 20/*设置字体大小*/
verticalAlignment:Text.AlignVCenter/*水平对齐*/
horizontalAlignment: Text.AlignHCenter/*垂直对其*/
placeholderText: "请输入密码 "
/*添加掩码*/
echoMode: TextInput.Password
/*前面的是属性*/
}

Button{
x:30
y:350
width:250
height:50
text:"登录"

}


}

使用技巧(快捷键)

image-20250206145134819

项目管理

image-20250206145724852

Clang代码模型
image-20250206145754306

QT框架功能概述

QT类库的模块
QT中的模块分为两大类
QT基本模块:提供了QT再所有平台上的基本功能
QT附加模块:实现一些特定功能的模块

基本模块

image-20250209023039408

附加模块

image-20250209023149900

QT附加模块可以实现一些特定目的,可能只在某些开发平台上有,或只能用于某些操作系统

QT全局定义

头文件(QT类的头文件都会包含该头文件)包含了QT类库的一些全局定义:
基本数据
函数

数据类型定义:
确保再各个平台上都有同意确定的长度

image-20250209030636816

image-20250209030650424

全局函数定义

image-20250209053057136

还有一些基础的数学原酸函数再头文件中定义,比如三角运算函数,弧度与角度之间的转换函数

宏定义

image-20250209053501541

image-20250209053509892

QT的元对象系统

QT中引入元对象系统堆标准C++语言进行了扩展
QObject类是所有使用原对象系统的类的基类
必须在一个类的开头部分插入宏Q_OBJECT,才可以使用元对象系统的特性。当MOC发现类中定义了Q_OBJECT宏时,会为其生成相应的C++源文件
元对象编译器是一个预处理器,先将Qt的特性程序转换为标准C++程序,再由标准C++编译器进行编译

Object类
image-20250212221442194

QMetaObject类
元对象是对类的描述,包含类信息、方法、属性等元数据
QObject和QMetaObject 提供了以下函数接口,可以获取运行时类型信息,类似标准的C++中的RTTI
image-20250212221629316

属性系统

在OObject的子类中可以通过Q_PROPERTY宏定义属性

image-20250216192921648

image-20250216192932650

这个部分后面太难了,学不懂,确定要用了再回来学

信号与槽

信号与槽是元对象系统支持的,对象间通信所采用的机制

connect函数的使用

image-20250216195058634

其中第一个参数是发送者,第二个参数是信号,第三个参数是接收者,这样就可以读懂了。
可知接收者往往就是指针,另这个函数是静态函数,所以不管在哪里调用都行。
比如在widget里面使用,那么肯定是指向widget的(子类)

如果信号和槽函数都存在重载的情况,则需要使用qOverload<参数类型>进行指定:

image-20250216201925347

上面的形式都是静态函数版本,无法获得对象本身的this指针。还有成员函数的版本

disconnect()函数的使用
image-20250216202257164

sender()函数
在槽函数里,使用QObject::sender()可以获取信号发射者的指针

1
QSPinBox*spinbox = qobject_cast<QSpinBox*>(sender())

自定义信号及其使用

image-20250216202421414

代码学习(基于C++)

声明:此部分的学习过程严格遵循《QT6 C++开发指南 2023》

image-20250117213926322

认识QT

简介:QT是一个跨平台的应用开发框架,也是最主流的C++开发框架
QT具有其他编程语言的拓展,但QT本身是用C++开发

跨平台

QT具有跨平台开发的的能力,只要熟悉一种平台的开发,很快就能适应其他平台的开发。并且QT源代码编译之后生成目标平台的原生二进制代码,不像JAVA那样需要虚拟机,运行效率更高。

QT支持的开发语言

C++和QML:
Q对标准的C+++语言进行了扩展,引入了信号和槽等机制。
QML是一个用来描述应用程序界面的声明式脚本语言
C++和QML可以混合使用
python:不做赘述

编写一个hello world程序

创建文件

image-20250117223552019

这里就要选择第一个了,因为现在要用C++的方式编写

重点是下图的地方要选qmake或者cmake,要求是选qmake

image-20250117223612580

image-20250117223650958

上面是选择基类,基本上也这样选,之后如果没有特殊情况都这样构建新项目。

构建完程序之后进入下面的画面,其中点击.ui文件自动跳转到了Design界面去编辑界面,编辑的方式类似早期我学过的VB,大概了解到了,这个.ui文件就是对于窗口布局的描述说明。

image-20250117223741477

再design里面找到label,然后拖到右边。

image-20250117225823302

就可以在这里写上hello world了
在右下角的部分可以改变文字的属性,框体也可以直接用拖动的方式编辑。
点击左下角就可以直接运行,这样第一个程序就结束了。

GUI程序设计基础

GUI程序结构与运行机制

image-20250117230212187

上面说了我们选择qmake的方式编写,这样一定会生成.pro结尾的配置文件,对于qmake中的配置文件有一些常见变量和含义(如下)

image-20250120172350271

再来说一下这个pro文件中常见的+=语法和格式,相当于把右边的包中的内容加到左边,类似于C++中的包含头文件

image-20250120172444538

qmake是构建项目的软件,它根据.pro文件生成makefile文件,然后C++编译器可以根据makefile文件进行编译和链接
qmake还会自动生成moc(meta-object compiler)和UIC(user interface compiler)生成构建规则

$$为替换函数的前缀

认识qt基础文件

pro文件在上面已经说了,剩下的几个文件我通过注释的方式大概了解一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { /*命名空间*/
class Widget;/*ui_widget.h里面定义的类,外部声明*/
}
QT_END_NAMESPACE

class Widget : public QWidget
{
Q_OBJECT//宏 使用qt信号与槽机制必须添加

public:
Widget(QWidget *parent = nullptr);
~Widget();

private:
Ui::Widget *ui;//Ui::Widget类型的一个指针,指向可视化的界面。
};
#endif // WIDGET_H

1
2
3
4
5
6
7
8
9
10
11
12
13
main.cpp
#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);//定义并创建应用程序
Widget w;//定义并创建窗口
w.show();//显式窗口
return a.exec();//应用程序运行,开始消息循环和事件处理
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
widget.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;
}

更改窗口标题

在如下图右下角位置可以更改
image-20250120225124520

信号与槽简介

信号与槽式QT编程的基础,也是QT的一大创新,它使QT中的组件就叫唤变得直观
image-20250120234108333

上面式信号槽多种实现方式中的一种,connect式QObject类中的静态成员函数。signal和slot式QT的宏,用于将哟参数转换为相应的字符串。下面式一些注意事项:
一个信号可以连接多个槽函数
多个信号可以连接同一个参函数
image-20250120234259986

一个型号可以连接另一个信号
QT还支持通过函数名称将信号和槽相关联,需要首先开启该功能。

QT项目构建过程的基本原理

image-20250120234428162

实操部分

关闭程序

因为全部是实操涉及代码 ,所以只能由我来描述操作的过程。实际过程也没办法用视频展示。首先按照惯例新建一个项目,然后来到ui设计的部分。然后拖入一个label 拖入一个btn。
然后就来到了这部分的关键操作:在下面选择信号与槽,然后选择刚才加入的按钮对象,事件选择关闭,对象选择整个widget窗口,触发选择点击。
到这里为止关闭的功能就做好了,可以直接运行程序。

image-20250120225551212

除此之外,关于修改按钮内容和标签内容,还可以通过代码的方式修改,在widget.cpp文件中使用this指针赋值就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->label->setText("这是用代码修改的标签");
ui->pushButton->setText("代码修改");
}

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

image-20250120233348033

同时经过我自己的测试,代码修改的方式优先级比直接在设置里面修改高。

可视化UI设计

项目要求

image-20250120233559611

注意 这个项目创建的时候必须要选择Qdialog作为窗口基类
比如我就做错了,所以下面的教程前面的部分都是根据错误的项目做的,但是步骤都是对的,只是中间我退回去重新构建了一下项目

加入qrc文件

image-20250121161042620

image-20250121161209236

成功导入之后进入设计页面,再右下角搜索icon,这个windowicon就是这个窗口左上角的图标了,然后通过右边的选择就可以选择刚才导入成功的bmp图标,然后再运行就会出现图中的样子,显示导入已经成功了,图标已经替换成了我们想要的图标。

image-20250121161426308

接下来就可以设计ui了
ui设计大致如下,上面我们已经改了窗口的图标
然后这里的设计用了两个group box 来排版
然后字体部分用了check box 颜色部分是radio button
下面就是一个可以输入的input widgets 输入窗口 选择的是Plain Text Edit

image-20250121162650778

构建好了基础的ui之后再为下方的三个按钮加上图标
首先选择要更改的按钮,点击之后在右下角搜索icon,然后通过选择的方式就可以选择到自己加入过的图标了。
image-20250121165351154

这里我做到这这一步 才发现程序建立的时候建立错误了。我的程序不是基于Qdialog的 我用了widget
所以这里我退回去重做了
重新构建完了之后,先进去信号与槽,然后通过选择把退出按钮的功能实现
然后把确定按钮的功能暂定为accept()

image-20250121180454871

接下来要做清空的功能,首先右键清空键,选择go to slot
然后选择clicked()

image-20250121180628616

image-20250121180656955

然后就进入了一个代码界面
image-20250121180726418

然后通过手动的方式写功能,调用了一个clear函数
image-20250121182524224

编写完了之后测试一下 功能正常
然后在来到字体部分,同样是右键点击。但是这里是要选择勾中和没勾中的状态,所以这里要选择布尔类型的clicked

image-20250121182702224

同样也是通过代码的方式修改,这里可能有点困难,所以我把截图先放上来,最后把代码全部放上来。
简单来说就是通过上面的操作修改之后,再通过下面的代码实现功能 三个字体操作的代码基本上是一样的
只有调用的set方法不同

image-20250121194003363

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#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_clearBtn_clicked()
{/*这里就相当于是用手动编写的方式给这个按钮添加功能*/
ui->plainTextEdit->clear();
}


void Dialog::on_checkBox_clicked(bool checked)
{/*下划线的本质是修改字体,所以我们要先拿到当前的字体然后修改
当前字体的下划线部分*/
QFont font = ui->plainTextEdit->font();
font.setUnderline(checked);
ui->plainTextEdit->setFont(font);
/*先创建一个字体对象 然后获取当前的字体
* 然后对获取到的字体调用添加下划线的方法
* 最后使用set方法设回字体
*/
}


void Dialog::on_checkBox_3_clicked(bool checked)
{
QFont font = ui->plainTextEdit->font();
font.setItalic(checked);
ui->plainTextEdit->setFont(font);
}


void Dialog::on_checkBox_2_clicked(bool checked)
{
QFont font = ui->plainTextEdit->font();
font.setBold(checked);
ui->plainTextEdit->setFont(font);

}


到这里为止 字体的部分已经全部设置好了,功能已经全部实现了。

接下来是关于颜色的部分,颜色是单选框 然后需要发送给同样的slots
说人话就是要手写代码了:首先来到头文件
首先在头文件里创建一个slot函数(注意slot函数的返回值类型都是void
然后再右键 去定义

image-20250121200915398

来到cpp文件的部分完成这里的代码 发现没有起作用

image-20250121223152431

说人话就是这里相当于只是写了一个函数,但是没有被调用,没有被加在主程序中,所以没有效果。

所以还要在上面的基类中加入connect
那么问题来了,怎么写这个connect语句
首先我们来到文件的顶部
然后点击上面自动生成的ui头文件
image-20250121223524908

在里面第一个函数结束前上方就可以找到
image-20250121223623940

然后我们手动添加connect就成功了

image-20250121225327404

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Dialog)
{
ui->setupUi(this);
connect(ui->blackRad,SIGNAL(clicked()), this, SLOT(do_FontColor()));
connect(ui->blueRad,SIGNAL(clicked()), this, SLOT(do_FontColor()));
connect(ui->redRad,SIGNAL(clicked()), this, SLOT(do_FontColor()));
}

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

void Dialog::on_clearBtn_clicked()
{/*这里就相当于是用手动编写的方式给这个按钮添加功能*/
ui->plainTextEdit->clear();
}


void Dialog::on_checkBox_clicked(bool checked)
{/*下划线的本质是修改字体,所以我们要先拿到当前的字体然后修改
当前字体的下划线部分*/
QFont font = ui->plainTextEdit->font();
font.setUnderline(checked);
ui->plainTextEdit->setFont(font);
/*先创建一个字体对象 然后获取当前的字体
* 然后对获取到的字体调用添加下划线的方法
* 最后使用set方法设回字体
*/
}


void Dialog::on_checkBox_3_clicked(bool checked)
{
QFont font = ui->plainTextEdit->font();
font.setItalic(checked);
ui->plainTextEdit->setFont(font);
}


void Dialog::on_checkBox_2_clicked(bool checked)
{
QFont font = ui->plainTextEdit->font();
font.setBold(checked);
ui->plainTextEdit->setFont(font);

}

void Dialog::do_FontColor()
{
QPalette plet = ui->plainTextEdit->palette();

if(ui->blackRad->isChecked())
plet.setColor(QPalette::Text,Qt::black);
if(ui->redRad->isChecked())
plet.setColor(QPalette::Text,Qt::red);
if(ui->blueRad->isChecked())
plet.setColor(QPalette::Text,Qt::blue);
ui->plainTextEdit->setPalette(plet);
}

dialog.h
#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

QT_BEGIN_NAMESPACE
namespace Ui {
class Dialog;
}
QT_END_NAMESPACE

class Dialog : public QDialog
{
Q_OBJECT

public:
Dialog(QWidget *parent = nullptr);
~Dialog();

private slots:
void on_clearBtn_clicked();

void on_checkBox_clicked(bool checked);

void on_checkBox_3_clicked(bool checked);

void on_checkBox_2_clicked(bool checked);
/*首先创造一个slot函数*/
void do_FontColor();


private:
Ui::Dialog *ui;
};
#endif // DIALOG_H



小结一下:上面主要讲了通过可视化UI设计(反正就是创建项目的时候选择genarate form,就是可视化ui设计了)来进行设计qt程序。第一步是创建程序,这个不赘述,第二部是设计UI,包括导入我们自己的图标等。第三步是给完成各个功能,主要通过代码的方式,操作底层逻辑暂时都学的差不多了,但是如何操作其他的还是不清楚。

代码化UI设计

image-20250121225445847

要求和上面的可视化UI设计一样,不同的是不勾选generate form,所以没有很多东西
说是更灵活,但是对我来说也更难。

cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "dialog.h"

#include <QHBoxLayout>
#include <QVBoxLayout>

#include <QCheckBox>
#include <QRadioButton>
#include <QPlainTextEdit>
#include <QPushButton>

void Dialog::do_chkBoxUnder(bool checked)
{
QFont font = txtEdit->font();
font.setUnderline(checked);
txtEdit->setFont(font);
}

void Dialog::do_chkBoxItalic(bool checked)
{
QFont font = txtEdit->font();
font.setItalic(checked);
txtEdit->setFont(font);
}

void Dialog::do_chkBoxBold(bool checked)
{
QFont font = txtEdit->font();
font.setBold(checked);
txtEdit->setFont(font);
}

void Dialog::do_setFontColor()
{
QPalette plet=txtEdit->palette();
if(radioBlack->isChecked())
plet.setColor(QPalette::Text,Qt::black);
if(radioRed->isChecked())
plet.setColor(QPalette::Text,Qt::red);
if(radioBlue->isChecked())
plet.setColor(QPalette::Text,Qt::blue);
txtEdit->setPalette(plet); // 应用新的调色板
}

Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
/*先创建三个组件*/
chkBoxUnder = new QCheckBox("下划线");
chkBoxBold = new QCheckBox("加粗");
chkBoxItalic = new QCheckBox("斜体");
/*创建一个水平布局容器*/
QHBoxLayout *HLayl = new QHBoxLayout();
//在水平布局容器里面添加三个组件
HLayl->addWidget(chkBoxUnder);
HLayl->addWidget(chkBoxItalic);
HLayl->addWidget(chkBoxBold);

//创建三个新的组件
radioBlack = new QRadioButton("黑色");
radioRed = new QRadioButton("红色");
radioBlue = new QRadioButton("蓝色");
QHBoxLayout *HLayl2 = new QHBoxLayout();
/*QHB是水平布局 让上面三个组件在同一列*/
HLayl2->addWidget(radioBlack);
HLayl2->addWidget(radioRed);
HLayl2->addWidget(radioBlue);
/*在水平布局容器里面添加三个组件*/
/*创建一个垂直布局容器*/
QVBoxLayout *Vlayl = new QVBoxLayout();/*QVB垂直布局 让上面两个组件在不同列*/

/*文本框*/
txtEdit = new QPlainTextEdit;
txtEdit ->setPlainText("hello world \n 手工创建!");
QFont font = txtEdit->font();
font.setPointSize(20);
txtEdit->setFont(font);

//按钮
btn0k = new QPushButton("确定");
btnCancel = new QPushButton("取消");
btnClose = new QPushButton("退出");
QHBoxLayout *HLayl3 = new QHBoxLayout();
HLayl3->addStretch();
HLayl3 ->addWidget(btn0k);
HLayl3->addStretch();
HLayl3 ->addWidget(btnCancel);
HLayl3->addStretch();
HLayl3 ->addWidget(btnClose);



/*在垂直布局容器里面添加组件*/
Vlayl->addLayout(HLayl);
Vlayl->addLayout(HLayl2);
Vlayl->addWidget(txtEdit);
Vlayl->addLayout(HLayl3);

setLayout(Vlayl);

/*连接*/
connect(chkBoxUnder,SIGNAL(clicked(bool)),this,SLOT(do_chkBoxUnder(bool)));
connect(chkBoxItalic,SIGNAL(clicked(bool)),this,SLOT(do_chkBoxItalic(bool)));
connect(chkBoxBold,SIGNAL(clicked(bool)),this,SLOT(do_chkBoxBold(bool)));
/*颜色*/
connect(radioBlack,SIGNAL(clicked(bool)),this,SLOT(do_setFontColor()));
connect(radioBlue,SIGNAL(clicked(bool)),this,SLOT(do_setFontColor()));
connect(radioRed,SIGNAL(clicked(bool)),this,SLOT(do_setFontColor()));
/*按钮*/
connect(btn0k,SIGNAL(clicked()),this,SLOT(accept()));
connect(btnCancel,SIGNAL(clicked()),this,SLOT(reject()));
connect(btnClose,SIGNAL(clicked()),this,SLOT(close()));

setWindowTitle("手工打造UI");

}

Dialog::~Dialog() {}

头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>

class QCheckBox;
class QRadioButton;
class QPlainTextEdit;
class QPushButton;


class Dialog : public QDialog
{
Q_OBJECT
private:
QCheckBox *chkBoxUnder;
QCheckBox *chkBoxItalic;
QCheckBox *chkBoxBold;

QRadioButton *radioBlack;
QRadioButton *radioRed;
QRadioButton *radioBlue;

QPlainTextEdit *txtEdit;

QPushButton *btn0k;
QPushButton *btnCancel;
QPushButton *btnClose;

private slots:
void do_chkBoxUnder(bool checked);
void do_chkBoxItalic(bool checked);
void do_chkBoxBold(bool checked);


void do_setFontColor();

public:
Dialog(QWidget *parent = nullptr);
~Dialog();
};
#endif // DIALOG_H

使用cmake构建系统

使用cmake构建系统(其他所有示例都使用qmake构建系统)
cmake是一个功能强大的跨平台的构建工具,它通过与平台和编译器无关的配置文件控制软件的构建过程(在不同的平台上使用不同的编译器),生成本地化的makefile文件或者IDE项目。很多大型的开源软件都使用cmake构建系统,qt6本身就是用cmake构建的。

本章节任务就是使用cmake实现上节课实现的。cmake项目是用cmake语言写的一些文件,项目的主文件是cmakeLists.txt

新建项目,这部分不赘述,容易错的点就是要选dialog

构建完了之后找到之间建立的qmake项目,把项目中的这四个部分覆盖到现在新建的cmake项目。

image-20250206144557275

然后修改一下ui的文字,重新保存,修改一下头文件,重新保存。(如果不修改,编译器不会判定为文件改变,不会保存也不会重新编译。)

然后在配置文件里面加上下面一行。

image-20250206144725274

然后重新保存,ui图标和功能就全部正常了

下面的部分是使用cmakeGUI生成VS工程,我认为用不到就先不学了,如果要用再回来学。

学习路线2

从按钮入手认识QT和样式

创建文件的过程不赘述,以下是按钮的mainwindow.cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
/*按钮的头文件 只有包含了头文件
后续的代码才可以使用按钮类型的对象*/

/*这个文件主要处理主窗口和图像方面的部分*/

//构造函数
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
/*在堆上创建了一个这个类型的对象
然后用指针Ui指向它*/
{
ui->setupUi(this);
/*ui指针指向函数
实际上的作用就是初始化控件*/

/*创建一个按钮*/
QPushButton * button = new QPushButton("01",this);
/*创建了一个QPB类型的指针,在堆上实例化了一个新对象*/

/*设置按钮的大小和位置*/
button->setGeometry(50,50,150,100);
/*前两个参数是按钮的位置xy坐标 后面的参数是宽和高。*/

/*设置按钮中字体的颜色*/
/*调用一个sSS方法 本质上是通过字符串传递一组css样式*/
button->setStyleSheet("color:red;"
/*设置按钮背景颜色*/ "background-color:lightblue;"
/*把字调大一点*/ "font-size:30px;");

/*下面主要是一些调整按钮样式的css*/
/*设置扁平化一些(隐藏式按钮*/
button->setFlat(false);
/*为了方便观察和调整 我们先改成false*/

/*设置按钮可见*/
button->setVisible(true);
/*如果写成false就不可以见了*/


}

MainWindow::~MainWindow()
{
/*析构*/
delete ui;
}

槽函数和lambda表达式

在上节课中我们已经建立了按钮,但是这个按钮并没有任何的功能,这节课通过槽函数我们就要给这个按钮赋予功能。
现在我们要给按钮赋予功能,现在以点击弹出提示框为例。

槽函数是 Qt 框架中用于处理信号(signal)和响应(响应事件)的核心机制之一。它是 Qt 中事件驱动编程的一部分,用于处理控件或其他对象触发的事件。

什么是槽函数?

槽函数是普通的成员函数或独立的函数,当某个信号发出时,槽函数会被调用。它们与 Qt 的信号-槽机制紧密结合,负责响应来自对象(如按钮、窗口等)发出的信号。

作用:

槽函数的主要作用是响应信号。它们使得 Qt 的对象可以根据特定事件或操作触发后执行某些操作。信号和槽提供了一种松耦合的机制,可以轻松实现不同对象之间的通信,而不需要彼此直接依赖。

Lambda 表达式(也称为匿名函数)是一种在 C++11 引入的语法,用于创建没有名字的内联函数。它允许你在代码的某个地方定义一个函数,并将其传递或直接使用,而无需先声明或定义一个完整的函数。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
/*按钮的头文件 只有包含了头文件
后续的代码才可以使用按钮类型的对象*/
#include <QMessageBox>

/*这个文件主要处理主窗口和图像方面的部分*/


/*槽函数 响应特定的信号事件。*/
// void onButtonClicked(){
// /*一个弹出信息类型的对话框,后面的语法是
// QMessageBox::information(parent, title, message, buttons, defaultButton);*/
// QMessageBox::information(nullptr,"提示","你点击了按钮");
// /*nullptr表示没有父窗口 但是这个参数不能省略。
// 第二个参数是提示框的标题
// 接下来就是文本 正文内容*/

// /*上面的就是正常的槽函数,然后就要吧槽函数连接到按钮里面
// 在下面通过connect连接*/

// }



//构造函数
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
/*在堆上创建了一个这个类型的对象
然后用指针Ui指向它*/
{
ui->setupUi(this);
/*ui指针指向函数
实际上的作用就是初始化控件*/

/*创建一个按钮*/
QPushButton * button = new QPushButton("01",this);/*前面是文本,后面是对象*/
/*创建了一个QPB类型的指针,在堆上实例化了一个新对象*/

/*设置按钮的大小和位置*/
button->setGeometry(50,50,150,100);
/*前两个参数是按钮的位置xy坐标 后面的参数是宽和高。*/

/*设置按钮中字体的颜色*/
/*调用一个sSS方法 本质上是通过字符串传递一组css样式*/
button->setStyleSheet("color:red;"
/*设置按钮背景颜色*/ "background-color:lightblue;"
/*把字调大一点*/ "font-size:30px;");

/*下面主要是一些调整按钮样式的css*/
/*设置扁平化一些(隐藏式按钮*/
button->setFlat(false);
/*为了方便观察和调整 我们先改成false*/

/*设置按钮可见*/
button->setVisible(true);
/*如果写成false就不可以见了*/

//connect(button,&QPushButton::clicked,onButtonClicked);
/*第二种方法 lambda表达式*/
connect(button,&QPushButton::clicked,[]{
QMessageBox::information(nullptr,"提示","你点击了按钮");
});
/*lambda中的中括号是捕获列表,这里是空的说明不捕获外部变量,只使用了自己内部定义的
代码逻辑和参数*/
/*{}中的内容是函数体 就是函数要实际执行的内容
用lambda表达式相当于一个临时匿名的槽函数 */

}

MainWindow::~MainWindow()
{
/*析构*/
delete ui;
}

垂直布局和水平布局

为什么需要一个中心部件?

QMainWindow 是 Qt 中用于构建主窗口的类,它具有许多预定义的区域(例如,菜单栏、工具栏、状态栏等),但是它没有一个默认的区域来放置你自己的控件。因此,你需要设置一个“中心部件”(central widget),作为显示控件的容器。

具体的原因

  1. QMainWindow 的布局限制:
    QMainWindow 自带了许多特殊的区域(例如菜单、工具栏、状态栏等),但是它本身没有提供直接用于添加控件的区域。你必须设置一个“中心部件”来填充主窗口的中央区域。
  2. 中心部件的作用:
    中心部件可以是任何 QWidget 类型的控件,布局管理器(如 QVBoxLayoutQHBoxLayout)会被应用到这个中心部件上,这样布局管理器中的控件就会显示在主窗口的中央区域。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*布局 垂直布局和水平布局*/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include<QVBoxLayout>/*垂直布局 vertical*/
#include<QHBoxLayout>/*水平布局 horizontal*/


MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*创建一个对象作为中心部件*/
QWidget * centralWidget01 = new QWidget(this);
/*设置成中心部件*/
setCentralWidget(centralWidget01);
/*创建一个新的垂直布局的对象作为容器 */
// QVBoxLayout * vBoxLayout01 = new QVBoxLayout();
/*进阶 改成水平的*/
QHBoxLayout * hBoxLayout01 = new QHBoxLayout();

QPushButton * button01 = new QPushButton("按钮1",this);
QPushButton * button02 = new QPushButton("按钮2",this);
QPushButton * button03 = new QPushButton("按钮3",this);
/*放大一下按钮*/
button01->setFixedSize(100,50);
button02->setFixedSize(100,50);
button03->setFixedSize(100,50);
/*然后把按钮添加到容器里*/
// vBoxLayout01->addWidget(button01);
// vBoxLayout01->addWidget(button02);
// vBoxLayout01->addWidget(button03);

/*改水平*/
hBoxLayout01->addWidget(button01);
hBoxLayout01->addWidget(button02);
hBoxLayout01->addWidget(button03);
/*这里的语法
容器-> 添加组件(添加的元素)*/

/*然后把这个容器放到中心部件里面 让这编译器知道这个容器是在中心位置*/
// centralWidget01->setLayout(vBoxLayout01);
centralWidget01->setLayout(hBoxLayout01);


}

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

微调框

QSpinBox

QSpinBox是QT框架中用于输入整数的微调框控件。用于可以通过点击微调框旁边的上下箭头来增加或者减少整数值,也可以直接在输入框中输入整数。它提供了设置了最小、最大值和步长的功能。

QDoubleSpinBox

和上面的类似,但他用于输入浮点数。用户可以通过上下箭头或者直接输入来改变值,再上述功能的基础上还提供了小数位数的功能。

常用方法

QSpinBox
setMinimum(int min):设置微调框的最小值。
setMaxIum(int max):设置最大值
setSingleStep(int step):设置每次点击上下箭头时数值的变化量
setValue(int value):设置微调框的当前值。
value():获取微调框的当前值。
QDoubleSpinBox
setMinimum(double min):设置微调框的最小值。
setMaxIum(double max):设置最大值
setSingleStep(double step):设置每次点击上下箭头时数值的变化量
setValue(double value):设置微调框的当前值。
value():获取微调框的当前值。
setDecimals(int prec):设置小数位数

在头文件中声明私有成员变量的好处:

  • 可以使得类的接口完整,类的使用者能够直接访问类中的控件和布局。
  • 遵循封装原则,类的实现细节可以隐藏在 .cpp 文件中,提供清晰的接口。
  • 可以方便其他类、模块和源文件与 MainWindow 类交互和调用这些成员。

配置OpenCV的方法!!!

自用版

因为跑起来问题非常的多,而且复杂,但是通过种种原因终于是成功引用了。

首先对于一个项目image-20250523214740333

点击这里添加库

image-20250523214752931

选择外部库

image-20250523214816999

选择这个

然后下面这个选项选择这个build

image-20250523214837032

导入成功之后会有这样的两段话

image-20250523214855535

把上面的换成绝对路径,把下面的换成加上include就行了

大作业开发

软件设计报告


一、软件设计任务概述

应用背景
随着计算机视觉和人工智能技术的快速发展,图像与视频处理软件在各个领域得到了广泛应用。例如,在医学影像分析、安防监控、工业检测以及娱乐应用中,图像与视频处理技术发挥着重要作用。本项目旨在开发一款功能全面、界面友好的图像与视频处理软件,支持基本的图像处理操作、视频处理功能以及基于深度学习的智能视觉分析。

任务目标

  1. 实现基本的图像处理功能,包括灰度化、二值化、均值模糊、伽马校正和边缘检测。
  2. 支持视频处理功能,包括视频播放、暂停、快进、快退以及马赛克处理。
  3. 集成基于YOLO的物体检测功能,实现对图像和视频中的目标检测。
  4. 实现人脸检测功能,增强软件的智能性。
  5. 提供友好的用户界面,使用户能够方便地操作和配置各项功能。

开发环境搭建

  • 操作系统:Windows 10 或更高版本。
  • 开发工具:Qt Creator 6.0 或更高版本。
  • 第三方库:OpenCV 4.5.0 或更高版本,用于图像和视频处理;
    dnn模块用于YOLO模型的加载与推理。
  • 其他依赖:C++编译环境(如MSVC)。

二、可行性研究、需求分析及进度规划

可行性研究

  1. 技术可行性
    • OpenCV和Qt提供了强大的图像和视频处理功能,能够满足项目需求。
    • YOLO模型在目标检测领域性能优越,且推理速度快,适合集成到实时处理中。
    • 人脸检测可以通过OpenCV自带的.CascadeClassifier实现,技术成熟。
  2. 经济可行性
    • 项目主要依赖开源库,无需额外购买许可证或付费服务,开发成本较低。
    • 仅需基本的硬件设备(如普通PC),无需高端服务器或专用设备。
  3. 操作可行性
    • 软件界面设计直观,用户无需专业培训即可上手。
    • 功能模块化设计,用户可以根据需求选择性使用功能。

需求分析

  • 用户需求

    • 专业用户(如研究人员、开发者)需要强大的图像处理和分析功能。
    • 普通用户(如摄影师、爱好者)需要简单易用的图像编辑工具。
  • 功能需求

    • 基本图像处理功能(灰度化、二值化等)。
    • 视频播放与处理功能。
    • 智能视觉分析功能(目标检测、人脸检测)。

进度规划

阶段 时间 描述
需求分析与设计 1周 确定功能需求,设计软件架构,完成UI设计。
开发阶段 3周 实现图像处理功能,集成OpenCV和YOLO模块,开发视频处理功能。
测试与优化 1周 测试各功能模块,修复bug,优化性能。
文档撰写与总结 1周 撰写软件设计报告,整理测试记录与开发心得。

三、软件设计的基本原理和采用的主要方法与技术

基本原理

  1. 图像处理
    • 基于OpenCV库实现图像的读取、显示和处理。
    • 使用滑块控件(QSlider)实现参数调节(如亮度、对比度)。
  2. 视频处理
    • 使用OpenCV的VideoCapture类实现视频的读取与播放。
    • 通过QTimer实现视频的实时显示与处理。
  3. AI智能视觉
    • 使用YOLO目标检测模型实现图像和视频中的目标检测。
    • 通过dnn模块加载预训练模型,进行实时推理。
  4. 人脸检测
    • 使用OpenCV的.CascadeClassifier实现人脸检测。
    • 通过滑块控件调节检测灵敏度。

主要方法与技术

  1. 模块化设计
    • 将功能模块化,如图像处理、视频处理、AI检测等,便于管理和维护。
  2. MVC模式
    • 模型(Model):数据存储与处理。
    • 视图(View):用户界面展示。
    • 控制器(Controller):处理用户输入与功能调用。
  3. 异步处理
    • 使用QTimer和信号槽实现视频的实时处理,避免主线程阻塞。

四、实现的过程与步骤

实现流程

  1. 需求分析与设计
    • 确定功能模块,设计软件架构。
    • 完成UI设计,使用Qt Designer绘制界面。
  2. 开发阶段
    • 实现图像处理功能(灰度化、二值化等)。
    • 集成OpenCV和dnn模块,实现YOLO目标检测。
    • 开发视频处理功能,包括播放、暂停、快进、快退。
  3. 测试与优化
    • 测试各功能模块,修复bug。
    • 优化性能,提升处理速度。

框图

1
2
3
4
5
6
7
8
9
10
11
12
13
+-------------------+       +-------------------+
| | | |
| 用户界面 |<----->| 控制器 |
| | | |
+-------------------+ +-------------------+
| |
| |
v v
+-------------------+ +-------------------+
| | | |
| 模型(数据) | | 视图(展示) |
| | | |
+-------------------+ +-------------------+

功能模块流程图

图像处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
用户点击“打开图片”按钮
|
v
读取并加载图片
|
v
显示原始图片
|
v
用户选择滤镜(如灰度化、二值化等)
|
v
应用滤镜并处理图片
|
v
更新并显示处理后的图片

视频处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
用户点击“打开视频”按钮
|
v
加载视频文件或摄像头流
|
v
显示视频第一帧
|
v
用户点击“播放”按钮
|
v
启动视频播放定时器
|
v
循环处理并显示视频帧
|
v
用户点击“暂停”或“停止”按钮
|
v
停止视频播放并更新界面状态

AI检测流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
用户点击“初始化YOLO”按钮
|
v
加载YOLO模型和分类名称
|
v
用户点击“开始检测”按钮
|
v
循环处理视频或图像帧
|
v
应用YOLO检测并标记目标
|
v
更新并显示检测结果

整体流程图

1
2
3
4
5
6
7
8
9
10
11
12
13
+-------------------+       +-------------------+
| | | |
| 用户界面 |<----->| 控制器 |
| | | |
+-------------------+ +-------------------+
| |
| |
v v
+-------------------+ +-------------------+
| | | |
| 模型(数据) | | 视图(展示) |
| | | |
+-------------------+ +-------------------+

详细步骤说明

  1. 用户交互
    • 用户通过界面按钮或控件触发功能请求。
  2. 数据加载
    • 根据用户选择,加载图片或视频文件,或开启摄像头流。
  3. 功能处理
    • 根据选择的功能模块,调用相应的处理函数(如图像滤镜、视频播放、目标检测)。
  4. 数据处理
    • 对加载的数据进行处理,如应用滤镜、检测目标、调整参数等。
  5. 结果展示
    • 将处理后的数据展示在界面上,供用户查看。
  6. 状态反馈
    • 更新界面状态,如按钮启用/禁用、处理进度等。

五、遇到的困难与获得的主要成果

遇到的困难

  1. 技术难点
    • YOLO模型的加载与推理速度优化。
    • 实时视频处理中多线程的协调与同步。
  2. 时间压力
    • 项目时间紧张,需要在短时间内完成多个功能模块的开发与测试。
  3. 资源限制
    • 由于硬件性能限制,YOLO模型的推理速度较慢,影响了用户体验。

获得的主要成果

  1. 成功实现了基本的图像处理功能,包括灰度化、二值化、均值模糊等。
  2. 集成并优化了YOLO目标检测功能,实现了对图像和视频的实时检测。
  3. 实现了视频的播放与处理功能,用户可以自由控制视频的播放速度与方向。
  4. 成功实现了人脸检测功能,增强了软件的智能性。

六、测试与运行记录

测试环境

  • 操作系统:Windows 10
  • 硬件配置:Intel i7处理器,16GB内存,NVIDIA GeForce GTX 1060
  • 软件版本:Qt 6.0,OpenCV 4.5.0

测试用例

  1. 图像处理功能
    • 打开一张图片,应用灰度化、二值化等滤镜,检查处理效果。
    • 使用滑块调节亮度和对比度,观察图像变化。
  2. 视频处理功能
    • 打开一段视频,播放、暂停、快进、快退,检查控制是否正常。
    • 应用马赛克处理,检查视频画质是否受到影响。
  3. AI检测功能
    • 打开一张图片,应用YOLO目标检测,检查检测结果。
    • 打开一段视频,应用YOLO目标检测,检查实时检测效果。

测试结果

  • 图像处理功能:运行正常,处理效果符合预期。
  • 视频处理功能:运行流畅,控制响应灵敏。
  • AI检测功能:检测准确率较高,但在复杂场景下可能误检。

测试截图
(以下为部分测试截图,展示了图像处理和目标检测的效果。)

Image Processing 1
图1:灰度化处理效果

Image Processing 2
图2:二值化处理效果

Object Detection
图3:YOLO目标检测效果


七、结果分析

功能实现

  • 软件成功实现了所有预设功能,包括图像处理、视频处理和AI检测。
  • 用户界面设计直观,操作简便,适合各类用户使用。

性能优化

  • 通过多线程和异步处理,提升了视频处理的流畅度。
  • YOLO模型的推理速度在硬件性能允许的范围内得到了优化。

用户体验

  • 软件运行稳定,功能切换流畅,用户反馈良好。
  • AI检测功能增强了软件的智能化,提升了用户体验。

不足与改进

  • 在复杂场景下,YOLO的检测精度可能不足,需要优化模型或使用更先进的算法。
  • 视频处理功能在低配置硬件上运行较慢,需要进一步优化代码性能。

八、软件开发心得

回顾整个开发过程,我深刻体会到软件开发的不易。从最初的代码敲击到功能的逐步完善,每一个环节都充满了挑战。尤其是在集成YOLO模型和优化视频处理性能的过程中,我经历了无数次的调试和优化,甚至在深夜里仍然在思考如何解决技术难题。

尽管开发过程中充满了困难,但最终的成功让我感到无比的成就感。通过这个项目,我不仅提升了自己的技术水平,还学会了如何在有限的时间内高效地解决问题。软件开发不仅仅是代码的堆砌,更是一种艺术,需要耐心、毅力和创造力。

这次开发经历让我明白,每一个功能的实现都离不开细致的思考和反复的测试。未来的开发中,我将继续保持这种严谨的态度,不断提升自己的技术水平,为用户带来更好的使用体验。

8d9a38ac18c35206c97fad90233d484

QT学习止步于此 再见了 的所有 QT福音战士

其他

关于bmp文件

看到视频教程里面用了很多的bmp文件,很多插入的文件也是bmp
但是因为没有花钱买原课程,只能蹭蹭免费的,所以这个问题需要我自己解决。
首先我找了阿里的图标库
iconfont-阿里巴巴矢量图标库
然后在里面找了几套适合的下载jpeg或者jpg格式,然后通过在线工具进行转换,得到了一套可以用的bmp格式的图标文件。
注意导入的时候需要在项目文件内部建一个文件夹,然后再在文件夹内放入图片,选择项目外部的文件夹进行导入报错了。

如何导入?
两种方法进行导入 第一种方法通过代码,修改pro文件,加入,这种方法不知道为什么失败了。
第二种方法 直接查看目录中的《加入qrc文件》部分即可