Qt之信号和槽
Qt的信号与槽(Signals and Slots) 是Qt框架最核心、最具特色的机制之一,用于实现对象之间的类型安全、松耦合通信。它替代了传统的回调函数或观察者模式,提供了一种更安全、灵活且易于使用的事件驱动编程模型。
文章目录
- 1. 认识信号和槽
-
- 1.1 信号
- 1.2 槽
- 1.3 信号和槽的连接
- 2. 信号和槽的连接函数的解析和连接方式
-
- 2.1 连接类型
- 2.2 自动连接
- 3. 信号和槽的断开连接
-
- 3.1 断开特定连接(推荐方式)
- 3.2 断开指定 sender、signal、receiver、slot 的连接
- 4. 槽函数的执行顺序和开销
1. 认识信号和槽
Qt使用信号和槽取代回调函数实现对象之间的通信。当一个特定事件触发时会发射信号,与此信号相关联的函数会被调用,该函数称之为槽或槽函数,这种关联Qt有专门的函数connect()实现,通过connect()函数将信号和槽连接起来,实现对象间的通信。因此信号和槽系统有三部分组成:信号、槽以及连接组成。
你可以将任意多个信号连接到同一个槽,也可以将一个信号连接到任意多个槽。甚至还可以将一个信号直接连接到另一个信号(这样,每当第一个信号被发射时,第二个信号会立即被触发)。
所有继承自QObject或其子类(例如QWidget)的类都可以包含信号和槽。也就是说只有QObject及其子类才可以使用信号和槽,由于信号和槽是通过元对象系统实现的,因此子类中必须包含Q_OBJECT宏。
connect(object_sender, signal, object_receiver, slot)
信号与槽是松耦合的:一个发出信号的类既不知道、也不关心有哪些槽接收了该信号,槽也不知道是否有任何信号连接到了它。信号和槽可以接受任意数量、任意类型的参数,且完全保证类型安全。这种设计确保了使用 Qt 能够创建真正相互独立的组件。

1.1 信号
信号是一个公共访问函数,可以从任何地方发出,建议从定义该信号的类及其子类中发出信号。Qt类特别是QWidget中有很多默认的信号,我们也可以自定义信号。
class MySignalObject : public QObject { //必须继承自QObject或其子类Q_OBJECT //必须要有Q_OBJECT宏signals:void signal1(); //无参数信号Q_SIGNALS:void signal2(int); //带参数的信号,参数可以是任意类型和数量void signal3(int, int);public:Q_SIGNAL void signal4(const MyType&);
};
发射信号可以使用emit 信号()语法方式,如emit signals2(12), 如果需要在第三方源码中使用信和槽,例如Boost中,为了防止signals, slots和emit关键字冲突,我们可以在编译器中配置选项(在CMake项目中添加:target_compile_definitions(my_app PRIVATE QT_NO_KEYWORDS), 在qmake项目(.pro)文件中添加:CONFIG += no_keywords),告诉Qt不要定义moc关键字:signals, slots和emit,如果想继续使用信号和槽,我们可以用宏Q_SIGNAL(或Q_SIGNALS)替换signals,Q_SLOT(或Q_SLOTS)替换slots,Q_EMIT替换emit, 也可以使用#undef取消signals, slots和emit宏定义:
#undef signals
#undef slots
#undef signals
Q_SIGNALS (带S): 用于定义信号区域,Q_SIGNAL(不带S): 用于声明单个信号,类似Q_SLOT和Q_SLOTS用于单个和多个槽函数。
不管是第三方还是非第三方源码中,不管有没有配置no_keywords,我们都可以使用宏Q_SIGNAL(或Q_SIGNALS)替换signals,Q_SLOT(或Q_SLOTS)替换slots,Q_EMIT替换emit, 而且为了防止可能与第三方库如Boost或C++标准库产生命名冲突,遵循Qt命名规范,Qt推荐使用Q_SIGNAL, Q_SLOT和Q_EMIT, 这样在多库环境中更安全可靠。
1.2 槽
当与槽连接的信号被触发时,该槽会被调用。槽是普通的C++函数,可以像普通函数一样被直接调用;它们唯一
