目录
Qt 的信号槽机制(Signals & Slots)是其核心特性之一。它提供了一种松耦合的事件通信方式,极大降低了代码之间的耦合度,同时让我们的代码结构更清晰、可维护性更高。很多初学者只知道 “写个 signals:
slots:
”,再加上 connect()
就能实现事件响应,却不了解这背后是如何运作的。本文将为你揭开信号槽的“神秘面纱”。
1. 基本概念
1.1 信号(Signal)
- 信号:用来发送消息(事件)
- 在 C++ 中通常被声明在
signals:
区域,函数声明类似于void somethingHappened(int value);
- 调用信号时,像调用一个普通函数一样,但它并不会执行实际代码,而是通过元对象系统通知已连接的槽函数
1.2 槽(Slot)
- 槽:用来接收消息(事件)并做出响应
- 一般声明在
public slots:
(或private slots:
)区块,也可以是任意的普通成员函数(在现代 Qt 中允许任意可调用对象作为槽) - 当对应的信号被发射时,所有连接到该信号的槽会依次被调用
1.3 连接(Connect)
信号和槽之间需要通过 connect()
关联。例如:
connect(
sender,
&SenderClass::valueChanged,
receiver,
&ReceiverClass::onValueChanged
);
当 sender->valueChanged(...)
这个信号被发射时,onValueChanged()
槽就会被自动调用。
提示:
- 早期的 Qt 4 风格写法:
SIGNAL(valueChanged(int)), SLOT(onValueChanged(int))
;- 从 Qt 5 开始,推荐使用函数指针的新语法,更安全也更易被编译器检查。
2. MOC(Meta-Object Compiler)是什么?
2.1 为什么需要 MOC
C++ 本身并没有反射机制,也无法原生识别“信号”或“槽”这样的概念。为了给 Qt 提供元对象(Meta Object)支持,官方开发了一套预处理器,也就是 MOC。它在编译前会扫描源码,找到所有 Q_OBJECT
、signals:
、slots:
等关键字,然后生成额外的 C++ 文件(通常命名为 moc_<filename>.cpp
),把这些额外的代码再与用户代码一同编译、链接。
简单来说,MOC 就是负责把 “Qt 信号槽的特殊语法” 翻译成 “C++ 能理解的普通函数和静态元数据” 的桥梁。
2.2 工作流程
假设你有一个类 MyWidget
,包含如下定义:
class MyWidget : public QWidget
{
Q_OBJECT