信号与槽的总结

信号与槽的总结

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函数的使用

C++ 复制代码
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 // 唯一连接(防止重复连接)

  2. 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表达式简化槽函数的定义

相关推荐
念九_ysl3 分钟前
Java 使用 OpenHTMLToPDF + Batik 将含 SVG 遮罩的 HTML 转为 PDF 的完整实践
java·开发语言·pdf
yaoxin52112313 分钟前
124. Java 泛型 - 有界类型参数
java·开发语言
Spirit_NKlaus15 分钟前
解决HttpServletRequest无法获取@RequestBody修饰的参数
java·spring boot·spring
不死的精灵22 分钟前
【Java21】在spring boot中使用ScopedValue
java·spring boot·后端
liulilittle33 分钟前
深度剖析:OPENPPP2 libtcpip 实现原理与架构设计
开发语言·网络·c++·tcp/ip·智能路由器·tcp·通信
88号技师39 分钟前
2025年6月一区-田忌赛马优化算法Tianji’s horse racing optimization-附Matlab免费代码
开发语言·算法·matlab·优化算法
勤奋的知更鸟1 小时前
Java 编程之模板方法模式
java·开发语言·模板方法模式
逸风尊者1 小时前
开发易掌握的知识:GeoHash查找附近空闲车辆
java·后端
十年编程老舅1 小时前
跨越十年的C++演进:C++20新特性全解析
c++·c++11·c++20·c++14·c++23·c++17·c++新特性
骑着王八撵玉兔1 小时前
【性能优化与架构调优(二)】高性能数据库设计与优化
数据库·性能优化·架构