Qt 的信号与槽(Signal & Slot)

Qt 信号(signal) 槽(Slot)

Qt 的信号与槽(Signal & Slot)

在 Qt 中,用户与界面的每一次交互都会产生一个 事件(Event)。例如:

  • 用户点击按钮
  • 用户关闭窗口
  • 鼠标移动
  • 键盘输入

Qt 为了处理这些事件,引入了一套非常核心的通信机制:信号与槽(Signal & Slot)
它本质上是一种 对象之间的消息通信机制,用于实现对象之间的解耦协作。

例如:

  • 按钮被点击 → 触发信号
  • 窗口关闭函数 → 作为槽函数执行

通过信号与槽机制,我们可以轻松实现:

1
2
3

点击按钮 → 窗口关闭

而不需要让按钮类直接依赖窗口类。


一、信号与槽的基本概念

Qt 中的信号与槽可以理解为:

1
2
3
4

Signal(信号) → 事件通知
Slot(槽) → 响应函数

当信号被发射时,Qt 会自动调用与之连接的槽函数。

简单理解为:

1
2
3
4

信号 == 触发条件
== 响应动作

例如:

1
2
3
4

按钮被点击 → clicked() 信号
窗口关闭 → close() 槽

建立连接后:

1
2
3

clicked() → close()


二、信号的本质

信号通常由 某个对象在特定事件发生时发出

常见的信号来源包括:

  • 按钮点击
  • 窗口刷新
  • 鼠标事件
  • 键盘输入
  • 数据变化

例如:

事件 对应信号
按钮点击 clicked()
文本改变 textChanged()
窗口关闭 destroyed()

对于开发者来说,信号的表现形式就是 函数声明

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
signals:
void clicked();
````

需要注意:

* **信号函数只声明,不需要实现**
* Qt 会在编译阶段自动生成相关代码

这依赖于 Qt 的 **元对象系统(Meta-Object System)**,由 **MOC(Meta Object Compiler)** 自动生成代码。

---

# 三、槽的本质

槽(Slot)本质上就是 **普通的成员函数**,用于响应信号。

槽函数可以:

* 定义在 `public / protected / private`
* 带参数
* 重载
* 被普通代码直接调用

例如:

```cpp
public slots:
void closeWindow();

槽函数和普通函数最大的区别是:

槽可以被信号自动调用

当信号发射时,Qt 会自动执行所有与之连接的槽函数。


四、信号与槽的底层机制

从实现角度看,信号与槽其实就是 函数调用关系的封装

例如:

1
2
3
按钮 clicked() 信号

窗口 close() 槽

在逻辑上可以理解为:

1
clicked() → close()

Qt 在内部维护一张 连接表(Connection List)

1
SignalSlot

当信号发射时,Qt 会遍历这张表并调用对应的槽函数。

这种机制的优势是:

  • 对象解耦
  • 支持一对多通信
  • 类型安全

例如:

1
2
3
4
5
Signal

slot1()
slot2()
slot3()

一个信号可以连接多个槽。


五、连接信号与槽

Qt 使用 QObject::connect() 来建立信号与槽之间的连接。

connect 函数原型

1
2
3
4
5
6
7
QObject::connect(
const QObject *sender,
const char *signal,
const QObject *receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection
);

参数说明:

参数 含义
sender 信号发送者
signal 信号
receiver 接收者
method 槽函数
type 连接方式

示例:点击按钮关闭窗口

1
2
connect(button, &QPushButton::clicked,
this, &QWidget::close);

逻辑关系:

1
2
3
QPushButton.clicked()

QWidget.close()

当按钮被点击时,窗口自动关闭。


六、连接方式(ConnectionType)

Qt 支持多种信号槽连接方式:

类型 说明
Qt::AutoConnection 自动选择(默认)
Qt::DirectConnection 直接调用
Qt::QueuedConnection 事件队列调用
Qt::BlockingQueuedConnection 阻塞队列调用
Qt::UniqueConnection 防止重复连接

最常用的是:

1
Qt::AutoConnection

Qt 会根据 线程关系 自动选择:

  • 同线程 → DirectConnection
  • 不同线程 → QueuedConnection

这也是 Qt 支持 线程间通信 的重要机制。


七、如何查看 Qt 内置信号和槽

Qt 的所有信号和槽都可以通过 Qt 官方文档 查看。

例如查询 QPushButton

1️⃣ 打开 Qt 文档
2️⃣ 搜索 QPushButton
3️⃣ 查看:

1
Signals

如果没有找到信号,可以继续查看父类,例如:

1
QAbstractButton

这里就可以看到:

1
2
3
clicked()
pressed()
released()

同理,槽函数可以在:

1
Slots

部分找到。


八、Qt Creator 自动生成信号槽代码

Qt Creator 提供了非常方便的 可视化信号槽生成工具

基本流程:

1️⃣ 创建 Qt Widget 项目
2️⃣ 打开 .ui 文件
3️⃣ 拖入一个按钮
4️⃣ 右键按钮 → 转到槽(Go to Slot)
5️⃣ 选择信号 clicked()

Qt Creator 会自动生成代码。


自动生成的槽函数

widget.h 中:

1
2
private slots:
void on_pushButton_clicked();

widget.cpp 中:

1
2
3
void Widget::on_pushButton_clicked()
{
}

命名规则:

1
on_对象名_信号名

例如:

1
on_pushButton_clicked()

含义:

部分 含义
on 固定前缀
pushButton 控件 objectName
clicked 信号名称

Qt 会自动根据这个规则完成连接。


九、显式 connect 与自动连接

Qt 提供两种方式连接信号槽:

1 自动连接(基于命名规则)

优点:

  • 代码少
  • UI开发方便

缺点:

  • 不直观
  • 不容易排查错误

2 显式 connect(推荐)

1
2
connect(button, &QPushButton::clicked,
this, &Widget::close);

优点:

  • 连接关系清晰
  • 编译期类型检查
  • 不依赖命名规则

在大型 Qt 项目中,更推荐 显式 connect


Qt 的信号与槽(Signal & Slot)
https://weihehe.top/2024/08/13/关键字/
作者
weihehe
发布于
2024年8月13日
许可协议