当前位置: 首页 > 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.lqws.cn/news/572149.html

相关文章:

  • 深入学习 GORM:记录插入与数据检索
  • MySQL技巧
  • 【ad-hoc】# P12414 「YLLOI-R1-T3」一路向北|普及+
  • Requests源码分析:面试考察角度梳理
  • MySQL 架构
  • 理解 Confluent Schema Registry:Kafka 生态中的结构化数据守护者
  • 第10.4篇 使用预训练的目标检测网络
  • 学习使用Visual Studio分析.net内存转储文件的基本用法
  • C# 委托(调用带引用参数的委托)
  • 计算机组成原理与体系结构-实验四 微程序控制器 (Proteus 8.15)
  • 【硬核数学】3. AI如何应对不确定性?概率论为模型注入“灵魂”《从零构建机器学习、深度学习到LLM的数学认知》
  • 【HuggingFace】模型下载至本地访问
  • SpringMVC实战:从配置到JSON处理全解析
  • 开源免费计划工具:帮你高效规划每一天
  • UE5 Grid3D 学习笔记
  • 什么是IPFS(InterPlanetary File System,星际文件系统)
  • c# 在sql server 数据库中批插入数据
  • C++ 格式化输入输出
  • 「Java案例」输出24个希腊字母
  • 计算机组成原理与体系结构-实验一 进位加法器(Proteus 8.15)
  • Linux下的调试器-gdb(16)
  • 信息安全与网络安全---引言
  • 矩阵的定义和运算 线性代数
  • 设计模式 | 组合模式
  • VMware设置虚拟机为固定IP
  • Transformer结构与代码实现详解
  • redisson看门狗实现原理
  • Linux基本命令篇 —— head命令
  • 【锁相环系列5】再谈数字锁相环
  • python sklearn 机器学习(1)