目录
[1.1 信号的本质](#1.1 信号的本质)
[2.1 连接信号和槽](#2.1 连接信号和槽)
[2.2 查看内置信号和槽](#2.2 查看内置信号和槽)
[2.2.1 通过代码实现关闭窗口功能](#2.2.1 通过代码实现关闭窗口功能)
[2.2.2 通过Qt Creator 生成信号槽代码](#2.2.2 通过Qt Creator 生成信号槽代码)
[3.1 基本语法](#3.1 基本语法)
[3.2 带参数的信号和槽](#3.2 带参数的信号和槽)
[3.2.1 参数关系](#3.2.1 参数关系)
[3.2.2 参数一致性](#3.2.2 参数一致性)
[3.2.3 QObject宏](#3.2.3 QObject宏)
[3.3 信号和槽存在的意义](#3.3 信号和槽存在的意义)
[3.4 信号和槽断开连接](#3.4 信号和槽断开连接)
[3.4.1 信号与槽的断开](#3.4.1 信号与槽的断开)
[3.5 使用lambda表达式来定义槽函数](#3.5 使用lambda表达式来定义槽函数)
一、概述

在Qt 中,用户和控件的每次交互过程称为一个事件。比如"用户点击按钮"是一个事件,"用户关闭窗口"也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出"按钮被点击"的信号,用户关闭窗口会发出"窗口被关闭"的信号。
Qt 中的所有控件都具有接收信号的能力,一个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作。例如,按钮所在的窗口接收到"按钮被点击"的信号后,会做出"关闭自己"的响应动作;再比如输入框自己接收到"输入框被点击"的信号后,会做出"显示闪烁的光标,等待用户输入数据"的响应动作。在Qt 中,对信号做出的响应动作就称之为槽。
信号和槽是Qt 特有的消息传输机制,它能将相互独立的控件关联起来。比如,"按钮"和"窗口"本身是两个独立的控件,点击"按钮"并不会对"窗口"造成任何影响。通过信号和槽机制,可以将"按钮"和"窗口"关联起来,实现"点击按钮会使窗口关闭"的效果。
Qt中,一定是先关联信号和槽,然后再触发这个信号,顺序不能颠倒,否则信号就不知道如何处理了(错过了)。

1.1 信号的本质
信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时Qt 对应的窗口类会发出某个信号,以此对用户的操作做出反应。因此,信号的本质就是事件。如:
• 按钮单击、双击
• 窗口刷新
• 鼠标移动、鼠标按下、鼠标释放
• 键盘输入
那么在Qt 中信号是通过什么形式呈现给使用者的呢?
• 我们对哪个窗口进行操作,哪个窗口就可以捕捉到这些被触发的事件。
• 对于使用者来说触发了一个事件我们就可以得到Qt 框架给我们发出的某个特定信号。
• 信号的呈现形式就是函数,也就是说某个事件产生了,Qt 框架就会调用某个对应的信号函数,通知使用者。
在Qt 中信号的发出者是某个实例化的类对象。
槽的本质
槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的C++函数是一样的,可以定义在类的任何位置(public、protected 或private),可以具有任何参数,可以被重载,也可以被直接调用(但是不能有默认参数)。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。
说明
(1)信号和槽机制底层是通过函数间的相互调用实现的。每个信号都可以用函数来表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。例如:"按钮被按下"这个信号可以用clicked()函数表示,"窗口关闭"这个槽可以用close()函数表示,假如使用信号和槽机制-
实现:"点击按钮会关闭窗口"的功能,其实就是clicked()函数调用close()函数的效果。
(2)信号函数和槽函数通常位于某个类中,和普通的成员函数相比,它们的特别之处在于:
• 信号函数用signals 关键字修饰,槽函数用public slots、protected slots 或者private slots 修饰。signals 和slots 是Qt 在C++的基础上扩展的关键字,专门用来指明信号函数和槽函数;
• 信号函数只需要声明,不需要定义(实现),而槽函数需要定义(实现)。

二、信号和槽的使用
2.1 连接信号和槽
在Qt 中,QObject 类提供了一个静态成员函数connect(),该函数专门用来关联指定的信号函数和槽函数。
Qt中提供的这些类,本身是存在一定的继承关系:

connect()函数原型:
connect (const QObject * sender ,
const char *signal ,
const QObject *receiver ,
const char *method ,
Qt::ConnectionType type = Qt::AutoConnection)

• sender:信号的发送者;
• signal:发送的信号(信号函数);
• receiver:信号的接收者;
• method:接收信号的槽函数;
• type:用于指定关联方式,默认的关联方式为Qt::AutoConnection,通常不需要手动设定。
代码示例:在窗口中设置一个按钮,当点击"按钮"时关闭"窗口".

2.2 查看内置信号和槽
系统自带的信号和槽通常是通过"Qt 帮助文档"来查询。
如上述示例,要查询"按钮"的信号,在帮助文档中输入:QPushButton,• 首先可以在"Contents"中寻找关键字signals,
• 如果没有找到,继续去父类中查找.因此我们去他的父类QAbstractButton 中继续查找关键字 signals,

这里的clicked()就是要找的信号。槽函数的寻找方式和信号一样,只不过它的关键字是slot。
2.2.1 通过代码实现关闭窗口功能





通过这些操作就可以了。
那么问题来了。我怎么知道Qpushbutton里面有clicked信号?我怎么知道QWidget有close槽?
一个字:多看文档。
但是当我们在翻阅文档的时候,如果在当前类中没有找到对应函数,不妨看看这个类的父类。

找到了。

点击clicked就能跳转到说明:


第二个参数详解


2.2.2 通过Qt Creator 生成信号槽代码
Qt Creator 可以快速帮助我们⽣成信号槽相关的代码.
代码⽰例: 在窗⼝中设置⼀个按钮,当点击 "按钮" 时关闭 "窗⼝" .
1、新建项⽬,如下图为新建完成之后所包含的所有⽂件;
注意:创建时要⽣成 UI 设计⽂件;

2、双击 widget.ui ⽂件,进⼊ UI 设计界⾯;

3、在 UI 设计窗⼝中拖⼊⼀个 "按钮" ,并且修改 "按钮" 的名称及字体⼤⼩等;

4、可视化⽣成槽函数;

当单击 "转到槽..." 之后,出现如下界⾯:对于按钮来说,当点击时发送的信号是:clicked(),所以此处选择:clicked()

对于普通按钮来说, 使⽤ clicked 信号即可. clicked(bool) 没有意义的. 具有特殊状态的按
钮(⽐如复选按钮)才会⽤到 clicked(bool) .
5、⾃动⽣成槽函数原型框架;
(1)在 "widget.h" 头⽂件中⾃动添加槽函数的声明;

说明:
自动生成槽函数的名称有一定的规则。槽函数的命名规则为:on_XXX_SSS,其中:
1、以"on "开头,中间使用下划线连接起来;
2、"XXX "表示的是对象名(控件的objectName 属性)。
3、"SSS "表示的是对应的信号。
如:"on_pushButton_clicked()",pushButton 代表的是对象名,clicked 是对应的信号。
(2)在 "widget.cpp" 中⾃动⽣成槽函数定义.

6、在槽函数函数定义中添加要实现的功能. 实现关闭窗⼝的效果.
三、自定义信号和槽
3.1 基本语法
在Qt 中,允许自定义信号的发送方以及接收方,即可以自定义信号函数和槽函数。但是对于自定义的信号函数和槽函数有一定的书写规范。


1、自定义信号函数书写规范
(1)自定义信号函数必须写到"signals"下;
(2)返回值为void,只需要声明,不需要实现;
(3)可以有参数,也可以发生重载;
2、自定义槽函数书写规范
(1)早期的Qt 版本要求槽函数必须写到"public slots"下,但是现在高级版本的Qt 允许写到类的 "public"作用域中或者全局下;
(2)返回值为void,需要声明,也需要实现;
(3)可以有参数,可以发生重载;
3、发送信号
使用"emit"关键字发送信号。"emit"是一个空的宏。"emit"其实是可选的,没有什么含义,只是为了提醒开发人员。

示例1:

示例2:
1、在widget.h 中声明自定义的信号和槽,如图所示;

啥也不能干现在,因为没有触发信号。

2、在widget.cpp 中实现槽函数,并且关联信号和槽

转到槽



注意:图中的①和②的顺序不能颠倒。
原因是,首先关联信号和槽,一旦检测到信号发射之后就会立马执行关联的槽函数。反之,若先发射信号,此时还没有关联槽函数,当信号发射之后槽函数不会响应.

3.2 带参数的信号和槽
Qt 的信号和槽也支持带有参数,同时也可以支持重载.
此处我们要求,信号函数的参数列表要和对应连接的槽函数参数列表一致.
此时信号触发,调用到槽函数的时候,信号函数中的实参就能够被传递到槽函数的形参当中.
通过这样的机制,就可以让信号给槽传递数据了.






3.2.1 参数关系
信号参数大于槽参数。

槽参数大于信号参数直接报错。

为啥呢?

个数不一致,槽函数就会按照参数顺序,拿到信号的前N个参数,只少需要确保,槽函数的每个参数都是有值的。
要求信号给槽的参数,可以有富裕,但是不能少。
3.2.2 参数一致性


3.2.3 QObject宏
不可或缺。

3.3 信号和槽存在的意义
所谓的信号槽,终究要解决问题,就是响应用户的操作。
信号槽,其实在GUI开发的框架中是一个比较有特色的存在。

创建多个信号和槽。



3.4 信号和槽断开连接
3.4.1 信号与槽的断开
使⽤ disconnect 即可完成断开.
disconnect 的⽤法和 connect 基本⼀致.

还可以调试看看,打日志。

3.5 使用lambda表达式来定义槽函数
Qt5 在Qt4 的基础上提高了信号与槽的灵活性,允许使用任意函数作为槽函数。
但如果想方便的编写槽函数,比如在编写函数时连函数名都不想定义,则可以通过Lambda表达式来达到这个目的。
Lambda表达怯是C++11 增加的特性。C++11 中的Lambda表达怯⽤于定义并创建匿名的函数对象,以简化编程⼯作。
Lambda表达式的语法格式如下:
capture \] ( params ) opt -\> ret { Function body; };
具体详解在cpp文章里面有介绍。


代码执行结果:
未点击之前

点击之后窗口位置变了,日志也输出信息了。


lambda除了可以按照值的方式来捕获变量[=]还可以按照应用的方式来捕获[&](Qt中很少这么写)捕获的变量一般就是各种控件的指针。指针变量按照值传递或者引用来传递都行,
如果按引用,还得关注这个变量的生命周期。
四、小结
图解:


耦合:高耦合就是生了一场大病牵一发而动全身无法继续学习了,低耦合就是得了一场小感冒不影响继续学习。
内聚:低内聚就是家里面的衣服很乱,到处都是,想要找到某件衣服很费劲。
高内聚就是家里面的衣服放在一个固定的地方比如说衣柜啥的。想要找到某件衣服很 容易就能找到。

