Qt中自定义信号与槽

自定义信号与槽

Qt 中自定义信号与槽

在 Qt 中,信号与槽不仅可以使用框架内置的接口,也可以由开发者自定义。这使得 Qt 可以在对象之间构建 灵活、解耦的通信机制。在实际项目中,自定义信号与槽经常用于 业务逻辑通知、模块间通信以及状态变化广播

例如:

  • 网络模块收到数据 → 通知 UI 更新
  • 后台任务完成 → 通知主线程刷新界面
  • 某个业务状态变化 → 通知多个模块响应

这些场景都非常适合通过 自定义信号与槽 实现。


一、自定义信号与槽的基本语法

Qt 允许开发者在类中声明自己的信号和槽,但需要遵循一定的规范。

1 自定义信号

信号需要在 signals 关键字下声明,例如:

1
2
3
4
5
6
7
8
9
10
class Teacher : public QObject
{
Q_OBJECT

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

signals:
void classBegin();
};

信号的特点:

  • 必须写在 signals 区域中
  • 返回值必须为 void
  • 只声明,不需要实现
  • 可以带参数
  • 可以重载

例如:

1
2
3
signals:
void classBegin();
void classBegin(QString courseName);

信号函数实际上 不会由开发者实现。Qt 在编译阶段通过 MOC(Meta Object Compiler) 自动生成相关代码。


2 自定义槽

槽本质上就是普通成员函数,用于响应信号。

早期 Qt 版本要求槽必须写在:

1
public slots:

但在 Qt5 之后,这个限制已经放宽,槽函数可以写在:

1
2
3
public
protected
private

例如:

1
2
3
4
5
6
7
8
9
10
class Student : public QObject
{
Q_OBJECT

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

public slots:
void startStudy();
};

槽函数特点:

  • 需要声明并实现
  • 返回值通常为 void
  • 可以带参数
  • 可以重载
  • 可以像普通函数一样被调用

实现示例:

1
2
3
4
void Student::startStudy()
{
qDebug() << "学生开始学习";
}

二、发送信号

信号通过 emit 关键字发送:

1
emit classBegin();

需要注意:

  • emit 本质上是 一个空宏
  • 即使不写 emit,代码也可以正常工作

例如:

1
classBegin();

依然可以触发信号。

不过在 Qt 开发中,建议保留 emit,因为它可以明显表达代码意图,使代码更具可读性。


三、连接信号与槽

信号与槽之间需要通过 connect() 建立连接:

1
connect(sender, signal, receiver, slot);

连接建立后:

1
SignalSlot

当信号发射时,Qt 会自动调用对应的槽函数。

需要注意 连接顺序问题

1
connect → emit

如果先发射信号,再建立连接:

1
emit → connect

那么信号不会触发任何槽函数。


四、自定义信号槽示例

下面通过一个简单的示例说明自定义信号与槽的使用。

假设有这样一个场景:

老师说 “上课了”,学生开始学习。

1 定义 Teacher 类

1
2
3
4
5
6
7
8
9
10
class Teacher : public QObject
{
Q_OBJECT

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

signals:
void classBegin();
};

2 定义 Student 类

1
2
3
4
5
6
7
8
9
10
class Student : public QObject
{
Q_OBJECT

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

public slots:
void startStudy();
};

实现:

1
2
3
4
void Student::startStudy()
{
qDebug() << "学生回到座位,开始学习";
}

3 在主程序中连接信号与槽

1
2
3
4
5
Teacher teacher;
Student student;

QObject::connect(&teacher, &Teacher::classBegin,
&student, &Student::startStudy);

4 发送信号

1
emit teacher.classBegin();

执行结果:

1
学生回到座位,开始学习

逻辑流程:

1
2
3
Teacher 发出信号

Student 槽函数被调用

五、带参数的信号与槽

信号和槽可以携带参数,用于传递数据。

例如:

1
2
signals:
void classBegin(QString courseName);

对应槽:

1
2
public slots:
void startStudy(QString courseName);

连接:

1
2
connect(&teacher, &Teacher::classBegin,
&student, &Student::startStudy);

发送信号:

1
emit teacher.classBegin("C++");

输出:

1
开始学习 C++

需要注意:

槽函数的参数数量可以 少于信号参数,但不能多于信号参数。

例如:

1
2
3
4
Signal:  void signal(int a, int b)
Slot: void slot(int a)
Slot: void slot(int a, int b)
Slot: void slot(int a, int b, int c)

六、自定义类通常继承 QObject

在 Qt 中,如果一个类需要使用信号槽机制,通常需要继承 QObject

1
2
3
4
class MyClass : public QObject
{
Q_OBJECT
};

原因是:

  1. 信号槽依赖 Qt 的 元对象系统
  2. QObject 提供对象树机制
  3. 支持动态属性、事件系统等

如果类没有继承 QObject,则无法使用信号与槽。


总结

Qt 的自定义信号与槽为应用程序提供了一种 灵活、解耦的通信机制。通过它可以轻松实现对象之间的事件通知,而不需要直接依赖彼此。

其核心流程可以总结为:

1
2
3
4
定义 Signal
定义 Slot
connect 建立连接
emit 发射信号

Qt中自定义信号与槽
https://weihehe.top/2025/02/25/C-与SWIG/
作者
weihehe
发布于
2025年2月25日
许可协议