码上通QT实战08--导航按钮切换界面

1、前言

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

2、马上干

1、新建4个新文件

2、新增信号

一、 Qt 的 Signals

信号是 Qt 为 C++ 扩展的一种特殊成员函数,本质上是事件的通知器:当某个特定事件发生时(比如按钮被点击、数据更新、窗口关闭),对象会发射(emit)对应的信号,告知外界 "这个事件发生了"。

信号有几个核心特点:

  1. 信号本身不包含任何实际逻辑,只负责 "通知",具体的处理逻辑由 "槽(Slots)" 来实现。
  2. 信号必须声明在类的 signals: 区域(无需加 public/private/protected,默认是 public)。
  3. 信号不能被手动调用,只能通过 emit 关键字触发(Qt 底层会处理调用逻辑)。
  4. 信号的返回值必须是 void,可以有参数(用于传递事件相关的数据)。

二、信号使用步骤

  1. 前置条件

使用信号与槽的类必须满足两个条件:

  • 继承自 QObject(或其子类,如 QWidgetQPushButton 等)。
  • 在类声明的最开始添加 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);
};
点击并拖拽以移动
  1. 发射(触发)信号

通过 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();
}
点击并拖拽以移动

四、信号的关键注意事项

  1. 参数匹配 :信号的参数个数可以≥槽的参数个数,且类型必须一一对应(槽可以忽略信号的部分参数)。
    • 合法:signal(int, QString)slot(int)
    • 非法:signal(int)slot(int, QString)
  2. 线程安全:Qt 支持跨线程的信号槽关联,默认会自动处理线程间的消息传递。
  3. 自动生成代码signals 是 Qt 的扩展语法,编译时 Qt 的 moc(元对象编译器)会自动生成信号的实现代码,无需你手动编写。
  4. 信号重载 :如果信号有重载(同名不同参数),关联时需要用 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 的关键,它不仅适用于界面交互(如按钮点击、输入框变化),也适用于后台逻辑的异步通信(如下载进度、数据更新)。

复制代码
原创不易,打字不易,截图不易,撸码不易,整理不易,走过路过,不要错过,欢迎点赞,收藏,转载,复制,抄袭,留言,灌水,请动动你的金手指,祝您早日实现财务自由。
相关推荐
一只小bit13 小时前
Qt 常用控件详解:按钮类 / 显示类 / 输入类属性、信号与实战示例
前端·c++·qt·gui
AC赳赳老秦13 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
不知道累,只知道类14 小时前
深入理解 Java 虚拟线程 (Project Loom)
java·开发语言
国强_dev14 小时前
Python 的“非直接原因”报错
开发语言·python
YMatrix 官方技术社区14 小时前
YMatrix 存储引擎解密:MARS3 存储引擎如何超越传统行存、列存实现“时序+分析“场景性能大幅提升?
开发语言·数据库·时序数据库·数据库架构·智慧工厂·存储引擎·ymatrix
玖疯子14 小时前
技术文章大纲:Bug悬案侦破大会
开发语言·ar
独自破碎E15 小时前
解释一下NIO、BIO、AIO
java·开发语言·nio
草莓熊Lotso15 小时前
脉脉独家【AI创作者xAMA】|当豆包手机遭遇“全网封杀”:AI学会操作手机,我们的饭碗还保得住吗?
运维·开发语言·人工智能·智能手机·脉脉
@areok@15 小时前
C++opencv图片(mat)传入C#bitmap图片
开发语言·c++·opencv