当前位置: 首页 > news >正文

【QT】信号和槽(1) 使用 || 定义

一、信号和槽概述

  • 事件与信号
  • 在 Qt 中,用户与控件的交互(如点击按钮或关闭窗口)产生事件,每个事件触发相应的信号。
  • 信号是事件的通知形式,通过函数表示。
  • 响应与槽
  • 控件接收信号并作出响应动作,称为槽。
  • 槽为普通 C++ 函数,可定义在类的不同访问级别中,并能被关联到一个或多个信号上自动执行

信号和槽(Signals and Slots )是 Qt 框架的核心机制之一 ,用于实现对象之间的通信。它本质上是一种事件驱动的回调机制 ,但与传统的函数指针回调不同,它是类型安全的、面向对象的,并且可以在运行时动态连接。


🔍 一、信号和槽的本质

✅ 1. 事件驱动机制

  • 信号(Signal) :当某个特定事件发生时(如按钮被点击),对象会发出一个信号。
  • 槽(Slot) :槽是一个普通的成员函数,可以被信号触发调用。

你可以把“信号”看作是一个事件的通知者,“槽”是这个事件的响应者。


✅ 2. 观察者模式的实现

Qt 的信号和槽机制本质上是 观察者设计模式(Observer Pattern) 的一种实现:

  • 对象(发布者)维护一组监听器(订阅者)
  • 当状态改变时,通知所有监听者

✅ 3. 松耦合通信机制

  • 发送信号的对象不需要知道哪个对象接收该信号
  • 接收信号的对象也不需要知道是谁发送了这个信号
  • 只要信号和槽的签名匹配,就可以建立连接

这种机制实现了高度解耦的设计,非常适合 GUI 编程中多个组件之间复杂交互的需求。


🧠 二、信号和槽的底层原理

虽然我们使用 connect() 函数来连接信号和槽,但其背后是 Qt 的 元对象系统(Meta-Object System) 提供支持:

1. MOC(Meta-Object Compiler)

  • Qt 在编译前先通过 MOC 工具处理源代码
  • MOC 会扫描类中带有 Q_OBJECT 宏的类,生成额外的 C++ 代码
  • 这些代码包括:
    • 信号函数的存根(stub)
    • 元信息表(meta-object table)
    • 用于连接信号和槽的 qt_metacall() 函数等

2. 信号函数本质是空函数

你定义的信号函数只是一个声明(没有具体实现):

signals:void mySignal(int value);

MOC 会为这些信号生成一个空函数体,用于在 connect() 被调用时进行注册。

3. 连接机制

当你调用:

connect(sender, &Sender::signalName, receiver, &Receiver::slotName);

Qt 内部会:

  • 将信号和槽的信息记录到一个全局的连接列表中
  • 使用元对象系统进行参数类型检查
  • 在信号被发射时,查找所有连接的槽并执行

4. 跨线程通信

Qt 支持跨线程的信号和槽通信:

  • 默认使用 Qt::AutoConnection
  • 如果接收对象在另一个线程,则自动切换到目标线程执行(通过事件队列)

📌 三、信号和槽的特性总结

类型安全

信号和槽的参数必须匹配(或兼容)

多对多连接

一个信号可以连接多个槽;一个槽也可以连接多个信号

自动内存管理

当对象被删除时,Qt 会自动断开与其相关的连接

线程安全

支持跨线程通信(需正确设置连接类型)

松耦合

不依赖具体对象,只依赖接口(即函数签名)


🧪 四、示例代码:信号和槽的基本用法

// sender.h
class Sender : public QObject {Q_OBJECT
public:explicit Sender(QObject *parent = nullptr) : QObject(parent) {}signals:void dataReady(const QString& data); // 声明一个信号
};// receiver.h
class Receiver : public QObject {Q_OBJECT
public slots:void handleData(const QString& data) { // 槽函数qDebug() << "Received data:" << data;}
};// main.cpp
#include <QApplication>
#include "sender.h"
#include "receiver.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);Sender sender;Receiver receiver;// 连接信号和槽QObject::connect(&sender, &Sender::dataReady, &receiver, &Receiver::handleData);// 触发信号emit sender.dataReady("Hello, Qt!");return app.exec();
}

输出结果:

Received data: "Hello, Qt!"

五、注意事项

必须继承QObject

否则无法使用信号和槽

必须包含Q_OBJECT

否则 MOC 不会处理该类

不能在信号中传递非 Qt 元对象类型

如自定义结构体必须注册为QMetaType

避免循环连接

A.connect(B), B.connect(A),可能导致死循环

注意连接方式

Qt::DirectConnection,Qt::QueuedConnection等,影响线程行为


📘 六、扩展:Qt5 与 Qt6 的变化

从 Qt5 开始,引入了 基于函数指针的 connect 语法 (更安全、更易读):

connect(sender, &Sender::signalName, receiver, &Receiver::slotName);

Qt6 中进一步强化了类型安全性,废弃了一些旧式写法(如字符串方式),推荐使用新式语法。


✅ 总结:信号和槽的本质是什么?

核心机制

基于 Qt 的元对象系统(MOC)实现

设计模式

观察者模式

实现方式

由 MOC 自动生成代码,实现信号的注册与转发

作用

实现对象间通信,松耦合、类型安全

底层结构

使用全局连接表维护信号与槽的关系

特点

支持多对多连接、跨线程通信、自动内存管理

http://www.lryc.cn/news/576941.html

相关文章:

  • 数据结构复习4
  • stm32之测量周期
  • GPT,GPT-2,GPT-3 论文精读笔记
  • 各种常用的串口助手工具分享
  • vue-30(理解 Nuxt.js 目录结构)
  • Java 大视界 -- 基于 Java 的大数据分布式存储在科研大数据归档与长期保存中的应用(328)
  • TCP/UDP协议深度解析(三):TCP流量控制的魔法—滑动窗口、拥塞控制与ACK的智慧
  • 【AGI】Qwen VLo:多模态AI的范式重构与AGI演进关键里程碑
  • 数据可视化 - 单子图
  • LeetCode 第80题 删除有序数组中的重复项Ⅱ
  • 【如何实现分布式压测中间件】
  • Conda 环境配置之 -- Mamba安装(causal-conv1d、mamba_ssm 最简单配置方法)-- 不需要重新配置CDUA
  • MCPA2APPT 智能化演示文稿系统:A2A、MCP、ADK 三大架构全流程自动化
  • stm32之普通定时器
  • 左神算法之Zigzag方式打印矩阵
  • 飞云翻倍布林(翻倍密码系统四线布林版)双安全系统+均价趋势指标+日线周线MACD,组合操盘技术图文分享
  • H3C-路由器DHCPV6V4配置标准
  • 群晖nas安装moodle跳坑记录
  • 【更新至2024年】1996-2024年各省农村居民人均消费支出数据(无缺失)
  • 第十二节:Vben Admin 最新 v5.0 (vben5) 快速入门 - 两种权限控制方式(附前后端代码)
  • 对象的finalization机制Test
  • 智慧水务:未来城市水务管理的创新实践与科技飞跃
  • 【科技核心期刊推荐】《计算机与现代化》
  • 学习使用dotnet-dump工具分析.net内存转储文件(3)
  • Java 数据结构 泛型
  • ListExtension 扩展方法增加 转DataTable()方法
  • 常用指令合集(DOS/Linux/git/Maven等)
  • BP-Tools21.02下载 加解密利器 金融安全交易算法工具 PCI认证工具 金融和智能卡的数据加解密和数据转换工具
  • RabbitMQ中,basicAck、basicNack和basicReject是三种核心的消息确认机制
  • 左神算法之矩阵旋转90度