1、前言
主窗口中包含4个导航按钮(监控、趋势、报警、设置)以及一个页面内容展示区域,多个导航按钮用于切换不同页面内容,实现导航需要用到信号和槽的关联。掌握信号机制是用好 Qt 的关键,它不仅适用于界面交互(如按钮点击、输入框变化),也适用于后台逻辑的异步通信。
2、马上干
1、新建4个新文件









2、新增信号
一、 Qt 的 Signals
信号是 Qt 为 C++ 扩展的一种特殊成员函数,本质上是事件的通知器:当某个特定事件发生时(比如按钮被点击、数据更新、窗口关闭),对象会发射(emit)对应的信号,告知外界 "这个事件发生了"。
信号有几个核心特点:
- 信号本身不包含任何实际逻辑,只负责 "通知",具体的处理逻辑由 "槽(Slots)" 来实现。
- 信号必须声明在类的
signals:区域(无需加public/private/protected,默认是public)。 - 信号不能被手动调用,只能通过
emit关键字触发(Qt 底层会处理调用逻辑)。 - 信号的返回值必须是
void,可以有参数(用于传递事件相关的数据)。
二、信号使用步骤
- 前置条件
使用信号与槽的类必须满足两个条件:
- 继承自
QObject(或其子类,如QWidget、QPushButton等)。 - 在类声明的最开始添加
Q_OBJECT宏(这是 Qt 元对象系统的核心,用于实现信号槽机制)。
2.声明信号
cpp
#include <QObject>
// 自定义类,继承 QObject
class MyClass : public QObject
{
Q_OBJECT // 必须添加这个宏,否则信号槽失效
public:
explicit MyClass(QObject *parent = nullptr) : QObject(parent) {}
// 声明信号:放在 signals: 区域
signals:
// 无参数信号:比如"数据更新"通知
void dataUpdated();
// 带参数信号:传递更新后的数据(支持多个参数,类型任意)
void dataUpdatedWithValue(int newValue, const QString &info);
};
- 发射(触发)信号
通过 emit 关键字触发信号,通常在某个事件发生时调用:
cpp
// 模拟"数据更新"事件
void MyClass::updateData(int value)
{
// 数据处理逻辑...
int newVal = value * 2;
// 发射无参数信号
emit dataUpdated();
// 发射带参数信号,传递数据
emit dataUpdatedWithValue(newVal, "数据更新完成");
}
三、信号与槽的关联
信号本身没有意义,必须和 "槽" 关联才能实现事件处理。Qt 提供了多种关联方式,最常用的是 connect 函数:
cpp
#include <QApplication>
#include <QPushButton>
#include <QObject>
class MyWidget : public QObject
{
Q_OBJECT
public slots: // 声明槽函数(Qt5 后槽也可放在普通成员函数区域)
void onButtonClicked() {
qDebug() << "按钮被点击了!";
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 创建按钮(Qt 内置控件,自带 clicked() 信号)
QPushButton btn("点击我");
btn.show();
// 创建自定义对象(包含槽函数)
MyWidget w;
// 关联信号与槽:按钮的 clicked 信号触发 onButtonClicked 槽
QObject::connect(&btn, &QPushButton::clicked, &w, &MyWidget::onButtonClicked);
return a.exec();
}
四、信号的关键注意事项
- 参数匹配 :信号的参数个数可以≥槽的参数个数,且类型必须一一对应(槽可以忽略信号的部分参数)。
- 合法:
signal(int, QString)→slot(int) - 非法:
signal(int)→slot(int, QString)
- 合法:
- 线程安全:Qt 支持跨线程的信号槽关联,默认会自动处理线程间的消息传递。
- 自动生成代码 :
signals是 Qt 的扩展语法,编译时 Qt 的moc(元对象编译器)会自动生成信号的实现代码,无需你手动编写。 - 信号重载 :如果信号有重载(同名不同参数),关联时需要用
static_cast明确指定信号类型:
信号与槽是 Qt 区别于原生 C++ 的核心特性,它实现了对象间的松散耦合,是 Qt 界面开发、异步通信的基础

3、触发信号
emit 关键字,它是触发 Qt 信号(signals)的核心关键字,专门用于 "发射" 信号,从而触发所有关联到该信号的槽函数执行
一、emit 是什么?
emit 是 Qt 为 C++ 扩展的一个空宏 (本质上被预处理为空白),作用是明确标识 "发射信号" 这个动作,让代码可读性更高。
- 语法上:
emit写在信号函数调用的前面,格式为emit 信号名(参数);。 - 底层逻辑:当你用
emit触发信号时,Qt 的元对象系统会自动遍历该信号关联的所有槽函数,并按照指定的连接类型(如直连 / 队列连接)执行这些槽函数。
使用 emit 的前提是:
- 信号所在的类必须继承
QObject并添加Q_OBJECT宏; - 信号已在
signals:区域声明(返回值为void,可带参数)
信号可以携带参数,emit 时需要传入对应类型的参数,槽函数可接收这些参数
cpp
#include <QObject>
#include <QDebug>
class DataSender : public QObject
{
Q_OBJECT
signals:
// 带参数的信号:传递字符串和整数
void newData(const QString &data, int id);
};
class DataReceiver : public QObject
{
Q_OBJECT
public slots:
// 槽函数接收信号的参数
void processData(const QString &data, int id) {
qDebug() << "收到数据 ID:" << id << ",内容:" << data;
}
};
int main()
{
DataSender sender;
DataReceiver receiver;
// 关联信号与槽
QObject::connect(&sender, &DataSender::newData,
&receiver, &DataReceiver::processData);
// 发射带参数的信号
emit sender.newData("Hello Qt", 1001); // 输出:收到数据 ID: 1001 ,内容: Hello Qt
return 0;
}
二、emit 的基本用法


4、关联信号
一、connect 函数的核心作用
connect 函数的本质是建立信号和槽之间的关联关系:当某个对象(发送者)发射指定信号时,自动调用另一个对象(接收者)的指定槽函数,实现 "事件触发→逻辑响应" 的解耦式通信。
二、connect 函数的主要形式
基于函数指针的写法,这是目前最推荐的用法。 自定义信号与槽的关联
cpp
#include <QObject>
#include <QDebug>
class Sender : public QObject
{
Q_OBJECT
signals:
// 自定义信号:带参数
void sendMessage(const QString &text, int num);
};
class Receiver : public QObject
{
Q_OBJECT
public slots:
// 自定义槽:参数个数 ≤ 信号,类型匹配
void receiveMessage(const QString &text) {
qDebug() << "收到消息:" << text;
}
};
int main()
{
Sender sender;
Receiver receiver;
// 关联自定义信号与槽
QObject::connect(&sender, &Sender::sendMessage,
&receiver, &Receiver::receiveMessage);
// 发射信号:触发槽函数执行
emit sender.sendMessage("Hello Qt", 123); // 输出:收到消息: Hello Qt
return 0;
}
connect 函数是 Qt 信号槽机制的入口,掌握它的不同写法和参数规则,就能灵活实现 Qt 对象间的通信。







5、运行测试




6、小结
Qt 完整的信号机制(信号与槽体系),这是 Qt 最核心的特色之一。
- 它实现了松耦合:信号发送者无需知道谁接收信号,接收者也无需知道信号来自哪里;
- 它是类型安全的:编译期会检查信号与槽的参数匹配性,避免回调函数的类型错误;
- 它支持跨线程通信:无需手动处理线程同步,Qt 自动适配不同线程的执行方式


掌握信号机制是用好 Qt 的关键,它不仅适用于界面交互(如按钮点击、输入框变化),也适用于后台逻辑的异步通信(如下载进度、数据更新)。
原创不易,打字不易,截图不易,撸码不易,整理不易,走过路过,不要错过,欢迎点赞,收藏,转载,复制,抄袭,留言,灌水,请动动你的金手指,祝您早日实现财务自由。
