跳转至

信号槽机制

参考:

信号槽简介

信号槽(Signals and Slots) 是 Qt 框架中用于对象间通信的核心机制,它为开发者提供了一种灵活、类型安全且高效的方式来实现对象间的交互。

  • 信号(Signal):信号是特殊的函数,在对象的内部状态发生特定变化时被发射。它只需要声明,无需手动实现具体代码,当满足特定条件时,Qt 会自动处理信号的发射。例如,当用户点击一个按钮时,按钮对象会发射 clicked() 信号。
  • 槽(Slot):槽本质上是普通的 C++ 成员函数,可以像其他函数一样被调用,也能在与之连接的信号被发射时自动触发执行。槽函数可以有参数和返回值,其定义和使用与普通 C++ 函数类似。

信号槽是观察者模式的一种实现,特性如下: - A、一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知; - B、一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候——也可以说是信号发出的时候——被调用的函数; - C、信号与槽的连接,形成一种观察者-被观察者的关系; - D、当事件或者状态发生改变的时候,信号就会被发出;同时,信号发出者有义务调用所有注册的对这个事件(信号)感兴趣的函数(槽)。

信号和槽是多对多的关系。一个信号可以连接多个槽,而一个槽也可以监听多个信号。

信号槽与语言无关,有多种方法可以实现信号槽,不同的实现机制会导致信号槽的差别很大。信号槽术语最初来自 Trolltech 公司的 Qt 库,由于其设计理念的先进性,立刻引起计算机科学界的注意,提出了多种不同的实现。目前,信号槽依然是 Qt 库的核心之一,其他许多库也提供了类似的实现,甚至出现了一些专门提供这一机制的工具库。

信号槽是Qt对象以及其派生类对象之间的一种高效通信接口,是Qt的核心特性,也是Qt区别与其他工具包的重要地方。信号槽完全独立于标准的C/C语言,因此要正确的处理好信号和槽,必须借助于一个成为MOC(Meta Object Compiler)的Qt工具,MOC工具是一个C预处理程序,能为高层次的事件处理自动生成所需要的附加代码。

解析connect函数

在Qt框架中,connect函数用于将对象的信号(signal)连接到另一个对象的槽(slot)上。当信号被发射(emit)时,与之连接的槽就会被调用。Qt的connect函数有多个重载版本,但最常见的形式接受四个或五个参数:

1、发送者(Sender):

  • 这是发出信号的对象。在Qt中,这通常是一个QObject或其子类的实例。
  • 参数类型:QObject *

2、信号(Signal):

  • 这是发送者对象中定义的一个信号。信号是类的成员函数,使用signals关键字在类的声明中定义。
  • 参数类型:通常是一个指向成员函数指针的类型,如void (SenderClass::*)(Args...),其中SenderClass是发送者的类名,Args...是信号的参数类型列表。
  • 注意:在Qt 5及以后版本中,你也可以使用&SenderClass::signalName这样的语法来指定信号。

3、接收者(Receiver):

  • 这是接收信号并调用槽的对象。它同样是一个QObject或其子类的实例。如果接收者为nullptr(或QCoreApplication::instance()),则槽函数将在全局范围内调用(即,作为静态成员函数或全局函数调用)。
  • 参数类型:QObject *

4、槽(Slot):

  • 这是接收者对象中定义的一个槽。槽是类的成员函数,使用slots关键字在类的声明中定义(但在Qt 5中,slots关键字是可选的)。
  • 参数类型:与信号相同的成员函数指针类型。
  • 注意:在Qt 5及以后版本中,你也可以使用&ReceiverClass::slotName这样的语法来指定槽。

5、连接类型(Connection Type)(可选参数):

  • 这个参数定义了信号和槽之间的连接类型。Qt支持几种不同的连接类型,如Qt::DirectConnection(直接连接)、Qt::QueuedConnection(排队连接)等。在Qt 5中,这个参数是可选的,并且默认是Qt::AutoConnection。
  • 参数类型:Qt::ConnectionType

下面是一个使用connect函数的示例:

Text Only
// 假设有两个类:Sender 和 Receiver,它们都是 QObject 的子类
// Sender 类有一个信号 signalEmitted()
// Receiver 类有一个槽 slotCalled()

Sender *sender = new Sender;
Receiver *receiver = new Receiver;

// 连接信号和槽
QObject::connect(sender, &Sender::signalEmitted, receiver, &Receiver::slotCalled);

// 在某个地方,当 signalEmitted() 被调用时,slotCalled() 也会被调用
sender->emit signalEmitted();

Qt 5引入了一种新的信号和槽语法,它使用函数指针而不是字符串来指定信号和槽,这提高了类型安全性和编译时检查。在上面的示例中,我们使用了这种新语法。如果你正在使用较旧的Qt版本,你可能需要使用基于字符串的旧语法。但是,新语法更受欢迎,因为它更安全且易于使用。