编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

    • README
    • QML基础入门

    • QT核心库实践

      • README
      • 核心功能基础
      • 并发与多线程
      • 文件与IO系统
      • 日期与时间处理
      • 网络与序列化
      • QT事件系统
      • 信号与槽机制
        • 7.1 基本概念
          • 7.1.1 信号与槽
          • 7.1.2 信号(Signal)
          • 7.1.3 槽(Slot)
          • 7.1.4 连接(Connect)
          • 7.1.5 优点和缺点
        • 7.2 信号与槽使用
          • 7.2.1 声明信号与槽
          • 7.2.2 连接信号与槽
          • 7.2.3 Lambda表达式
        • 7.3 信号与槽特性
          • 7.3.1 自动连接
          • 7.3.2 参数传递
          • 7.3.3 多对多连接
          • 7.3.4 断开连接
        • 7.4 跨线程通信
          • 7.4.1 连接类型
          • 7.4.2 跨线程通信案例
        • 7.5 信号槽和事件
          • 7.5.1 两者关系
        • 7.5 信号槽综合案例
          • 7.5.1 项目结构
          • 7.5.2 代码实现
          • 7.5.3 运行结果
          • 7.5.4 代码解析
          • 7.5.5 断开连接
          • 7.5.6 综合案例总结
      • 多媒体的应用
      • 容器类和算法
      • 高级编程技巧
    • Linux实践开发

  • Apps
  • Linux应用开发
  • QT核心库实践
杨充
2025-09-15
目录

信号与槽机制

# 07.信号和槽机制

# 目录介绍

  • 7.1 基本概念
    • 7.1.1 信号与槽
    • 7.1.2 信号(Signal)
    • 7.1.3 槽(Slot)
    • 7.1.4 连接(Connect)
    • 7.1.5 优点和缺点
  • 7.2 信号与槽使用
    • 7.2.1 声明信号与槽
    • 7.2.2 连接信号与槽
    • 7.2.3 Lambda表达式
  • 7.3 信号与槽特性
    • 7.3.1 自动连接
    • 7.3.2 参数传递
    • 7.3.3 多对多连接
    • 7.3.4 断开连接
  • 7.4 跨线程通信
    • 7.4.1 连接类型
    • 7.4.2 跨线程通信案例
  • 7.5 信号槽和事件
    • 7.5.1 两者关系
  • 7.5 信号槽综合案例
    • 7.5.1 项目结构
    • 7.5.2 代码实现
    • 7.5.3 运行结果
    • 7.5.4 代码解析
    • 7.5.5 断开连接
    • 7.5.6 综合案例总结

# 7.1 基本概念

Qt 的信号与槽机制是其核心特性之一,用于实现对象之间的通信。信号与槽机制是 Qt 对观察者模式的实现,具有类型安全、松耦合和跨线程通信等优点。

# 7.1.1 信号与槽

功能:实现对象之间的松耦合通信。核心类:

  • QObject:提供信号与槽的基础支持。
  • QSignalMapper:将多个信号映射到单个槽。
  • QMetaObject::connect:动态连接信号与槽。

信号与槽机制,核心概念:

  • 信号(Signal):对象发出的事件(如按钮点击)。
  • 槽(Slot):响应信号的函数。
  • 信号与槽通过 QObject::connect 函数连接,实现对象间的通信。

# 7.1.2 信号(Signal)

信号是类中声明的特殊成员函数,用于在特定事件发生时发出通知。

信号不需要实现,只需声明。信号可以带参数,用于传递数据。

# 7.1.3 槽(Slot)

槽是普通的成员函数,用于响应信号。

槽需要实现。槽可以带参数,参数类型必须与信号匹配。

# 7.1.4 连接(Connect)

使用 QObject::connect() 函数将信号与槽连接起来。当信号发出时,连接的槽函数会被自动调用。

# 7.1.5 优点和缺点

松耦合:对象间无需直接调用彼此的方法。

灵活性:一个信号可以连接多个槽,一个槽可以响应多个信号。

# 7.2 信号与槽使用

# 7.2.1 声明信号与槽

在类中使用 signals 和 slots 关键字声明信号和槽。

#include <QObject>
#include <QDebug>

class MyClass : public QObject {
    Q_OBJECT // 必须包含 Q_OBJECT 宏

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

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

public slots:
    void mySlot(int value) { // 声明槽
        qDebug() << "Slot received value:" << value;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 7.2.2 连接信号与槽

QObject::connect() 是用于连接信号(Signal)与槽(Slot)的核心函数。它的作用是将一个对象的信号与另一个对象的槽函数关联起来,当信号被触发时,槽函数会自动执行。

函数原型,以及参数详细介绍

static bool QObject::connect(
    const QObject *sender,        // 发送信号的对象
    const char *signal,           // 信号的名称
    const QObject *receiver,      // 接收信号的对象
    const char *slot,             // 槽函数的名称
    Qt::ConnectionType type = Qt::AutoConnection // 连接类型
);
1
2
3
4
5
6
7
  1. sender,类型:const QObject *;含义:发送信号的对象指针。示例:button(按钮对象)。
  2. signal,类型:const char *;含义:信号的名称,需要使用 SIGNAL() 宏进行封装。示例:SIGNAL(clicked())(按钮的点击信号)。
  3. receiver,类型:const QObject *;含义:接收信号的对象指针。示例:this(当前对象)。
  4. slot,类型:const char *;含义:槽函数的名称,需要使用 SLOT() 宏进行封装。示例:自定义的槽函数
  5. type,类型:Qt::ConnectionType;含义:连接类型,决定信号与槽的执行方式。默认值为 Qt::AutoConnection。可选值:
  • Qt::AutoConnection:自动选择连接方式(默认)。
  • Qt::DirectConnection:信号触发时立即执行槽函数(同步)。
  • Qt::QueuedConnection:将槽函数放入事件队列,稍后执行(异步)。
  • Qt::BlockingQueuedConnection:阻塞发送线程,直到槽函数执行完毕。
  • Qt::UniqueConnection:确保连接是唯一的,避免重复连接。

返回值,类型:bool。含义:连接是否成功。如果成功返回 true,否则返回 false。

# 7.2.3 Lambda表达式

Lambda 表达式可以作为槽函数使用,简化代码。

QObject::connect(&sender, &MyClass::mySignal, [](int value) {
    qDebug() << "Lambda received value:" << value;
});
1
2
3

# 7.3 信号与槽特性

# 7.3.1 自动连接

信号与槽的连接是自动的,当信号发出时,槽函数会被立即调用。

# 7.3.2 参数传递

信号与槽的参数类型必须匹配,但槽的参数可以比信号少。

QObject::connect(&sender, &MyClass::mySignal, &receiver, [](int value) {
    qDebug() << "Lambda received value:" << value;
});
1
2
3

# 7.3.3 多对多连接

一个信号可以连接多个槽,一个槽也可以接收多个信号。

QObject::connect(&sender, &MyClass::mySignal, &receiver1, &MyClass::mySlot);
QObject::connect(&sender, &MyClass::mySignal, &receiver2, &MyClass::mySlot);
1
2

# 7.3.4 断开连接

使用 QObject::disconnect() 断开信号与槽的连接。

QObject::disconnect(&sender, &MyClass::mySignal, &receiver, &MyClass::mySlot);
1

# 7.4 跨线程通信

Qt 的信号与槽机制支持跨线程通信,通过 Qt::ConnectionType 参数指定连接类型。

# 7.4.1 连接类型

  • Qt::AutoConnection(默认):如果信号和槽在同一线程,使用直接连接;否则,使用队列连接。
  • Qt::DirectConnection:槽函数在信号发出的线程中立即执行。
  • Qt::QueuedConnection:槽函数在接收对象的线程中异步执行。
  • Qt::BlockingQueuedConnection:槽函数在接收对象的线程中同步执行,发送线程会阻塞直到槽函数执行完毕。

# 7.4.2 跨线程通信案例

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(int value) {
        qDebug() << "Worker thread ID:" << QThread::currentThreadId();
        qDebug() << "Received value:" << value;
    }
};

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

    QThread workerThread;
    Worker worker;

    worker.moveToThread(&workerThread); // 将 worker 移动到新线程
    workerThread.start();

    // 跨线程连接
    QObject::connect(&app, &QCoreApplication::aboutToQuit, &worker, &Worker::deleteLater);
    QObject::connect(&app, &QCoreApplication::aboutToQuit, &workerThread, &QThread::quit);
    QObject::connect(&workerThread, &QThread::finished, &workerThread, &QThread::deleteLater);

    // 发送信号
    emit worker.doWork(42);

    return app.exec();
}
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
30
31
32
33
34
35

# 7.5 信号槽和事件

# 7.5.1 两者关系

信号槽机制深度依赖事件循环:

信号发射 → 生成元调用事件 → 加入事件队列 → 事件循环处理 → 执行槽函数
1

# 7.5 信号槽综合案例

以下是一个比较全面的 Qt 信号与槽使用案例,涵盖了信号与槽的基本用法、带参数的信号与槽、Lambda 表达式作为槽、跨线程通信、以及信号与槽的断开连接等场景。

# 7.5.1 项目结构

SignalSlotExample/
├── main.cpp
├── MyClass.h
├── MyClass.cpp
├── Worker.h
├── Worker.cpp
1
2
3
4
5
6

# 7.5.2 代码实现

(1)MyClass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QDebug>
#include <QThread>
#include "Worker.h"

class MyClass : public QObject {
    Q_OBJECT

public:
    explicit MyClass(QObject *parent = nullptr);

signals:
    void signalWithoutArgs(); // 无参数的信号
    void signalWithArgs(int value, const QString &text); // 带参数的信号

public slots:
    void slotWithoutArgs(); // 无参数的槽
    void slotWithArgs(int value, const QString &text); // 带参数的槽

private:
    Worker *worker;
    QThread workerThread;
};

#endif // MYCLASS_H
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

(2)MyClass.cpp

#include "MyClass.h"

MyClass::MyClass(QObject *parent) : QObject(parent) {
    // 创建 Worker 对象
    worker = new Worker();
    // 将 Worker 移动到子线程
    worker->moveToThread(&workerThread);
    // 连接信号与槽
    // 1. 无参数的信号与槽
    connect(this, &MyClass::signalWithoutArgs, this, &MyClass::slotWithoutArgs);
    // 2. 带参数的信号与槽
    connect(this, &MyClass::signalWithArgs, this, &MyClass::slotWithArgs);
    // 3. 跨线程的信号与槽
    connect(this, &MyClass::signalWithArgs, worker, &Worker::doWork);
    // 4. 使用 Lambda 表达式作为槽
    connect(this, &MyClass::signalWithoutArgs, []() {
        qDebug() << "Lambda slot called!";
    });
    // 启动子线程
    workerThread.start();
}

void MyClass::slotWithoutArgs() {
    qDebug() << "Slot without args called!";
}

void MyClass::slotWithArgs(int value, const QString &text) {
    qDebug() << "Slot with args called! Value:" << value << "Text:" << text;
}
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

(3)Worker.h

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QDebug>
#include <QThread>

class Worker : public QObject {
    Q_OBJECT
public slots:
    void doWork(int value, const QString &text);
};

#endif // WORKER_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14

(4)Worker.cpp

#include "Worker.h"

void Worker::doWork(int value, const QString &text) {
    qDebug() << "Worker is running in thread:" << QThread::currentThreadId();
    qDebug() << "Received value:" << value << "Text:" << text;
}
1
2
3
4
5
6

(5)main.cpp

#include <QCoreApplication>
#include "MyClass.h"

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

    MyClass myClass;

    // 发出无参数的信号
    emit myClass.signalWithoutArgs();

    // 发出带参数的信号
    emit myClass.signalWithArgs(42, "Hello, Qt!");

    return a.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 7.5.3 运行结果

运行程序后,输出如下:

Slot without args called!
Lambda slot called!
Slot with args called! Value: 42 Text: "Hello, Qt!"
Worker is running in thread: 0x7f8b8b5c1700
Received value: 42 Text: "Hello, Qt!"
1
2
3
4
5

# 7.5.4 代码解析

  1. 无参数的信号与槽:
  • signalWithoutArgs 信号触发 slotWithoutArgs 槽和 Lambda 表达式。
  1. 带参数的信号与槽:
  • signalWithArgs 信号触发 slotWithArgs 槽和 Worker::doWork 槽。
  1. 跨线程通信:
  • Worker 对象在子线程中运行,signalWithArgs 信号通过 Qt::QueuedConnection 自动跨线程调用 Worker::doWork。
  1. Lambda 表达式作为槽:
  • 使用 Lambda 表达式作为槽函数,简化代码。

# 7.5.5 断开连接

如果需要断开信号与槽的连接,可以使用 disconnect 函数:

disconnect(this, &MyClass::signalWithoutArgs, this, &MyClass::slotWithoutArgs);
1

# 7.5.6 综合案例总结

这个案例展示了 Qt 信号与槽的多种用法,包括:

  • 无参数的信号与槽。
  • 带参数的信号与槽。
  • 使用 Lambda 表达式作为槽。
  • 跨线程的信号与槽通信。
  • 信号与槽的断开连接。
上次更新: 2026/06/10, 11:13:41
QT事件系统
多媒体的应用

← QT事件系统 多媒体的应用→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式