自定义信号和槽
信号链式传递是信号触发槽再发信号,实现多级响应;信号转发是接收信号后原样或处理后发出新信号,解耦模块通信。
自定义信号和槽
自定义信号和槽
信号链式传递
在 Qt 中,信号链式传递(Signal Chaining / Signal Relay)是指:
一个对象接收到信号后,在对应的槽函数中再次发出另一个信号,从而实现多个对象之间信号的逐级传递或响应链式处理。
这种模式可以让多个模块间解耦通信,适用于状态同步、事件广播、控制流分层等复杂场景。
基础示意图:
1
2
3
4
5
6
7
Object A ---emit---> signalA()
|
v
Object B <--slotA()--- 接收信号后 emit signalB()
|
v
Object C <--slotB()--- 最终处理
自定义信号示例
widget.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
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget* parent = nullptr);
~Widget();
signals: // 信号默认强制规定为公有类型,这样才能保证其他对象能接收到信号
void sendMsg(QString str); // 信号只需要声明,而不要写实体代码
public slots:
void buttonClicked();
private:
Ui::Widget* ui;
};
#endif // WIDGET_H
widget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "widget.h"
#include "./ui_widget.h"
Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {
ui->setupUi(this);
// 关联按钮的点击事件到 buttonClicked
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::buttonClicked);
}
Widget::~Widget() {
delete ui;
}
void Widget::buttonClicked(){
// 用 emit 发信号
emit sendMsg(tr("这是发送的信息"));
}
点击按钮后会发送一个自定义的信号 sendMsg(QString str)
。
showmsg.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef SHOWMSG_H
#define SHOWMSG_H
#include <QObject>
class ShowMsg : public QObject {
Q_OBJECT
public:
explicit ShowMsg(QObject* parent = nullptr);
public slots:
void recvMsg(QString str);
};
#endif // SHOWMSG_H
showmsg.cpp
1
2
3
4
5
6
7
8
9
10
#include "showmsg.h"
#include <QMessageBox>
ShowMsg::ShowMsg(QObject* parent) : QObject{parent} {
}
void ShowMsg::recvMsg(QString str){
// 第一个参数是父窗口指针,设置为 NULL,代表没有父窗口,就是在系统桌面直接弹窗
QMessageBox::information(NULL, tr("Show"), str);
}
recvMsg(QString str)
负责接收信号并弹窗。
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "showmsg.h"
#include "widget.h"
#include <QApplication>
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
Widget w;
ShowMsg s;
// 关联,信号里的字符串参数会自动传递给槽函数
// 在 main 函数里,需要手动加 QObject:: 前缀来调用 connect 函数
QObject::connect(&w, &Widget::sendMsg, &s, &ShowMsg::recvMsg);
w.show();
return a.exec();
}
信号转发
在 Qt 中,信号转发(Signal Forwarding)是指:
一个对象接收到信号后,不做任何业务逻辑处理,而是原样或稍作处理后再次发出一个信号,从而把事件“转发”给其他对象或上层模块。
这是一种常用的“事件中继机制”,能让对象之间保持良好的解耦。
方式一:信号直接转发信号(推荐)
1
connect(sender, &Sender::signalA, this, &ThisClass::signalB);
要求:signalA
和 signalB
的参数 完全一致
方式二:槽函数中转发出另一个信号(可以做参数处理)
如果想对信号参数稍作处理,必须手写槽函数,再用 emit
发出新信号。
1
2
3
4
5
6
7
8
9
10
11
class Forwarder : public QObject {
Q_OBJECT
public slots:
void onSignalA(int value) {
// 做一点处理,然后发出另一个信号
emit signalB(value + 1);
}
signals:
void signalB(int value);
};
方式三:lambda 转发(用于临时逻辑、轻量场景)
在 C++11 及以上,可以用 lambda 捕获参数,转发出去:
1
2
3
QObject::connect(&objA, &A::signalA, [&objB](int v) {
emit objB.signalB(v); // 假设 signalB 是 public 信号
});
信号直接转发信号示例
widget.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
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget* parent = nullptr);
~Widget();
signals:
void sendVoid(); // 没有参数,所以能和按钮的 clicked 信号匹配,实现信号到信号的关联
private:
Ui::Widget* ui;
};
#endif // WIDGET_H
widget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include "widget.h"
#include "./ui_widget.h"
Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {
ui->setupUi(this);
// 第四个参数是信号,直接关联到自定义的信号,而不需要槽函数中转
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::sendVoid);
}
Widget::~Widget() {
delete ui;
}
showvoid.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef SHOWVOID_H
#define SHOWVOID_H
#include <QObject>
class ShowVoid : public QObject {
Q_OBJECT
public:
explicit ShowVoid(QObject* parent = nullptr);
signals:
public slots:
void recvVoid();
};
#endif // SHOWVOID_H
showvoid.cpp
1
2
3
4
5
6
7
8
9
#include "showvoid.h"
#include <QMessageBox>
ShowVoid::ShowVoid(QObject* parent) : QObject{parent} {
}
void ShowVoid::recvVoid(){
QMessageBox::information(NULL, tr("Show"), tr("Just void."));
}
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "showvoid.h"
#include "widget.h"
#include <QApplication>
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
Widget w;
ShowVoid s;
// clicked 发给 sendVoid,sendVoid 再发给 recvVoid
QObject::connect(&w, &Widget::sendVoid, &s, &ShowVoid::recvVoid);
w.show();
return a.exec();
}
本文由作者按照 CC BY 4.0 进行授权