当前位置:   article > 正文

C++ Qt——从入门到入土 (一)

c++ qt

目录

1.环境的配置

1.1 Qt的下载

1.2 在Vs中配置Qt

1.3 解决中文乱码的问题

 2.第一个窗口(搜索窗口)

2.1 构造一个Qt Widgets项目

2.2 Qt初体验——窗口基本属性设置&调整

2.2.1 构造析构函数

2.2.2 设置窗口标题和大小

2.2.3 窗口初始位置的移动

2.2.4 窗口背景颜色设置

*2.2.5 QstyleSheet详细

3.Qt常用控件

3.0 何为控件

3.1 按钮——QPushButton

3.2 信号与槽函数

3.2.1 概述

3.2.2 槽函数与连接

3.2.3 信号与发射

3.3 自定义信号的发射

3.4 文本、图片的“显示屏”——QLabel

3.4.0 概述

3.4.1 初始化与文本设置

3.4.2 点缀QLabel

3.4.3 部分文字效果变化

3.4.4 图片的判断存在、读取、加载

3.4.5 图片在QLabel上的展示

3.4.6 例子——应用QLabel为窗口添加背景

*3.4.7 关于QWidget背景图片的其他设置方法

3.4.8 进击!利用QLabel播放动图

3.4.9 以上的全部代码及图片资源连接

3.5 文本输入框——QLineEdit(从这里开始正式布局搜索窗口)

3.5.0 概述

3.5.1 初始化与默认提示文字的设置

3.5.2 实现当输入框内有文字输入时激活搜索按钮

3.5.3 获取并展示搜索内容

3.6 模式、对象的选择框——QCheckBox

3.6.0 概述

3.6.1 QCheckBox的初始化

3.6.2 QCheckBox选中状态的反馈

3.7 Qt中的“小浏览器”——QTextBrowser

3.7.0 概述

3.7.1 基于QTextBrowser自定义一个历史记录浏览框控件

3.7.2 Qt框架下读取txt文本内容

3.7.3 在窗口中添加和初始化自定义的历史浏览框

3.7.4 历史记录框的隐藏与失能


1.环境的配置

1.1 Qt的下载

Qt的下载链接如下:Index of /archive/qt/5.12/5.12.3

常见问题&解决:

我在下载时遇到了浏览器拦截,说无法安全下载此文件,解决的办法是在浏览器的设置选项中关闭智能拦截(关掉如图的选项即可)

 注意:

Qt挺大的,占用大概20G的内存,所以要注意好安装的位置避免空间不够得重新安装

安装步骤:

参考:(18条消息) QT安装具体图解_流楚丶格念的博客-CSDN博客_qt安装


1.2 在Vs中配置Qt

第一步:添加系统环境变量

首先找到桌面的我的电脑图标,右键点击选择属性,然后依次点击高级系统设置和环境变量

 找到自己安装的Qt的路径,进入后找到如下几个bin的位置并依次添加到系统环境变量的path中去:

第二步:下载Qt tools

在Vs的扩展->管理扩展中搜索Qt找到要下载的扩展工具(下载好之后需要重新打开 Vs)

 划重点!!!

下载好之后记得关闭Qt Tools的自动更新(如下图),否则整个项目都会出现奇奇怪怪的错误。

此后进行Vs的环境配置:

如图依次点击:扩展->Qt Vs Tools->Options 

再按照下图进行版本添加

 

 至此,环境已配置完成!


1.3 解决中文乱码的问题

在新建的Qt项目中(新建Qt项目详见2.1),按照下图顺序进行编码设置

 

 2.第一个窗口(搜索窗口)

2.1 构造一个Qt Widgets项目

首先,依次按照下图建立一个新的Qt项目,一般都继承自QWidget,因为这貌似是Qt所有窗口类的基类。

搞定后点击Finish就得到了一个带一个继承自QWidget类的窗口的Qt项目

2.2 Qt初体验——窗口基本属性设置&调整

2.2.1 构造析构函数

在这之前我们先干一件事——写好析构函数以避免内存外溢。

通过如上方式构造的一个窗口类中,一开始就有一个私有成员

Ui::FinddialogClass ui;

乍一看貌似没有指针成员析构与否并不影响,但是在之后添加控件时我们往往以指针的形式来定义它们,这时候挨个析构过去相当麻烦,所以Qt的这个ui变量如果写成指针的形式,然后再在析构中释放ui指针的内存即可自动释放掉该Qt类下的所有指针成员的内存。 

将上述代码修改为:

Ui::FinddialogClass *ui;

紧接着构造析构函数:

头文件中:

  1. class Finddialog : public QWidget
  2. {
  3. Q_OBJECT
  4. public:
  5. Finddialog(QWidget *parent = Q_NULLPTR);
  6. //析构防止内存溢出
  7. ~Finddialog();
  8. private:
  9. Ui::FinddialogClass *ui;
  10. };

源文件中:

  1. //析构防止内存溢出
  2. Finddialog::~Finddialog()
  3. {
  4. delete ui;
  5. }

2.2.2 设置窗口标题和大小

接下来我们在类的初始构造函数中设置窗口标题和其大小

  1. Finddialog::Finddialog(QWidget *parent)
  2. : QWidget(parent)
  3. {
  4. ui->setupUi(this);
  5. //设置窗口标题
  6. setWindowTitle(tr("查询系统"));
  7. //重设窗口大小
  8. resize(1080, 720);
  9. };

效果如下:

让我们看看函数原型来了解一下参数:

标题设置函数:setWindowTitle(const QString &);

可见其参数类型为一个QString对象,而QString类是整个Qt对字符串处理使用的类。

因此在自己直接写入字符串时最好以tr()包裹,这时一个好习惯(参考自C++ Gui Qt4编程一书)

所以显然下述程序是错误的:

  1. #include "finddialog.h"
  2. #include <string>
  3. using namespace std;
  4. string my_title = "查询系统";
  5. Finddialog::Finddialog(QWidget *parent)
  6. : QDialog(parent)
  7. {
  8. ui->setupUi(this);
  9. //设置窗口标题
  10. setWindowTitle(my_title);
  11. //重设窗口大小
  12. resize(1080, 720);
  13. };

要解决这个问题就涉及到了String类与QString类之间的转换:

从String转换为QString:

利用函数QString::fromStdString(String &);

将QString转换为String:

xx.toStdString()

其中xx为一个QString对象

即上述例子应该修改为:

  1. #include "finddialog.h"
  2. #include <string>
  3. using namespace std;
  4. string my_title = "查询系统";
  5. Finddialog::Finddialog(QWidget *parent)
  6. : QWidget(parent)
  7. {
  8. ui->setupUi(this);
  9. //设置标题与大小
  10. setWindowTitle(QString::fromStdString(my_title));
  11. setFixedSize(1080, 720);
  12. }
  13. //析构
  14. Finddialog::~Finddialog()
  15. {
  16. delete ui;
  17. }

大小设置函数:setFixedSize(const QSize &);

其中QSize为Qt框架下的尺寸类型,即(宽,高)两个整数

当然Qt还提供了设置宽和高(横向和纵向)的两个函数:

setFixedHeight(int h);

setFixedWidth(int w);

2.2.3 窗口初始位置的移动

窗口初始生成位置的移动依托于下面的函数

move(const QPoint &);

其中QPoint表示Qt坐标系下的一个点,这里就要说说Qt坐标系,我们假设QPoint的坐标构成为(x, y),则坐标系可如下图所示:

 可以看出QPoint的第一个坐标值也就是x越大则该点在屏幕上越靠右,y值越大则越靠下

而这里的move函数实际上是以窗口的左上角为基准,通过将左上角的点放到指定的QPoint处来实现窗口初始位置的变化。

可以在窗口初始化时添加move代码:

  1. Finddialog::Finddialog(QWidget *parent)
  2. : QWidget(parent)
  3. {
  4. ui->setupUi(this);
  5. //设置标题与大小
  6. setWindowTitle(QString::fromStdString(my_title));
  7. setFixedSize(1080, 720);
  8. //窗口生成位置移动
  9. move(500, 200);
  10. }

效果如下:

2.2.4 窗口背景颜色设置

函数原型:

setStyleSheet(const QString &styleSheet);

这里设置背景色用到的sheet写法为:"QXx { background-color : QColor;}"

其中:QXx为要设置的控件的Qt基类,比如这个窗口继承自QLabel那就写成"QLabel { backgroung-color : QColor;}"。而QColor指Qt中表示颜色的数值

其中常用的QColor表示法有三种:

1.使用系统预置颜色

如:"QLabel { backgroung-color : green;}"、"QLabel { backgroung-color : blue;}"等

这里可以用的颜色有:redgreenblueyellowgray、black、whiteorangepinkbrown、beige(米白色)、aqua(水绿色)、tan(褐色)、silvergoldskyblue等等

以米白色为例:

  1. Finddialog::Finddialog(QWidget *parent)
  2. : QWidget(parent)
  3. {
  4. ui->setupUi(this);
  5. //设置标题与大小
  6. setWindowTitle(QString::fromStdString(my_title));
  7. setFixedSize(1080, 720);
  8. //窗口生成位置移动
  9. move(500, 200);
  10. //设置
  11. setStyleSheet("QWidget { background-color : beige;}");
  12. }

注意:当你写的是不存在的预置颜色会默认设置成黑色

2.使用RGB三原色表示法(rgba(r, g, b))

例:"QLabel { backgroung-color : rgba(174, 221, 129);}"

效果如下:

这里推荐一篇博客:(18条消息) 好看的常用背景色RGB数值_wujinpengjiusan的博客-CSDN博客_好看的颜色rgb

3.使用十六进制表示颜色

如:"QLabel { backgroung-color : #3697ad;}"

效果如下:

使用时建议参考网站:#3c8dbc十六进制颜色代码表,图表,调色板,绘图&油漆 (encycolorpedia.cn)

*2.2.5 QstyleSheet详细

参考博客:(18条消息) 【Qt开发】StyleSheet使用总结_码农code之路-CSDN博客_stylesheet用法

在QstyleSheet中有下面这些枚举量:

background-color:Qcolor;      背景色

color:QColor;                  字体颜色

border-radius:Rpx;                    边框圆角半径(R为int型表示圆角半径)

border:2px solid green;                边框2像素,实现,绿色

font:10pt;                      字体大小10

应用到一个按钮控件则得到:(详见2.3.1)

先在.h文件中在窗口类下添加一个关闭按钮指针成员(记得引入#include <QPushButton>)

QPushButton* closeButton; 

在到.cpp的窗口类构造函数中初始化它

  1. // 初始化按钮
  2. closeButton = new QPushButton(tr("关掉我吧!")); // 分配空间
  3. closeButton->setParent(this); // 绑定到当前窗口
  4. closeButton->setFixedSize(100, 30); // 大小设置
  5. closeButton->move(980, 0); // 右上角
  6. // 样式设置
  7. closeButton->setStyleSheet("QPushButton { background-color : white;"\
  8. "color : blue;"\
  9. "border-radius : 2px;"\
  10. "border : 2px solid green;"\
  11. "font : 15px;}");
  12. // 点击时关闭
  13. connect(closeButton,
  14. &QPushButton::clicked,
  15. this,
  16. &Finddialog::close);

效果如下: 

这里特别解释一下setStyleSheet中的\符号:

因为要同时设置多个属性的时候堆在一行里代码的可读性会很差很差,所以我们常常会一个属性独占一行,而每个属性的设置都是由一串QString字符设置的,那么分行时就要注意字符串的拼接问题,这里的\符号就是用来拼接跨行的字符串的

举一个很简单的例子:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. cout<<"我爱"\
  6. "C艹!"\
  7. "C艹,"\
  8. "万岁!"<<endl;
  9. }

 随便来个简单的编译器比如dev-c++运行一下这个小例程得到的结果将是下图:

 可以看到利用\可以使分行的字符串进行无缝衔接,这一招在Qt框架下同样管用

3.Qt常用控件

3.0 何为控件

什么是控件呢,字面理解就是可以控制的部件。它是人机交互的渠道,通过对一个控件进行点击、双击、输入等操作可以使其发出信号,而对应的信号被某些控件接受时就会执行对应的槽函数。(关于信号和槽函数详见后文)比如2.2.5中的关闭按钮例子,在我们点击关闭按钮时,这一点击信号会被这个按钮发射出来,并由我们的Finddialog窗口接受,同时执行关闭窗口的操作。

所以控件就可以简单的理解成是一个可视化的交互渠道。当然你也可以使他失能变成静默控件,即不能被点击、选中或输入,只能拿来看。


3.1 按钮——QPushButton

接下来我想通过按钮来让你快速入门控件并对信号和槽函数的机制有一个初步的印象。

为一个窗口添加一个控件的基本流程如下:

 先来看一个具体的例子吧,还是以2.2.5中的关闭按钮为例:

首先进行头文件中的声明步骤(1、2步)

 然后转到.cpp中进行按钮的初始化

 如此一来便得到了一个关闭按钮。

下面来逐步分析:

第一第二步有类基础的你应该不难理解,就是将一个窗口中的每一个控件声明成该窗口的一个成员变量。以此将控件的操作权给到该窗口。

第三步中,由于我们习惯性地将控件以指针的方式进行编写,那么第一步自然是分配空间。也即:

closeButton = new QPushButton(tr("关掉我吧!"));

这里用到了一个带参构造,将你想要呈现在按钮里的文本放入QPushButton的参数中。

当然也可以用无参构造和设置按钮文本来实现,比如:

  1. closeButton = new QPushButton;
  2. closeButton->setText(tr("关掉我吧!"));

这里用到了Qt控件的一个比较通用的方法:

设置控件上的文本内容:

setText(const Qstring &);

这一方法许多控件都具有。

这时候如果你已经急不可耐地运行了你就会发现一个问题——在窗口上找不到按钮。这是为什么呢?因为在Qt框架下,控件与窗口之间是子和父的关系,想要让一个控件在一个窗口上展现出来就要明确的说明该控件的“父亲”——也就是它要在哪展示。

这一关系的声明用到了一个所有控件都有的方法:

setParent(QWidget* parent);

从这个函数原型我们也可以发现父指针的类型是QWidget*,这侧面反映了QWidget是Qt窗口类中的基类这一事实。那么,调用这个方法将关闭按钮绑定到当前窗口就很简单了。因为这一步往往在当前窗口的构造中同步进行,所以括号中就是this指针(当前窗口对象的指针)

closeButton->setParent(this);

紧接着就是大小、位置、样式的设置,这里用到的方法和上面窗口设置中介绍的一样:

大小设置用:setFixedSize(const QSzie &);resize(const QSzie &);

位置的设置用:move(const QPoint &);

样式设置用:setStyleSheet(const QString &styleSheet);

即:

  1. closeButton->setFixedSize(100, 30); // 大小设置
  2. closeButton->move(980, 0); // 右上角
  3. // 样式设置
  4. closeButton->setStyleSheet("QPushButton { background-color : white;"\
  5. "color : blue;"\
  6. "border-radius : 2px;"\
  7. "border : 2px solid green;"\
  8. "font : 15px;}");

接下来,要实现点击这个按钮时让窗口关闭,这就要用到Qt中特有的信号&槽函数机制!

敲重点!!!(信号和槽函数是重中之重!!!)


3.2 信号与槽函数

3.2.1 概述

信号和槽函数的机制在我看来是一项成功的仿生学(手动狗头/dodge)。这一机制是用在控件与窗口还有系统进行交互的过程中的,用人话说就是程序中的几个部分互相请求“帮忙”的过程

想象一下你需要别人帮忙的时候是怎样的步骤:

1.发现自己有麻烦需要帮忙了

2.将这一信号通过语言或者文字传递给能给你提供所需帮助的人

3.那个人帮你解决困难

注意上面加粗的四个部分,它们就对应了信号与槽函数的四大要素——信号发送者、信号、信号接收者、槽函数

其中信号发送者,也就是“你”,往往是某一个控件,而信号接收者则既可以是一个控件也可以是窗口。

那么就只剩下信号和槽函数是我们比较陌生的了。接下来逐一介绍。

3.2.2 槽函数与连接

先说槽函数(因为Qt的许多类中已经预置了很多信号)。

假如现在“帮助者”收到了一个要关闭窗口的信号请求,那就要通过槽函数来实现。而怎样的请求应该对应怎样的帮助是需要预先就定义好的。前面说了“帮助者”可以是控件或窗口,而控件与窗口之间有明确的子-父关系,那么我们只要将槽函数定义在窗口中即可。

关于这一点,进一步理解就是帮助的“权限”或者说能力。比如关闭窗口这一动作是父亲窗口的变动,依托于它生存的儿子控件们不一定有可以操纵它的权利。或者说这个忙控件们没有能力帮助,而控件可以操纵的窗口也一定可以操作,因此将所有槽函数声明在窗口中是十分合理的。

定义的方式为在public slots:下定义

以关闭窗口为例,则有:

.h中在窗口类的public slots:下定义该槽函数

  1. class Finddialog : public QWidget
  2. {
  3. Q_OBJECT
  4. public:
  5. Finddialog(QWidget *parent = Q_NULLPTR);
  6. private:
  7. Ui::FinddialogClass* ui;
  8. QPushButton* closeButton;
  9. public slots:
  10. void close_window();
  11. };

.cpp中进行实现

  1. // 初代关闭窗口的槽函数
  2. void Finddialog::close_window()
  3. {
  4. this->close();
  5. }

到这里,“帮助者”已经知道自己收到关闭信号时应该干啥了,此时距离成功就差临门一脚——怎么将四个要素连接起来

在Qt框架下,连接交互四要素的工具是connect函数,而connect有两种常见的用法:

第一种:

  1. connect(sender, //信号发射者,为一个指针
  2. &Filed::signal, //发射的信号,形式为&加上作用域加上信号函数名
  3. reciver, //信号的接收者,为一个指针
  4. &Filed::slot); //对应的槽函数,形式为&加上作用域加上槽函数名

这一种写法的特点是signal与slot的参数不用写出来,十分简洁漂亮。适用于不需要传递具体信息时的情况。

第二种:

  1. connect(sender, //信号发射者,为一个指针
  2. SIGNAL(signal(arg type)), //发射的信号,形式为SIGNAL括号内加上带参数的信号函数
  3. reciver, //信号的接收者,为一个指针
  4. SLOT(slot(arg type))); //对应的槽函数,形式为SLOT括号内加上带参数的槽函数

这里值得注意的是:信号函数和槽函数种的参数只需要保留类型!!!不用具体写出参数名!

例如有一个代表大脑的指针brain发出信号函数want_eat(QString &food);和一个嘴巴mouth对应的槽函数eat(QString &food);

则用这种连接方式应写为:

  1. connect(brain, //信号发射者——大脑
  2. SIGNAL(want_eat(QString &)), //发射想吃东西的信号,并且带有一个字符信息表示想吃啥
  3. mouth, //嘴巴接受到这一信号
  4. SLOT(eat(QString &))); //开始恰想恰的东西

这种写法就适用于信号和槽函数之间有参数传递的情况。


而这里我们的点击信号和关闭槽函数显然不需要有参数的传递,所以写为:

  1. // 点击时关闭
  2. connect(closeButton,
  3. &QPushButton::clicked,
  4. this,
  5. &Finddialog::close_window);

这样我们就实现了点击关闭按钮实现关闭窗口的功能 

3.2.3 信号与发射

再来说说信号,回到前面的例子,信号是求助者像帮忙者发出的信号,而这一信号只需要包含一些必要条件,比如“今晚到凤凰城边上替我打个麻将”这一求助信号就包含了时间、地点等信息,但往往求助的信号是不含很多具体信息的,比如“帮我答个到”、“帮我带个饭”、“老师捞捞”等等。但无论含有多少具体信息,它们都有一个共性——求助者除了发出求助信号外往往不用做出其他举措。所以信号函数在定义时大多是只定义而不实现的。

那么信号函数应该如何定义呢?由于它不用实现的性质,所以直接在信号发射者对应的.h文件中的类内的signals:下定义好即可。并且由于控件与窗口的父子关系与窗口的全局性,所以一般我们让自定义的信号由当前的窗口来发射,于是自定义信号函数一般都是定义在窗口类的signals:下的。

比如上述想吃东西的信号,在定义时就可以写成:

  1. signals:
  2. void want_eat(QString &food);

而这一信号并不需要在.cpp的源文件中进行实现。

到这里其实还不够,前面说了,信号是需要发射的,而常用的一些信号比如鼠标点击、键盘输入等等在Qt框架下是已经预设了的,它们的发射一般不需要我们自己实现,比如上面的关闭按钮的实现中的按钮点击信号QPushButton::clicked(),在我们用鼠标点击按钮时他就会自己发射这一信号,而这一步实现其实是封装在QPushButton中了的。而在我们自定义信号时,想要发射它还需要进行实现。一般发射信号的步骤会加在某一槽函数中。比如看到了一个食物的槽函数会在现在饥饿状态时发射一个想吃这个食物的信号。如:

  1. public slots:
  2. void see_food(QString &food)
  3. {
  4. if (is_hungry())
  5. {
  6. emit want_eat(food);
  7. }
  8. }

可以看到,这其中发射信号时使用的语法是emit + 信号函数。

上述就是信号的定义与发射的过程,接下来我们通过一个具体的例子来巩固一下。

假设现在有一个这样的需求——需要在窗口中添加一个按钮,点击一次它就会“逃跑”一次(即随机移动一次),同时根据点击次数刷新文本。

乍一看直接使用QPushButton::clicked()的预设信号就好,可是很快我们就应该意识到这样不行,因为我们需要获取点击的次数。这时候就需要自定义一个信号函数来表示第几次被点击了。

而点击次数计算我选择在发射点击几次的信号的槽函数中利用静态变量来计数。下面我先贴上我的实现代码然后进行分析。

finddialog.h为:

  1. #pragma once
  2. #include <QtWidgets/QWidget>
  3. #include "ui_finddialog.h"
  4. #include <QPushButton>
  5. #include <QMessageBox>
  6. #include <QRandomGenerator>
  7. class Finddialog : public QWidget
  8. {
  9. Q_OBJECT
  10. public:
  11. Finddialog(QWidget *parent = Q_NULLPTR);
  12. private:
  13. Ui::FinddialogClass* ui;
  14. QPushButton* closeButton;
  15. // 信息对话框
  16. QMessageBox* info_box = NULL;
  17. // 调皮按钮
  18. QPushButton* misc_button;
  19. signals:
  20. // 调皮按钮点击信号
  21. void misc_clicked(const QString& num);
  22. public slots:
  23. void shutdown_window();
  24. void close_window();
  25. // 发射点击信号
  26. void send_misc_clicked();
  27. // 调皮按钮开始调皮
  28. void misc_change(const QString& num_str);
  29. };

finddialog.cpp为:

  1. #include "finddialog.h"
  2. Finddialog::Finddialog(QWidget *parent)
  3. : QWidget(parent)
  4. {
  5. ui->setupUi(this);
  6. // 设置标题与大小
  7. setWindowTitle(tr("图鉴系统"));
  8. setFixedSize(1080, 720);
  9. // 窗口生成位置移动
  10. move(500, 200);
  11. // 设置
  12. this->setStyleSheet("QWidget { background-color : rgba(174, 221, 129);}");
  13. // 初始化关闭按钮
  14. closeButton = new QPushButton(tr("关掉我吧!")); // 分配空间
  15. closeButton->setParent(this); // 绑定到当前窗口
  16. closeButton->setFixedSize(100, 30); // 大小设置
  17. closeButton->move(980, 0); // 右上角
  18. // 样式设置
  19. closeButton->setStyleSheet("QPushButton { background-color : white;"\
  20. "color : blue;"\
  21. "border-radius : 2px;"\
  22. "border : 2px solid green;"\
  23. "font : 15px;}");
  24. // 点击时关闭
  25. connect(closeButton,
  26. &QPushButton::clicked,
  27. this,
  28. &Finddialog::shutdown_window);
  29. // 初始化调皮按钮
  30. misc_button = new QPushButton(tr("我是调皮按钮捏声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/429748
    推荐阅读
    相关标签