Qt 的信号与槽(Signal & Slot)
Qt 信号(signal) 槽(Slot)
Qt 的信号与槽(Signal & Slot)
在 Qt 中,用户与界面的每一次交互都会产生一个 事件(Event)。例如:
- 用户点击按钮
- 用户关闭窗口
- 鼠标移动
- 键盘输入
Qt 为了处理这些事件,引入了一套非常核心的通信机制:信号与槽(Signal & Slot)。
它本质上是一种 对象之间的消息通信机制,用于实现对象之间的解耦协作。
例如:
- 按钮被点击 → 触发信号
- 窗口关闭函数 → 作为槽函数执行
通过信号与槽机制,我们可以轻松实现:
1 | |
而不需要让按钮类直接依赖窗口类。
一、信号与槽的基本概念
Qt 中的信号与槽可以理解为:
1 | |
当信号被发射时,Qt 会自动调用与之连接的槽函数。
简单理解为:
1 | |
例如:
1 | |
建立连接后:
1 | |
二、信号的本质
信号通常由 某个对象在特定事件发生时发出。
常见的信号来源包括:
- 按钮点击
- 窗口刷新
- 鼠标事件
- 键盘输入
- 数据变化
例如:
| 事件 | 对应信号 |
|---|---|
| 按钮点击 | clicked() |
| 文本改变 | textChanged() |
| 窗口关闭 | destroyed() |
对于开发者来说,信号的表现形式就是 函数声明。
例如:
1 | |
槽函数和普通函数最大的区别是:
槽可以被信号自动调用
当信号发射时,Qt 会自动执行所有与之连接的槽函数。
四、信号与槽的底层机制
从实现角度看,信号与槽其实就是 函数调用关系的封装。
例如:
1 | |
在逻辑上可以理解为:
1 | |
Qt 在内部维护一张 连接表(Connection List):
1 | |
当信号发射时,Qt 会遍历这张表并调用对应的槽函数。
这种机制的优势是:
- 对象解耦
- 支持一对多通信
- 类型安全
例如:
1 | |
一个信号可以连接多个槽。
五、连接信号与槽
Qt 使用 QObject::connect() 来建立信号与槽之间的连接。
connect 函数原型
1 | |
参数说明:
| 参数 | 含义 |
|---|---|
| sender | 信号发送者 |
| signal | 信号 |
| receiver | 接收者 |
| method | 槽函数 |
| type | 连接方式 |
示例:点击按钮关闭窗口
1 | |
逻辑关系:
1 | |
当按钮被点击时,窗口自动关闭。
六、连接方式(ConnectionType)
Qt 支持多种信号槽连接方式:
| 类型 | 说明 |
|---|---|
Qt::AutoConnection |
自动选择(默认) |
Qt::DirectConnection |
直接调用 |
Qt::QueuedConnection |
事件队列调用 |
Qt::BlockingQueuedConnection |
阻塞队列调用 |
Qt::UniqueConnection |
防止重复连接 |
最常用的是:
1 | |
Qt 会根据 线程关系 自动选择:
- 同线程 → DirectConnection
- 不同线程 → QueuedConnection
这也是 Qt 支持 线程间通信 的重要机制。
七、如何查看 Qt 内置信号和槽
Qt 的所有信号和槽都可以通过 Qt 官方文档 查看。
例如查询 QPushButton:
1️⃣ 打开 Qt 文档
2️⃣ 搜索 QPushButton
3️⃣ 查看:
1 | |
如果没有找到信号,可以继续查看父类,例如:
1 | |
这里就可以看到:
1 | |
同理,槽函数可以在:
1 | |
部分找到。
八、Qt Creator 自动生成信号槽代码
Qt Creator 提供了非常方便的 可视化信号槽生成工具。
基本流程:
1️⃣ 创建 Qt Widget 项目
2️⃣ 打开 .ui 文件
3️⃣ 拖入一个按钮
4️⃣ 右键按钮 → 转到槽(Go to Slot)
5️⃣ 选择信号 clicked()
Qt Creator 会自动生成代码。
自动生成的槽函数
在 widget.h 中:
1 | |
在 widget.cpp 中:
1 | |
命名规则:
1 | |
例如:
1 | |
含义:
| 部分 | 含义 |
|---|---|
| on | 固定前缀 |
| pushButton | 控件 objectName |
| clicked | 信号名称 |
Qt 会自动根据这个规则完成连接。
九、显式 connect 与自动连接
Qt 提供两种方式连接信号槽:
1 自动连接(基于命名规则)
优点:
- 代码少
- UI开发方便
缺点:
- 不直观
- 不容易排查错误
2 显式 connect(推荐)
1 | |
优点:
- 连接关系清晰
- 编译期类型检查
- 不依赖命名规则
在大型 Qt 项目中,更推荐 显式 connect。