代码编织梦想

学习内容:Qt编程开发

提示:这里可以添加要学的内容

应用程序框架创建

1、选择New Project
在这里插入图片描述
2、选择Application(Qt)->Qt Widgets Application
在这里插入图片描述
3、项目命名
在这里插入图片描述
4、选择qmake
在这里插入图片描述
一共有三种Build系统,分别是qmake、Cmake和Qbs。
Cmake:很常用,功能也很强大,许多知名的项目都是用它,比如 OpenCV 和 VTK,但它的语法繁杂。
qmake:是针对辅助 Qt 开发的,但也可以在非 Qt 项目使用,特点是语法简单明了,但功能也相对简单。
Qbs:号称下一代构建工具。
由于是初学,这里我们选择qmake。
5、选择基类(刚开始可以不勾选Generate form)
在这里插入图片描述
基类也有三种:QMainWindow、QWidget、QDialog。
QMainWindow:提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围 菜单、工具条和一个状态条。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围 菜单、工具条和一个状态条。QMainWindow常常被继承,因为这使得封装中央部件、菜单和工具条以及窗口状态条变得更容易,当用户点击菜单项或者工具条按钮时,槽会被调用。
QWidget:所有用户界面对象的基类,QMainWindow和QDialog都是QWidget的子类。窗口部件是用户界面的一个基本单元:它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制自己。每一个窗口部件都是矩形的,并且它们按Z轴顺序排列。一个窗口部件可以被它的父窗口部件或者它前面的窗口部件盖住一部分。
QDialog:对话框窗口的基类。对话框窗口是主要用于短期任务以及和用户进行简要通讯的顶级窗口。QDialog可以是模态对话框也可以是非模态对话框。QDialog支持扩展性并且可以提供返回值。它们可以有默认按钮。QDialog也可以有一个QSizeGrip在它的右下角,使用setSizeGripEnabled()。 QDialog 是最普通的顶级窗口。一个不会被嵌入到父窗口部件的窗口部件叫做顶级窗口部件。通常情况下,顶级窗口部件是有框架和标题栏的窗口(尽管使用了一定的窗口部件标记,创建顶级窗口部件时也可能没有这些装饰。)在Qt中,QMainWindow和不同的QDialog的子类是最普通的顶级窗口。
如果是顶级对话框,那就基于QDialog创建,如果是主窗体,那就基于QMainWindow,如果不确定,或者有可能作为顶级窗体,或有可能嵌入到其他窗体中,则基于QWidget创建。
由此可见,QWidget的自由度是最高的,最适合刚开始学习编程了。
6、后面一直下一步即可,直至工程创建完毕。

项目文件分类

Widget类工程创建完毕后,工程文件分布如下:
在这里插入图片描述
首先是工程文件*.pro,工程文件定义了Qt用的类库、目标程序的文件名、采用的模板、C++源文件、C++头文件和样式文件,如下图所示:
在这里插入图片描述
然后是头文件*.h,头文件列出了本工程文件包含的用户头文件,如下图所示:
在这里插入图片描述
最后就是源文件*.cpp,源文件列出了本工程包含的用户C++源文件。
main.cpp文件(主函数源文件)
在这里插入图片描述
widget.cpp 文件(widget自定义函数方法文件)
在这里插入图片描述
测试过程执行完毕会生成一个空窗口,因为没有对窗口进行处理,仅仅声明了一个窗口类对象Widget w,并show()展示了出来。
在这里插入图片描述

Hello Qt

为了更好的了解工程结构,在新建工程窗口选择其他项目->Empty qmake Project:
在这里插入图片描述
接着命名HelloQt。
创建完毕后的项目工程结构如下图所示:
在这里插入图片描述
其中*.pro文件是空的,需要主动添加Widget,引入QWidget窗口基类模型,添加如下代码:
在这里插入图片描述
同时在工程目录上右键添加新文件,这里选择c++源文件并命名为main.cpp:
在这里插入图片描述
然后工程文件*.pro就会主动添加如下属性,表示该工程包含这些源文件:
在这里插入图片描述
以此类推,如果创建头文件,也会添加对应的属性。
对main.cpp进行代码编写,引入Qt应用程序类QApplication和窗口基类QWidget,以及按钮类QPushButton来添加按钮。如下图所示:
在这里插入图片描述
该代码的解释是,先创建一个应用程序app对象以及窗口对象w,将w对象的窗口名设置为"hjw";然后添加一个按钮对象b,设置内容为”HelloQt“;接着必须给按钮对象b指定父对象w,让按钮b显示在窗口w上。接着添加另一个按钮对象b1,使用构造函数传参的方式指定父对象,并设置内容为"222";
最后使用show函数显示窗口,注意:Qt里面窗口是默认隐藏的,如果不show一下会看不见窗口;
exec函数是让app程序一直运行,等待人为事件干预,比如按钮点击,关闭等操作。
运行结果如下:
在这里插入图片描述
如果不指定父对象,会出现以下结果:
在这里插入图片描述
按钮窗口和主窗口分离。

指定父对象

在上一小节提到过指定父对象,如果没有给一个对象指定父对象,那么就会产生两个窗口,窗口与窗口之间没有关系。所以为了多个对象可以叠加在一起,必须指定父对象,分为两种方式:
1、SetParent方式
简单粗暴,直接使用子对象的SetParent方法即可:

子对象.SetParent(&父对象);

只需注意,必须取父对象的地址输入该函数。
2、直接构造函数传参

子对象类型 子对象(&父对象);
或者
子对象类型 *子对象;//定义子对象指针
子对象 = new 子对象类型(&父对象);

信号(Signal)和槽(Slot)函数

新建一个qmake工程并命名为SignalAndSlot(信号和槽)类名为mainWidget,main源文件如下:
在这里插入图片描述
在执行到mainWidget时,会先转入mainWidget类函数进行数据处理,然后跳回main函数展示界面。
其中类的头文件和源文件代码如下:
头文件:
在这里插入图片描述
源文件:
在这里插入图片描述
头文件里创建了两个按钮对象,并通过引用头文件在源文件中调用出来。与上节操作一致,先指定父对象,设置内容,及坐标。但是添加了一个connect函数,这个是连接信号和槽的处理函数。信号相当于指令发出者(press和release分别是按钮按下去一瞬间发送信号和松开鼠标的一瞬间发送信号),槽相当于指令执行者,其他解释请看图片里的注释。对b1按钮的点击信号,做出反应的槽函数为关闭主窗口mainWidget,b2的发生事件就是在按钮b1,还有一个注释掉的事件是执行mainWidget中自定义槽函数mySlot。这个下节会说明。
点击abc按钮前:
在这里插入图片描述
点击后:
在这里插入图片描述
close按钮也就是b1按钮隐藏了。

槽函数的自定义

对于槽函数,也就是执行事件,是可以自定义的,如果想让对应的对象执行某个事件,那么只需在该对象类的头文件里面添加自定义函数,并且在该对象的源文件里面添加函数处理方法即可。以mainWidget为例:
在该头文件里面定义了mySlot()函数。
在这里插入图片描述
并且,需要对该函数进行编写,在源文件内添加即可:
在这里插入图片描述
该槽函数mySlot就是使按钮内容变为"def"。
添加connect对mainWidget进行处理:
在这里插入图片描述
表示b2按钮点击后,b2会切换内容。
点击前:
在这里插入图片描述
点击后:
在这里插入图片描述

创建父窗口和子窗口

如果再创建一个窗口,不指定到父对象的话,我们可以得到两个窗口,一个父窗口,一个子窗口,对应一个主类,一个子类。
只需在工程文件中添加一个名为subwidget类即可:
在这里插入图片描述
它包含了头文件和源文件。
头文件:
在这里插入图片描述
这里的头文件包含了一个signal,待会会提到它的作用。
源文件:
在这里插入图片描述

那么如何将子窗口的显示导入到main函数呢?
其实直接和主窗口一样,在main函数调用即可。
在这里插入图片描述
执行结果如下图:
在这里插入图片描述
其实也可在mainWidget类里面声明一个子窗口类的对象。
在这里插入图片描述
然后在mainWidget类函数里面调用w.show()效果也是相同的。

信号的定义

虽然上文中创建了两个窗口,但是,两个窗口之间并没有联系,那怎么样将它们联系互动起来呢?
这里先给一个思路,比如我们想刚开始主窗口显示,子窗口隐藏,点击主窗口某个按钮对象后,主窗口隐藏,子窗口显示,同理在子窗口那边也是如此。那么便达到了不同窗口之间跨越的功能。
这里在主窗口新建一个按钮对象b3,并定义两个函数showTranslate和dealsub,分别实现主窗口切换到子窗口和子窗口切换到主窗口的功能:
在这里插入图片描述
按钮b3的设置和b3信号处理如下:
在这里插入图片描述

在这里插入图片描述
这里实现隐藏主窗口,显示子窗口。
那么子窗口的按钮定义同样如此:
在这里插入图片描述
在这里插入图片描述
需要注意的是,主窗口能处理子窗口的事件是因为主窗口给子窗口通过connect发送信号,主窗口的主类可以直接定义子类的对象(上文提到过),对子窗口进行处理,达到显示的效果。
在这里插入图片描述

在这里插入图片描述

但是子窗口点击按钮以后,也想处理主窗口的话,我们尝试在子类中定义主类的对象,发现:
在这里插入图片描述

定义失败,证明子类是不能使用主类的对象的,说明子类不能直接处理主类。
那如何处理呢,我们可以想想,如果事件都只能用主类对象来处理的话,那么子类的信号发生时,我们可不可以直接将信号发送给主类,然后让主类控制主窗口的显示和子窗口的隐藏,就达到了切换窗口的目的。
因此,我们需要在子类定义一个信号mySignal,必须写到signals里面,和一个发送信号槽函数sendSlot:
在这里插入图片描述
然后如何发送信号给主类?,如下图:
在这里插入图片描述
这里使用connect连接信号和槽,槽的作用就是发送信号给主类。注意使用emit +信号函数。
发送完信号以后,主类接收信号,通过connect连接:
在这里插入图片描述
这里的信号就不再是某个按钮了,而是子窗口点击按钮后,发射的mySIgnal信号,槽函数和之前的没有区别,自定义如下:
在这里插入图片描述

总结

信号和槽是指,某个对象发送信号给执行事件的对象,然后事件操作由槽来定义,信号也可以定义,一般来说,主类的信号可以直接产生,大多数情况无需自定义,但是槽函数是随意的。如果是子类要执行某个事件,由于权限不足,也就是不能改变主类的属性,它必须通过发射信号,然后由主类定义该信号,才能间接的通过主类处理事件。
就是说主类可以处理主类和子类的操作。只需定义槽函数即可。
那么子类处理自己的操作,可以定义槽函数,如果它想对主类进行操作,必须定义槽函数,将操作设置为发射信号,然后由主类接收自定义信号,来间接的控制主类的操作,当然也可以发送信号给主类,来控制自己,只不过还不如直接定义自己的槽函数来的快。