QT从入门到精通(二) ——信号与槽机制

Qt 的信号与槽机制 (Signal and Slot)是 Qt 框架 中用于对象间通信的核心机制之一。它允许对象之间进行松耦合的事件驱动式通信,尤其适合 GUI 应用程序 中的事件处理。


1. 基本概念

信号 (Signal)

  • 当对象的状态发生变化时,它会发出一个信号
  • 信号是一种声明,不需要实现。
  • 信号不需要知道谁会接收它,也就是松耦合的设计。

槽 (Slot)

  • 槽是一个普通的函数,可以用来接收信号。
  • 当信号发出时,与之关联的槽函数将被自动调用。
  • 槽可以是成员函数、普通函数或 lambda 表达式。

连接 (Connect)

  • 信号和槽通过 QObject::connect() 进行连接。
  • 当信号发出时,Qt 会自动调用与其连接的槽。

2. 信号与槽的工作原理

Qt 的信号与槽机制基于 元对象系统(Meta-Object System),它使用以下特性:

  • Q_OBJECT 宏:类中必须包含此宏,表示该类支持信号与槽。
  • moc 工具:Qt 的元对象编译器,会处理信号与槽相关的代码。

Qt 的 事件循环 负责在对象间传递信号,确保槽在正确的上下文中执行。


3. 信号与槽的定义与使用

1) 定义一个信号与槽

要使用信号与槽,必须满足以下条件:

  • 类需要继承自 QObject
  • 在类声明中加入 Q_OBJECT 宏。
  • 使用 signals 关键字声明信号。
  • 使用 slots 关键字声明槽函数。

示例代码:

定义类:
cpp 复制代码
#include <QObject>
#include <QDebug>

class MyObject : public QObject {
    Q_OBJECT

public:
    explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}

signals:
    void mySignal(int value); // 声明一个信号

public slots:
    void mySlot(int value) {  // 定义一个槽
        qDebug() << "Received signal with value:" << value;
    }
};
连接信号与槽:
cpp 复制代码
#include <QCoreApplication>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    MyObject obj1, obj2;

    // 连接信号与槽
    QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot);

    // 触发信号
    emit obj1.mySignal(42);

    return a.exec();
}

输出结果:

复制代码
Received signal with value: 42

2) 连接方式

QObject::connect 有多种形式,支持不同的连接模式。

语法:

cpp 复制代码
QObject::connect(sender, SIGNAL(signalName(params)), receiver, SLOT(slotName(params)));

现代写法(推荐): 使用函数指针和 lambda 表达式。

cpp 复制代码
QObject::connect(sender, &ClassName::signalName, receiver, &ClassName::slotName);

Lambda 表达式示例:

cpp 复制代码
QObject::connect(&obj1, &MyObject::mySignal, [](int value) {
    qDebug() << "Lambda slot received value:" << value;
});

3) 信号与槽的重载

如果信号或槽有多个重载版本,必须在连接时指定函数指针。

示例:

cpp 复制代码
class Example : public QObject {
    Q_OBJECT
signals:
    void valueChanged(int);
    void valueChanged(double);
};

Example obj;
QObject::connect(&obj, static_cast<void (Example::*)(int)>(&Example::valueChanged), 
                 &obj, [](int value) { qDebug() << "Int version called:" << value; });

4. 信号与槽的特点

  1. 松耦合
    • 信号的发送者和槽的接收者无需了解彼此的存在。
  2. 类型安全
    • 信号与槽的参数必须匹配,否则编译器会报错。
  3. 多对多关系
    • 一个信号可以连接多个槽。
    • 多个信号可以连接到同一个槽。
  4. 线程安全
    • 跨线程连接时,信号会安全地传递到接收线程。

5. 信号与槽的连接类型

在多线程程序中,Qt 提供了不同的连接类型:

连接类型:

  1. Qt::AutoConnection(默认)

    • 如果信号和槽在同一线程中,则为直接连接
    • 如果在不同线程中,则为队列连接
  2. Qt::DirectConnection

    • 信号发出后,槽会立即执行,位于发送线程。
  3. Qt::QueuedConnection

    • 信号会进入接收线程的事件队列,由接收线程执行。
  4. Qt::BlockingQueuedConnection

    • 发送线程阻塞,直到槽函数执行完毕。仅适用于跨线程。

6. 注意事项

  1. 使用 Q_OBJECT
    • 类必须继承自 QObject,并包含 Q_OBJECT 宏,否则信号与槽不会工作。
  1. moc 工具的支持

    • 需要使用 Qt 的 Meta-Object Compiler (moc) 进行预处理,否则信号与槽无法解析。
  2. 参数匹配

    • 信号与槽的参数个数和类型必须兼容。信号的参数可以多于槽的参数,但前者必须兼容后者。
  3. 析构时自动断开连接

    • 当对象被销毁时,Qt 会自动断开与该对象相关的所有连接。

总结

Qt 的信号与槽机制是一种强大且灵活的事件处理机制,它提供了类型安全松耦合 的通信方式,广泛用于 Qt 应用程序中的 组件间交互事件处理

现代 C++ 写法(函数指针和 Lambda 表达式)更加简洁和安全,推荐在新代码中使用。

相关推荐
weixin_428005303 分钟前
C#调用 AI学习从0开始-第2阶段(Function Calling+工具调用智能体)-第9天实战-实现计算器工具
开发语言·学习·c#·functioncalling·ai实现计算器工具
特种加菲猫22 分钟前
C++11核心特性深度解析:从列表初始化到lambda与包装器
开发语言·c++
JSMSEMI1127 分钟前
JSM12N60C 600V N沟道增强型功率MOSFET
开发语言·javascript·ecmascript
设计师小聂!27 分钟前
Java异常处理
java·开发语言·后端·编辑器·idea
清水白石00830 分钟前
从打印对象到高质量调试:彻底理解 Python 中 `__repr__` 和 `__str__` 的区别
开发语言·python
枕星而眠36 分钟前
C++ 面向对象核心机制深度解析:多态性、虚函数、虚继承与 final 类
运维·开发语言·c++·后端
minji...38 分钟前
MySQL数据库 (四) MySQL的数据类型,tinyint,float,decimal,枚举enum和集合set
数据库·mysql·tinyint·enum·decimal·varchar·bit
阿演1 小时前
DataDjinn 新版本更新:国产数据库支持、连接树体验、AI 查询和表格编辑继续增强
数据库·人工智能·ai·ai编程
Evand J1 小时前
【MATLAB例程】自适应渐消扩展卡尔曼滤波(AFEKF)三维雷达目标跟踪|效果已调优,附下载链接和运行结果,代码直接运行即可
开发语言·算法·matlab·目标跟踪·卡尔曼滤波·自适应滤波·代码定制
爱装代码的小瓶子1 小时前
3. 设计buffer模块
linux·服务器·开发语言·c++·php