文章目录
- 1. 信号和槽的基本概念
- 处理的先后顺序
- connect 函数的用法
- connect 函数 使用练习
- 2. 自定义 信号 和 槽
- 自定义槽函数
- 第二种定义槽函数的方式
- 第二种定义槽函数的方式
- 自定义信号
- 3. 带参数的 信号 和 槽
- 参数个数的影响
- 参数类型的影响
- 4. 信号和槽存在的意义
- 5. 信号和槽 的断开
- 6.使用 lambda表达式 定义 槽函数
1. 信号和槽的基本概念
信号源:由那个控件发出的信号
信号的类型:用户进行不同的操作 就可能触发不同的信号
(点击按钮 触发点击信号)
信号的处理方式:槽 (slot) (槽相当于一个函数)
Qt中使用 connect 这样的函数 把一个信号和 一个槽 关联起来
只要信号触发 Qt就会自动执行槽函数
( 槽函数 本质是一种 回调函数 )
处理的先后顺序
回到家 你妈面色不善 你脑袋里一顿回想 是因为最近考试考的很差 所以要跟你妈表决心 一定好好学
信号源:你妈
信号类型:面色不善
信号处理方式:脑袋里一顿回想 是因为最近考试考的很差 -> 要跟你妈表决心 一定好好学
一定要把信号的处理方式准备好 再触发信号
Qt中 一定是先关联信号 和 槽 再触发信号 顺序不能颠倒 否则 信号就不知道如何处理
(你妈面色不善 你没有想到你做过什么以及解决办法 那留给你的只有一顿毒打)
connect 函数的用法
connect 是 QObject 提供的 静态成员函数

connect 有 五个参数 但最后一个参数提供了默认参数 所以一般只考虑前四个参数
第一个参数 sender 表示信号源 描述了当前信号是那个控件发出来的
第二个参数 signal 表示信号的类型 发出哪一种信号
第三个参数 receiver 表示 那个对象负责处理
第四个参数 method 表示 这个对象该怎么处理
connect 函数 使用练习

new 一个 对象 button ( QPushButton 表示普通按钮) 其父对象为 Widget对象 (详细介绍请翻前几篇Qt博客)
使用 setText 函数 设置文本 关闭
使用 move 函数 将文本 移动

此时运行程序后 显示的关闭 按钮 按并没有反应 还需 通过 connect函数 将 信号和 槽 连接


当输入 connect 函数的 第二个参数 时 会出现 click 和 clicked
click 为 slot (槽)函数 作用为 调用时 相当于 点击了一下按钮 (点击的动作)
clicked 为 信号函数 即 要触发的点击信号 (点击完成了)
当输入 connect 函数的 第四个参数 时
close 是 QWidget 内置的槽函数
Widget 继承自 QWidget 也就继承了 父亲的槽函数
具体作用为 关闭当前窗口 或控件
当前信号由 button 发出 使用 clicked 触发点击信号 this作为一个指针 指向了 Widget 对象 由Widget对象负责处理
使用 close 函数 关闭当前窗口
即 针对 button 按钮 进行点击 Widget 就会关闭

点击 关闭按钮 当前 Widget 窗口 就会 关闭
2. 自定义 信号 和 槽
自定义槽函数
第二种定义槽函数的方式

connect 的第四个参数 作为 自定义的槽函数 handleClicked
即自己定义在Widget窗口下如何操作

槽 就是一个 普通的成员函数 即自定义槽函数 和 自定义 普通成员函数 相同
所以 在 widget.h中 添加 共有的成员函数 handleClicked

在 widget.cpp 中 对 自定义槽函数 handleClicked 进行定义
在Widget窗口中 若按下按钮 显示 按钮已经按下

运行程序 按下按钮后 由 Widget 变为 按钮已经按下
第二种定义槽函数的方式

打开ui界面 拖动 Push Button (普通按钮) 到右侧框中
并修改 为 按钮

此时 ui 界面 右侧的 objectName 为 pushButton
通过 ui->pushButton 的方式 就可以获取到 界面上 拖上去的这个按钮

在ui界面上 右击按钮 选择转到槽

在对话框中 说明 QPushButton 都提供那些信号 (包含其父类的信号)

双击 clicked 就会直接生成好了 函数的声明 和 定义

运行程序后 点击按钮 依旧从 Widget 变为 按钮已经按下

在Qt中 除了通过 使用 connect 来连接 信号槽 之外 还可以通过 函数名字的方式来自动连接
on 作为前缀名字 pushButton 是 按钮的 objectName clicked 作为 信号 的名字
当函数名符合上述规则后 Qt就会自动把信号 和 槽 建立联系
自定义信号
信号对应到 用户的某个操作
Qt 信号 是一个 特殊的 函数
1. 只需写出函数声明 告诉 Qt 这是一个信号 即可
这个函数的定义 是在 Qt 编译过程中 自动生成的 (自动生成的过程 无法干预)
2.作为信号函数 这个函数的返回值 必须为 void
有没有参数都可以 也可以支持重载

signals 是 Qt自己扩展的关键字
扫描到类中包含 signals 这个关键字的时候 就会自动 把 下面的 函数声明 认为 是 信号 并且 给 这些信号函数 自动生成函数定义

给 mySiganl 这样的函数声明 当成信号 并且给信号自动生成对应的函数定义

声明一个槽函数 handleMySignal
并在内部使用 setWindowsTitle 设置窗口标题

由 this (Widget对象) 发出 mySignal 信号 再由 this (Widget对象) 通过 handleMySignal 处理

此时运行程序 发现信号并没有发出来
Qt内置的信号 不需要手动通过代码触发
用户在 GUI 进行某些操作 就会自动触发对应信号

Qt中 提供 关键字 emit (发送)
通过这样的方式 就可以把信号发射出去
此时的窗口标题 发生了改变
3. 带参数的 信号 和 槽
当信号带有参数时 槽的参数 必须和信号的参数一致
(理想情况下是这样 也可以不一样 后面会说特殊情况)
此时发射信号的时候 就可以给信号函数传递实参 与之对应的 这个参数 就会被传递到对应的槽函数中
就可以起到让信号给槽传参效果了

当写函数声明时 只需写形参的类型即可 不用写形参的名字

发送信号时 信号带有的实参会把其传递到 槽函数的形参中

运行程序后 点击按钮 发现窗口标题改变了
传参可以起到 复用代码 的效果
有多个逻辑 逻辑上基本一致 但涉及到的数据不同
就可以通过函数 来复用代码 并在不同的场景中传入不同的参数

此时只有一个connect 函数 将 信号和槽连接
同样都是 mySignal信号 但是其中内容不同
通过一套信号槽 搭配不同的参数 就可以起到设置不同标题的效果

运行程序后 若点击设置文本1为标题 则 窗口 改变为 把标题设置为标题1
若点击设置文本2为标题 则 窗口 改变为 把标题设置为标题2
参数个数的影响

信号的参数有两个 而槽的参数有一个

运行程序后 发现功能依旧正常实现
信号函数的参数个数 超过了槽函数的参数个数 都是可以正常使用的

信号参数有一个 槽函数的参数有两个

运行程序后 发现会报错
信号函数的参数个数 少于槽函数的参数个数 此时代码无法编译通过
参数类型的影响

信号的参数类型 从 const QString 变为 int

当发出信号后 将 10 和 20 传递给 text
但是由于 两者 参数类型不一致 就导致报错
4. 信号和槽存在的意义
信号槽 解决的问题是 响应用户的操作
一个信号 可以 connect 到多个槽函数
一个槽函数 也可以被多个信号 connect

声明三个信号 和 三个 槽函数

使用connect函数
将 mysignal1 信号 与 mySlot1 槽函数 关联
将 mysignal1 信号 与 mySlot2 槽函数 关联
将 mysignal2 信号 与 mySlot1 槽函数 关联
将 mysignal1 信号 与 mySlot1 槽函数 关联
Qt引入 信号槽机制 本质是为了能够让 信号和槽 之间按照 多对多的方式 来进行 关联
(一个信号可以关联多个槽 一个槽可以关联多个信号)
5. 信号和槽 的断开
使用 disconnect 断开 信号槽的连接

声明两个槽函数 handleClick 和 handleClick2 并分别定义

先使用 connect 函数 将ui界面 pushButton 按钮 与 handleClick 槽函数 连接

再使用 disconnect 函数 将 pushButton 按钮 与 handleClick 槽函数 连接断开
重新使用 connect 函数 将 pushButton 按钮 与 handleClick_2 槽函数 连接

运行程序后 出现两个按钮

先点击 修改窗口标题按钮 发送信号 使得 窗口变为 修改标题

点击 切换槽函数 按钮 发送信号 使得PushButton按钮与 handleClick 槽函数 断开 与 handleClick 函数连接

再次点击 修改窗口标题按钮 此时窗口为 修改标题2
6.使用 lambda表达式 定义 槽函数
定义槽函数时 可以使用 lambda表达式
圆括号为 形参列表 大括号为 函数体内容

之前还需要在 Widget类中 写一个 槽函数的声明 再回到 Widget.cpp文件中 写一个 槽函数的定义
现在只需要 写一个 lambda 表达式 即可

由于lambda表达式 是一个 回调函数
这个函数 无法直接获取到上层作用域的变量
lambda 为了解决这个问题 引入了 变量捕获 的概念
通过变量捕获 获取到 外层 作用域中的变量

将button变量名 捕获到 lambda表达式里面 就可以正常运行了

由于 button 是 new 出来的变量 所以 生命周期 随着整个窗口(挂到对象树上 窗口关闭才会释放)

this 指向的父对象为 Widget 对象
该变量放在main函数结束后才销毁 只要进程不结束 widget就可以用 对应的this 也就 可用
lambda表达式 可以简化 槽函数的定义