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

信号与槽的总结

信号与槽的总结

QT中的信号与Linux的信号对比

1)信号源

2)信号的类型

3)信号的处理方式

QT信号与Linux信号的深度对比分析

一、信号源对比

QT信号

  • 用户定义信号

    :由开发者通过

    signals:
    

    关键字在QObject派生类中显式声明

    class MyObject : public QObject {Q_OBJECT
    signals:void mySignal(int param);
    };
    
  • 框架内置信号:QT框架提供的信号(如QPushButton的clicked())

  • 信号触发方式

    :通过

    emit
    

    关键字显式触发

    emit mySignal(42);
    

Linux系统信号

  • 系统预定义信号:由操作系统内核预先定义(如SIGINT、SIGSEGV等)

  • 硬件产生信号:如SIGSEGV(内存访问错误)、SIGFPE(算术异常)

  • 进程间信号

    :通过kill()系统调用发送

    kill(pid, SIGTERM);
    

二、信号类型对比

QT信号类型特征

特性说明
类型安全编译时检查参数类型匹配
带参数可携带任意数量、类型的参数
面向对象必须属于某个QObject派生类
同步/异步默认队列连接(异步),可设置为直接连接(同步)

Linux信号类型特征

特性说明
固定编号标准信号编号1-31,实时信号34-64
无参数仅信号编号,不能携带额外数据
进程级别与特定线程/进程关联,非面向对象
同步触发信号处理函数在信号产生时立即执行

常见Linux信号示例:

SIGINT (2):终端中断信号(Ctrl+C)

SIGKILL (9):强制终止信号

SIGSEGV (11):无效内存访问

SIGTERM (15):终止请求信号

三、处理方式对比

QT信号处理(信号-槽机制)

// 连接方式
QObject::connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);// 槽函数声明
public slots:void updateValue(int newValue);**处理特点**:
  1. 多线程安全:自动跨线程事件队列传递
  2. 连接类型:
    • 直接连接(同步执行)
    • 队列连接(异步,接收者线程事件循环处理)
    • 自动连接(默认,根据线程关系自动选择)
  3. 内存管理:自动处理对象生命周期(可使用Qt::UniqueConnection)

Linux信号处理

// 信号处理函数注册
struct sigaction sa;
sa.sa_handler = handler;
sigaction(SIGINT, &sa, NULL);void handler(int sig) {// 信号处理逻辑
}

处理特点

  1. 同步执行:中断当前执行流立即处理
  2. 限制严格:
    • 信号处理函数中只能调用异步信号安全函数
    • 不能使用malloc等非可重入函数
  3. 特殊处理:
    • SIGKILL和SIGSTOP不能被捕获或忽略
    • 某些信号会导致核心转储(如SIGSEGV)

四、关键差异总结

对比维度QT信号Linux信号
抽象级别高层次面向对象机制低层次操作系统机制
参数传递支持复杂参数传递仅信号编号,无参数
线程处理自动处理跨线程通信需要显式处理线程掩码
可靠性可靠,不会丢失非实时信号可能丢失
处理时机通过事件循环异步处理立即中断当前执行流
调试支持可通过QtCreator调试需要gdb等系统级调试工具

五、实际应用场景

QT信号典型用例

  1. GUI事件处理(按钮点击、窗口关闭)
  2. 跨线程通信(工作线程到主线程通知)
  3. 模块间解耦(观察者模式实现)

Linux信号典型用例

  1. 进程控制(优雅终止服务进程)
  2. 异常处理(内存错误、算术异常捕获)
  3. 进程间简单通知(无需复杂数据传递)

六、高级主题

QT信号的高级特性

  1. Lambda表达式连接:

    connect(button, &QPushButton::clicked, [=](){qDebug() << "Button clicked";
    });
    
  2. 信号转发:

    connect(obj1, &ClassA::signalA, obj2, &ClassB::signalB);
    
  3. 信号连接管理disconnect()断开连接

Linux信号的进阶处理

  1. 信号屏蔽:

    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    pthread_sigmask(SIG_BLOCK, &set, NULL);
    
  2. 实时信号处理:

    union sigval value;
    value.sival_int = 42;
    sigqueue(pid, SIGRTMIN, value); // 可携带少量数据
    
  3. 替代方案:更复杂的进程通信建议使用socket、管道等机制

信号槽中connect函数的使用

connect (const QObject *sender, const char * signal ,const QObject * receiver , const char * method , Qt::ConnectionType type = Qt::AutoConnection )

参数说明:

• sender:信号的发送者;

• signal:发送的信号(信号函数);

• receiver:信号的接收者;

• method:接收信号的槽函数;

• type: ⽤于指定关联⽅式,默认的关联⽅式为 Qt::AutoConnection,通常不需要⼿动设定。

在控件的问题上我们需要查阅的问题

内置了哪些信号,信号是何时触发的

内置了哪些槽,槽的作用是什么

一、常见控件的内置信号

  1. 按钮类控件(QPushButton等)

主要内置信号

  • clicked():按钮被鼠标点击或键盘激活时触发
  • pressed():按钮被按下时立即触发
  • released():按钮被释放时触发
  • toggled(bool checked):可切换按钮状态改变时触发
// 示例:连接按钮点击信号
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
  1. 文本输入类控件(QLineEdit, QTextEdit)

主要内置信号

  • textChanged(const QString &text):文本内容改变时触发
  • textEdited(const QString &text):用户编辑文本时触发
  • returnPressed():按下回车键时触发
  • editingFinished():编辑完成(失去焦点)时触发
// 示例:实时响应文本变化
connect(ui->lineEdit, &QLineEdit::textChanged,[this](const QString &text){qDebug() << "Current text:" << text;});
  1. 选择类控件(QComboBox, QCheckBox, QRadioButton)

主要内置信号

  • currentIndexChanged(int index):当前选项改变时触发
  • currentTextChanged(const QString &text):当前文本改变时触发
  • stateChanged(int state):复选框/单选按钮状态改变时触发
// 示例:响应下拉框选择变化
connect(ui->comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),[](int index){qDebug() << "Selected index:" << index;});

二、信号触发时机详解

  1. 用户交互触发
  • 鼠标事件:点击、双击、悬停等
  • 键盘事件:按键按下、释放、输入等
  • 触摸事件:触摸屏交互
  1. 状态变化触发
  • 值改变:如滑块位置、进度条值等
  • 焦点变化:控件获得/失去焦点
  • 可见性变化:显示/隐藏状态改变
  1. 系统事件触发
  • 定时器超时:QTimer的timeout()信号
  • 网络响应:QNetworkReply的finished()信号
  • 文件系统变化:QFileSystemWatcher的fileChanged()信号

三、常见控件的内置槽函数

  1. 基础功能槽
槽函数作用适用控件
setText(const QString &)设置控件文本QLabel, QLineEdit等
clear()清空内容QLineEdit, QTextEdit等
setEnabled(bool)启用/禁用控件所有QWidget派生类
show()/hide()显示/隐藏控件所有QWidget派生类
// 示例:使用内置槽
connect(ui->actionClear, &QAction::triggered,ui->textEdit, &QTextEdit::clear);
  1. 状态控制槽
槽函数作用适用控件
setChecked(bool)设置选中状态QCheckBox, QRadioButton
setCurrentIndex(int)设置当前选项QComboBox, QTabWidget
setValue(int)设置数值QProgressBar, QSlider
// 示例:控制进度条
connect(ui->startButton, &QPushButton::clicked,[this](){ui->progressBar->setValue(0);});

四、槽函数的作用与分类

  1. 数据操作槽
  • 数据获取:如text()value()
  • 数据设置:如setText()setValue()
  • 数据清除:如clear()reset()
  1. 状态控制槽
  • 启用/禁用控制setEnabled()setDisabled()
  • 可见性控制show()hide()setVisible()
  • 状态切换setChecked()toggle()
  1. 视图操作槽
  • 滚动控制scrollToTop()scrollToBottom()
  • 缩放控制zoomIn()zoomOut()
  • 选择控制selectAll()deselect()

五、信号与槽的高级应用

  1. 自动连接命名槽

QT支持特定命名格式的槽函数自动连接:

// 声明
private slots:void on_pushButton_clicked();// 实现
void MainWindow::on_pushButton_clicked() {// 无需显式connect,自动关联名为"pushButton"的按钮点击信号
}
  1. 信号与槽的连接类型
// 五种连接类型
Qt::AutoConnection      // 自动选择(默认)
Qt::DirectConnection    // 同步直接调用
Qt::QueuedConnection    // 异步队列调用
Qt::BlockingQueuedConnection // 阻塞式队列调用
Qt::UniqueConnection    // 唯一连接(防止重复连接)
  1. Lambda表达式作为槽
connect(ui->pushButton, &QPushButton::clicked, [this](){// 可以直接访问类成员ui->label->setText("Button clicked at " + QTime::currentTime().toString());
});

六、最佳实践建议

  1. 信号-槽连接规范
    • 优先使用新式语法(&Sender::signal形式)
    • 避免在构造函数中连接尚未完全初始化的对象
  2. 资源管理
    • 使用QPointer管理可能被删除的对象
    • 及时断开不再需要的连接(disconnect)
  3. 线程安全
    • 跨线程连接使用QueuedConnection
    • 避免在不同线程间直接操作GUI控件
  4. 性能优化
    • 高频信号考虑节流(throttling)或防抖(debouncing)
    • 大量连接时考虑使用QSignalMapper或lambda统一处理

自定义槽函数

本质:自定义的一个普通的成员函数

可以让QTCreator自动生成

自定义信号

本质:成员函数

函数的定义是QT自己生成的,作为程序员只需要写函数声明即可

signals:自定义信号的关键字

emit:完成信号的发射(emit可以省略)

信号和槽也可以带参数

发射信号的时候,把参数传给对应的参数

信号的参数和槽的参数一致

1)类型匹配

2)个数,信号的参数要多于槽的参数

信号槽存在的意义:解耦合

代码要达到的要求:高内聚,低耦合

具体含义为:对程序影响很小,写代码的时候,某个代码的功能被集中在一起

disconnect的使用方式:类似于connect

lambda表达式简化槽函数的定义

http://www.xdnf.cn/news/14818.html

相关文章:

  • Linux内核深度解析:IPv4策略路由的核心实现与fib_rules.c源码剖析
  • bean注入的过程中,Property of ‘java.util.ArrayList‘ type cannot be injected by ‘List‘
  • 从“电话催维修“到“手机看进度“——售后服务系统开发如何重构客户体验
  • 历史数据分析——中证医药
  • 《数据维度的视觉重构:打造交互式高维数据可视化的黄金法则》
  • 如何解决Spring Boot中@Valid对List校验失效问题
  • Python小工具之PDF合并
  • Linux应用基础
  • [netty5: HttpObjectEncoder HttpObjectDecoder]-源码解析
  • 传输层 udptcp
  • 【力扣 简单 C】746. 使用最小花费爬楼梯
  • 国产 OFD 标准公文软件数科 OFD 阅读器:OFD/PDF 双格式支持,公务办公必备
  • LongT5: 针对长序列的高效文本到文本Transformer
  • Linux NFS终极指南:安装、配置与性能优化
  • 【解决“此扩展可能损坏”】Edge浏览器(chrome系列通杀))扩展损坏?一招保留数据快速修复
  • 【无标题】Go语言中的反射机制 — 元编程技巧与注意事项
  • 简单 Python 爬虫程序设计
  • Vue3-组件化-Vue核心思想之一
  • 物联网数据安全区块链服务
  • 遗传算法的原理与实现示例
  • Android开发前的准备工作
  • 批量PDF转换工具,一键转换Word Excel
  • 考研408《计算机组成原理》复习笔记,第三章(3)——多模块存储器
  • 10分钟搭建 PHP 开发环境教程
  • 基于 ETL 工具实现人大金仓数据库的数据迁移与整合实操指南
  • Go中使用Google Authenticator
  • OpenSSL 内存泄漏修复全景:119 个历史 Commit 的类型分析与防御启示
  • uniapp 微信小程序水印
  • bug记录::= 给全局变量赋值导致出现panic
  • Python大模型应用开发实践 - 初探