- 目录
- 一、Qt概述
- 二、基于Qt创建GUI程序(对应P1-P12)
- 三、基础知识点(对应P13-P28)
- 3.1 Qt专门数据类型
- 3.2 日志输出
- 3.3 字符串类及其相关方法
- 3.4 QVariant类
- 3.5 坐标类QPoint
- 3.6 直线类QLine
- 3.7 直线类QLine
- 3.8 矩形类QRect
- 3.9 日期类QDate、时间类QTime和日期与时间类QDateTime
- 四、信号槽(signals & slots)(对应P29-P35)
- 4.1 信号与槽概述
- 4.2 标准信号槽使用【重要】
- 4.3 自定义信号槽使用【重要】
- 4.4 信号槽扩展
- 4.4.1 信号槽使用扩展
- 4.4.2 信号槽的两种连接方式(对应P34)
- 4.4.3 Lambda表达式
- 五、定时器类QTimer(区别于时间类QTime)(P36-37)
- 六、窗口类QWidget、QDialog、QMainWindow(P38-P56)
- 6.1 QWidget类(P38-P40)
- 6.2 QDialog类(P41-P50)
- 6.2.1 QDialog类自身(P41-P42)
- 6.2.2 QDialog子类: QMessageBox(P43)【重要】
- 6.2.3 QDialog子类: QFileDialog(P44)【重要】
- 6.2.4 QDialog子类: QFontDialog
- 6.2.5 QDialog子类: QColorDialog
- 6.2.4 QDialog子类: QInputDialog(P47-P48)【重要】
- 6.2.4 QDialog子类: QProgressDialog
- 6.3 QMainWindow类(P51-P56)【重要】
- 6.3.1 菜单栏
- 6.3.2 工具栏
- 6.3.3 状态栏
- 6.3.4 停靠窗口(Dock Widget)
- 6.3.5 资源文件
- 七、窗口布局
- X、Qwt概述
目录
笔记整理于Qt开发编程-入门基础教程Qt5等系列视频,侵权自删!
一、Qt概述
- 定义:Qt是一个跨平台的C++应用程序开发框架。
- 用途:被广泛用于开发GUI(图形化用户界面)程序,也可以用于开发非GUI程序。
- 注1:Qt提供了大量可调用的类库,帮助我们实现各种功能。当我们想要使用某些类库时,需要将其对应的模块加载到项目之中(个人理解:类似于C++中的include头文件操作)。
- 注2:Qt Creator是Qt程序的一款IDE(用VS也可以编写Qt程序)。
二、基于Qt创建GUI程序(对应P1-P12)
- 步骤:参考系列视频的P7
- 说明:(1)生成的文件中,XXX.pro基本不需要我们进行修改(如果我们要使用Qt的其他模块时,需要在该文件的第一行进行添加);(2)YY.h、YY.cpp和YY.ui三者可以视为绑定在一起的三个文件。
- MSVC、MinGW这些是Qt的编译套件,在创建GUI程序时可以进行选择。
- Qt代码使用#进行注释。
- Qt有三个窗口类:QWidget、QDialog和QMainWindow。
- 对于Qwidget而言,它是是所有窗口类的基类。它既可以内嵌到主窗口中,也可以不内嵌(通过是否给定参数this来实现)。
- 对于对话窗口类QDialog而言,其具有模态(使用exec函数)和非模态(使用show函数)两种显示方式。在模态显示方式下,Dialog将会阻塞程序的执行。这表现为:如果此时有多个子窗口,那么将不能进行随机切换(不能实现焦点切换),此时我们只能先关闭Dialog窗口。而在我们关闭了Dialog子窗口之后,主窗口MainWindow才能够显示出来。
- 对于窗口类QMainWindow而言,其不可以作为内嵌窗口,并且其还拥有额外的菜单栏、状态栏和工具栏。其中工具栏可以有多个。
- 【如何添加子窗口】右键点击项目名,点击其中的Add new选项,进行选择即可。
- 关于Qt的坐标原点:原点在窗口左上角,x轴正向右,y轴正向下。
- 【一个感受】 我们常做的一个操作是:在最上面include某个库,然后基于某个对象调用这个库中的某些函数!
- 关于Qt的内存回收机制:只有满足一定条件的被new出的对象才能被回收——①创建的对象必须是QObject类的子类(间接子类也可以);②创建出的类对象,必须要指定其父对象是谁(常用this)。
- Qt中的qDebug()作用相当于C++中的cout。
三、基础知识点(对应P13-P28)
3.1 Qt专门数据类型
Qt是C++框架,因此支持C++所有数据类型(int、long等)。除此以外,Qt还自定义了一些数据类型。【注1】我们只需要了解这些数据类型即可,在实际应用中没有必要使用这些数据类型。 【注2】Qt的基本数据类型定义在#include <QtGlobal>中,这个文件中也包括了很多宏(Macros)。 【注3】鼠标选中某个类,按下F2即可查看该类的源代码(类似于回调查看)!
3.2 日志输出
- 想在Qt中进行log输出,需要使用专门的类,其头文件名为QDebug(这对应了C中的printf、C++中的cout)
- 例子:qDebug() << "我很帅" << " * " << 10000;
- 【主要】修改完代码之后,我们应该先点击.pro文件进行重新构建,然后再点击左下角的三角形进行编译!!
- 如果我们想在点击Debug目录下的Debug.exe时也看到输出内容(即看到日志输出)的话,就需要修改.pro文件中的部分代码为CONFIG += c++11 console(原先只有CONFIG += c++11),此时我们在点击exe文件后,将会跳出一个终端窗口。
3.3 字符串类及其相关方法
- Qt中可以使用C中的char*、C++的std::string以及Qt自身的QByteArray或QString,来表示字符串类型。
- 对于QByteArray,我们可以使用相关函数完成字符串拼接、插入、删除等操作。例如void QByteArray::truncate(int pos)的作用即为从字节数组的pos位置将数组截断(前面部分留下,后面部分被删除)。此外,还可以完成子字符串查找和判断、遍历、查看字节数、类型转换等操作。
- 对于QString,其相关函数及其功能和QByteArray差不多。【注意】字符串大小写敏感即区分大小写的意思。
- 二者的区别包括:(1)QString可以对QByteArray进行进一步的封装(QByteArray是对char *的简单封装,而QString是对char *的深度封装。也因此,QByteArray可以直接转换为char *,而QString需要先转换为QByteArray);(2)QString可以设置字符串敏感而QByteArray不可以;(3)对于同一个字符串,QString和QByteArray计算长度得到的结果不同(QString的长度是字符个数,一个汉字算一个字符;QByteArray的长度是字符串占用的字节数,一个汉字占三个字节)。
3.4 QVariant类
- QVariant类中可以包括各种数据类型。在实际使用中,QVariant可以视作泛型!
- 【注意】当我们在.h文件中声明一个方法时,可以按下alt + 回车键,从而跳转到.cpp文件中添加相关定义。该方法的测试也在.cpp文件中进行。—— 这也对应了.h和.cpp文件的功能,前者用于声明各种方法,后者用于定义各种方法的内容!
- 使用QVariant类不仅可以对Qt中的标准类型数据进行处理,也可以对自定义类型进行处理。这大大扩展了该类的实用性。
- 【注意】在使用自定义类型时,需要使用宏Q_DECLARE_METATYPE!—— 这好像在资料代码中有看到!!
- 【注意】按下F4,可以直接从.h文件跳转到.cpp文件。
3.5 坐标类QPoint
- 使用场景:移动某个窗口到某个位置。
- 作用:设置坐标、获取坐标、坐标值算数运算等。
3.6 直线类QLine
- 含义:两点确定一条直线,因此QLine其实就是一个封装了两个坐标点的类。
- 作用:设置两点的坐标、获取两点的坐标、获取二点中点的坐标、平移直线(平移两个点;根据调用函数的不同,返回值可能有,也可能无)、比较直线对象(比较两点的坐标是否同时相等)等
3.7 直线类QLine
- 作用:形容长度和宽度。
- 具体:设置或获取宽度和高度、交换高度和宽度、 高度和宽度的算数运算等。
- 【注意】设置参数时需要使用setXXX,而获取参数时直接使用XXX即可(XXX为参数名;获取时不使用getXXX)。
3.8 矩形类QRect
- 作用:描述一个矩形/窗口(集合了之前学的坐标类和尺寸类)。
- 具体:设置或获取重要点的坐标或者矩形的宽度高度等。
3.9 日期类QDate、时间类QTime和日期与时间类QDateTime
类似上面,略。 【注1】传入参数例如int month,传出参数例如int *year(即传出参数传出的是地址)。 【注2】QTime类可以设置或者获取毫秒。 【注3】我们最好可以使用QElapsedTimer类来计时(例如计算某个程序运行所需的时间),QTime类中的相关函数已经被废弃了(其实二者的函数名是一样的,只是类库名字不同而已)。 【注意】添加某个类的头文件的快捷方式:将鼠标放在该类的上方,按alt + 回车,便可以选择并添加相应的头文件了。
四、信号槽(signals & slots)(对应P29-P35)
4.1 信号与槽概述
- 【定义】信号槽就是一种事件处理机制。信号signal的本质就是事件,而槽slot/槽函数代表的就是事件的处理动作。我们无需关心事件捕捉以及信号发射(这两件事都是Qt框架内部实现的),而只需要定义事件的处理动作。信号槽又称观察者模式/发布-订阅模式。
- 【深入理解信号】 具体地,信号是由于用户对窗口或者空间进行了某些操作(例如按钮单击双击、窗口刷新、鼠标常用操作、键盘输入等),导致窗口或控件产生了某个特定事件,这时候Qt对应的窗口类会发出某个信号,以此对用户的挑选做出反应。我们可以将信号认为是对事件的描述。
- 【深入理解槽】 槽/槽函数其实是一类能对Qt框架中产生信号进行处理的函数。在Qt时,槽函数的所有者是某个类的实例对象。
- 【深入理解信号与槽的关系】 在Qt中,信号和槽函数本身都是独立的个体,二者并无关联。但有时因为有些特殊需求,需要将二者连接到一起,这可以通过调用QObject类中的connect函数来实现。该函数有四个参数,按照顺序分别是信号发出者、信号、信号接收者和事件处理动作(方法)。【注意】槽函数是由Qt框架调用的,我们只是通过connect函数将槽函数注册给Qt框架。在注册完毕之后,Qt框架就将不断帮助我们检测有无相关信号的发出(这一步不由connect函数实现,不要弄错了)。由此也可以看出,信号槽其实就是一种回调机制(函数的调用由框架来实现,不需要通过编写额外代码来实现)。
4.2 标准信号槽使用【重要】
- 例子:实现以下功能——点击窗口上的按钮,关闭窗口(显然,按钮是信号发出者QPushBotton,而窗口是信号的接收者和处理者QWidget) 。
- 相关代码:
// 单击按钮发出的信号
[signal] void QAbstractButton::clicked(bool checked = false)
// 关闭窗口的槽函数
[slot] bool QWidget::close();
// 单击按钮关闭窗口(这行代码应该写在.cpp文件中)
connect(ui->closewindow, &QPsushBotton::clicked, this, &QMainWindow::close);
4.3 自定义信号槽使用【重要】
- 为了满足一些特定需求,我们有时需要自己去定义信号和槽函数。此时二者的连接依旧使用connect函数。
- 【注意】如果想要使用自定义的信号槽,那么我们必须编写新的类并且让这个类继承Qt的某些标准类。此外,还要满足以下两个条件:(1)该类必须从QObject类或其子类进行派生;(2)在定义类的头文件中加入Q_OBJECT宏。
- 【深入理解自定义信号】(1)信号是自定义类的成员函数,且返回值是void类型;(2)信号需要使用signals关键字进行声明,使用上类似于public;(3)信号函数只需要声明,不需要定义(即没有函数体实现);(4)不同信号之间可以发生重载(因为本质上都是函数,函数之间可以发生重载)。例如:
class Test : public QObject
{
Q_OBJECT
signals:
void testsignal();
void testsignal(int a);
}
- 【深入理解自定义槽】(1)槽函数的返回值也是void类型;(2)槽函数也支持信号重载,且其参数与自定义信号在类型和个数上完全一致(后者发送,前者接收)。当然,也可以只取后者的一部分(相当于我只取一部分信号);(3)槽函数可以是自定义类的成员函数、全局函数、静态函数、lambda表达式(匿名函数);(4)槽函数可以使用关键字slots进行声明(Qt5中可以省略),例如public slots、private slots、protected slots(后两者只能在类内部使用);(5)和自定义信号不同,自定义槽函数是需要在相应.cpp文件中实现其函数体的。例如:
class Test : public QObject
{
// 此处不需要添加Q_OBJECT
public:
void testSlot();
static void testFunc();
public slots:
void testSlot(int id);
}
- 【应用场景举例】—— 重要!!!
// 女朋友饿了,我请她吃饭
// class GirlFriend
// class Me
【注1】添加新的类的操作也是右键Qt项目名称,右键Add new!—— 很重要,解释了参考项目中其他文件的由来。注意在完成了这步之后,还需要在主头文件中包含这几个新.h文件,同时完成声明、例化相应类的操作。 【注2】在使用自定义信号和自定义槽函数的时候,通常需要同时添加新的按钮以及相应的槽函数。具体见视频P32!!—— 讲解了一个非常体现逻辑的例子,值得多看。
4.4 信号槽扩展
4.4.1 信号槽使用扩展
- 一个信号可以连接多个槽函数,发送一个信号有多个处理动作。此时,我们需要写多个connect连接,且槽函数的执行顺序与connect函数的调用顺序(书写顺序)是一致的(Qt5中是这样的;Qt4中随机)。
- 一个槽函数可以连接多个信号。多个不同的信号,处理动作是相通的。
- 信号可以连接信号。即信号接收者可以不用动作处理接收到的信号,而继续发生新的信号。—— 这其实有利于体现信号的一致性?
- 信号槽是可以断开的,通过调用disconnect函数即可,其参数与connect函数完全一致。
4.4.2 信号槽的两种连接方式(对应P34)
- Qt5和Qt4的信号连接方式不同。
- 注意当信号槽发生重载时,我们要么选用Qt4的连接方式,要么进行额外的信号函数指针声明(对应Qt5的连接方式)。前者在编写上更简单,但是一旦写错就很难定位(因为不会报相应的错)。因此我们仍然推荐使用后一种方式。
4.4.3 Lambda表达式
- Lambda表达式的本质就是一个一名函数,它在各种编程语言(C++、Java)中都可以使用,它能够提高代码效率,同时使程序更加灵活。
- 语法格式
[capture](params) opt -> ret {body;};
- capture: 捕获列表
- params: 参数列表
- opt: 函数选项
- ret: 返回值类型
- body: 函数体
- 最简单的例子:
// 匿名函数的定义,代码执行这个匿名函数是不会被调用的
[](){
qDebug() << "hello,我是一个lambda表达式...";
};
// 调用匿名函数
[](){
qDebug() << "hello,我是一个lambda表达式...";
}();// 相比上面只加了一个(),这代表了参数列表(此处为空)。
- 【注意】据说Lambda表达式只在输出消息文本中使用,在复杂操作中基本不使用。
- 【注意】 弹幕:匿名函数相对于普通函数不需要出栈和入栈,效率更高。
五、定时器类QTimer(区别于时间类QTime)(P36-37)
- 作用:周期性地执行某些操作,或者制作一些动画效果(稚晖君?)
- 常用函数:setInterval、start、timeout(信号!)、setTimerType、signalShot(槽函数!) 等
- 【重要】 P37中讲解的例子或许能够帮助我们很好地理解参考项目!(这里还介绍了如何使得按钮上的文字根据点击进行相应变化!)
六、窗口类QWidget、QDialog、QMainWindow(P38-P56)
6.1 QWidget类(P38-P40)
- QWidget类继承于QObject类和QPaintDevice类(绘图设备类—— 感觉后续很可能会用到!!)。
- QWidget类是所有窗口类的父类,也是所有控件类(按钮、输入框、标签等)的基类。
- 我们在学习QWidget类时,主要关注其公共函数、公共槽函数以及信号三个部分的内容!
- 【关于公共函数】我们可以完成:设置宽度高度等几何参数、设置左上角图标和标题等操作。
- 【关于槽函数】我们可以完成:显示/隐藏/关闭窗口、窗口最大化/最小化/全屏显示等操作。
- 【关于信号】可以触发信号发射的事件:点击右键显示出菜单、图标或者标题发生变化等。
- 【注意】在设计界面上,我们可以直接右键点击按钮,然后点击转到槽,便可以添加与这个按钮相对应的槽函数(如clicked())!注意不要修改所给槽函数的名称。
6.2 QDialog类(P41-P50)
6.2.1 QDialog类自身(P41-P42)
- QDialog窗口有两种显示形式:(1)模态;(2)非模态。
- 同样地,我们在学习QDialog类时,主要关注其公共函数、公共槽函数以及信号三个部分的内容!
- 【关于公共函数】由于继承了QWidget类,所以可以使用QWidget类的公共函数。而QDialog类自身也有一些公共函数,但是很少使用。
- 【关于槽函数】我们可以完成:显示/隐藏/关闭窗口、窗口最大化/最小化/全屏显示等操作。
- 【关于信号】可以触发信号发射的事件:点击右键显示出菜单、图标或者标题发生变化等。
6.2.2 QDialog子类: QMessageBox(P43)【重要】
- 作用:给用户展示一些信息(包括提示信息、错误信息、询问信息等)(常见的界面提示音与这个类息息相关~)。
- 我们主要关注的是这个类的静态方法(about等)。
6.2.3 QDialog子类: QFileDialog(P44)【重要】
- 作用:打开文件或目录。(我们可以使用其来完成加载文件、选择目录等操作)
- 类似地,我们主要关注这个类的静态方法(getExistingDirectory等)。
6.2.4 QDialog子类: QFontDialog
作用:可以将选择的字体设置给单个或所有的窗口。关注点同上。
6.2.5 QDialog子类: QColorDialog
作用:可以将选择的颜色设置给单个或所有的窗口。同上。
6.2.4 QDialog子类: QInputDialog(P47-P48)【重要】
- 作用:得到能够和用户进行交互的对话框。
- 常用静态函数:getDouble、getInt、getItem、getMultiLineText、getText等
6.2.4 QDialog子类: QProgressDialog
- 作用:得到进度条窗口。
- 我们在学习QProgressDialog类时,主要关注其公共函数、公共槽函数以及信号三个部分的内容!
6.3 QMainWindow类(P51-P56)【重要】
QMainWindow类有两个特点:①可以包含菜单栏、工具栏、状态栏;②不能内嵌。
6.3.1 菜单栏
- 以word为例,菜单栏就是最上方的“打开”“格式”“引用”等。
- 常用信号:triggered等
6.3.2 工具栏
- 工具栏可以有多个,位置可以设置(上下左右或者悬浮)。
- 设计界面中,点击左上角的toolbar(前提是已经添加)之后,便可以在右下角进行一些属性的设置。
6.3.3 状态栏
- 状态栏的位置在窗口的最下方。
6.3.4 停靠窗口(Dock Widget)
略
6.3.5 资源文件
- 定义:存储资源(图片文件、配置文件、小的音频文件)的文件??
- 作用:能够让我们不用每次调用文件时都使用相对路径的形式(具有换电脑就显示不出等弊端)。其原理是将首次使用的这些资源文件保存到一个存储文件中,这样之后即使我们换电脑了,该存储文件也会随着代码的编译加载而编译加载。
- 使用:选中项目名,点击右键Add new,选择Qt-Qt Resource进行添加。
- 备注:资源文件的后缀名是.qrc,它将出现在左侧栏的Resources中。在往项目中添加资源文件之前,我们首先要将各个文件放在与项目文件同级或者更深层次的目录中。放置完之后,我们还需要依次完成Add Prefix、Add Files、Copy Path等操作。
七、窗口布局
- 基本上我们需要制作Qt的窗口界面,都需要进行一系列的布局。 否则可能会出现控件不能显示、控件不能按照期望的大小显示、控件不能跟随窗口进行缩放等情况。
- 布局方式:三种——水平布局、垂直布局和网格布局,它们分别对应了设计界面中Layouts中的多种形式。
- 使用方式1:先拖入布局方式对应的图标,再将我们需要布局的按钮拖入图标内部(红框),这些按钮将会按照对应布局方式进行排列。
- 使用方式2:先拖入一个Widget窗口,然后再将各个按钮拖入Widget窗口内部,接着再进行布局。
- 备注1:已经设置好的布局方式,是可以在设计界面中进行修改的。
- 备注2:网格布局能够保证一些必要的对齐,而灵活使用弹簧可以保证一些间隙的实现。
- 备注3:我们可以在设计界面的右上角来确认哪些Widget没有进行布局。
X、Qwt概述
- Qwt是Qt的一个2D画图开发模块库,可以实现基于数据实时生成曲线图等等。
- 但是我们也有看到没有使用Qwt库,却也实现了曲线的实时绘制的视频。如 QT温湿度实时采集软件(开源)