QT —— 信号和槽(带参数的信号和槽函数)

QT —— 信号和槽(带参数的信号和槽函数)

  • 带参的信号和槽函数
  • 信号参数个数和槽函数参数个数
      • 1. 参数匹配规则
      • 2. 实际代码示例
        • ✅ 合法连接(槽参数 ≤ 信号参数)
        • ❌ 非法连接(槽参数 > 信号参数)
      • 3. 特殊处理:使用 Lambda 适配参数
      • 4. 注意事项
      • 总结
  • 信号和槽函数多对多思想
  • disconnect
  • QT中使用lambda函数
      • Lambda 表达式基本结构
      • 1. 捕获列表 `[ ]`
      • 2. 参数列表 `( )`
      • 3. 函数体 `{ }`
      • 4. 返回值(可选)
      • 常见用法示例
        • (1) 按值捕获局部变量
        • (2) 按引用捕获并修改局部变量
        • (3) 捕获 `this` 访问成员变量
        • (4) 带参数的 Lambda
      • 注意事项
      • 总结

我们之前已经了解了QT当中的信号,并且已经了解了自定义信号和自定义槽函数应该怎样书写,如果还不了解的小伙伴可以点击这里:

https://blog.csdn.net/qq_67693066/article/details/147278172
https://blog.csdn.net/qq_67693066/article/details/147275998

我们今天来看一下带参的信号和槽函数应该是怎么样的:

带参的信号和槽函数

其实还是比较简单,在头文件声明,在cpp文件中实现就行了:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QString>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
//槽函数
public slots:void myaction_1(const QString&);//声明信号
signals:void mysignal_1(const QString&); //设置参数为QStringprivate:Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 连接 Widget 的自定义信号到槽函数connect(this, &Widget::mysignal_1, this, &Widget::myaction_1);//发射信号emit Widget::mysignal_1("this this my text"); //传递了参数
}//实现槽函数
void Widget::myaction_1(const QString& text)
{qDebug() << text;
}Widget::~Widget()
{delete ui;
}

在这里插入图片描述

信号参数个数和槽函数参数个数

在 Qt 的信号和槽机制中,槽函数的参数个数可以少于或等于信号的参数个数,但不能多于信号的参数个数。这是 Qt 信号和槽连接的重要规则之一。


1. 参数匹配规则

情况信号参数槽函数参数是否合法说明
1void signal()void slot()✅ 合法无参数,完全匹配
2void signal(int)void slot(int)✅ 合法参数类型和数量完全匹配
3void signal(int, QString)void slot(int)✅ 合法槽可以忽略后面的参数
4void signal(int)void slot(int, QString)❌ 不合法槽的参数不能多于信号
5void signal(int)void slot(QString)❌ 不合法参数类型必须兼容
6void signal(int)void slot()✅ 合法槽可以完全不接收参数

2. 实际代码示例

✅ 合法连接(槽参数 ≤ 信号参数)
// 信号:带两个参数
signals:void dataReady(int value, const QString &message);// 槽1:完全匹配(两个参数)
public slots:void handleData(int value, const QString &msg) {qDebug() << "Value:" << value << "Message:" << msg;}// 槽2:只接收第一个参数(忽略第二个)void handleValueOnly(int value) {qDebug() << "Value:" << value;}// 槽3:无参数void handleNoArgs() {qDebug() << "Data received!";}// 连接方式(Qt5 风格)
connect(this, &MyClass::dataReady, this, &MyClass::handleData);      // 完全匹配
connect(this, &MyClass::dataReady, this, &MyClass::handleValueOnly); // 忽略第二个参数
connect(this, &MyClass::dataReady, this, &MyClass::handleNoArgs);    // 无参数
❌ 非法连接(槽参数 > 信号参数)
// 槽4:尝试接收三个参数(但信号只有两个)
public slots:void handleInvalid(int a, const QString &b, bool c) {  // 编译报错!qDebug() << a << b << c;}// 错误连接
connect(this, &MyClass::dataReady, this, &MyClass::handleInvalid);  // 编译失败

3. 特殊处理:使用 Lambda 适配参数

如果信号和槽的参数不匹配,可以通过 Lambda 表达式 转换参数:

connect(this, &MyClass::dataReady, this, [this](int v, const QString &m) {mySlot(v, m, true);  // 手动添加额外参数
});// 槽函数(三个参数)
void mySlot(int v, const QString &m, bool extra) {qDebug() << v << m << extra;
}

4. 注意事项

  1. 参数类型必须兼容

    • 如果信号是 int,槽可以是 intdouble(隐式转换),但不能是 QString
    • 例如:
      signals: void valueChanged(int);
      slots: void logValue(double);  // ✅ OK(int → double)
      slots: void logValue(QString); // ❌ 错误(类型不匹配)
      
  2. 默认参数的影响

    • 如果槽有默认参数,实际调用时未传递的参数会使用默认值:
      slots: void showMessage(const QString &msg, bool bold = false);
      // 可以连接单参数信号:
      signals: void messageSent(const QString &);
      
  3. 旧式 Qt4 语法的限制

    • 使用 SIGNALSLOT 宏时,参数类型必须严格匹配(不支持隐式转换):
      connect(btn, SIGNAL(clicked(bool)), this, SLOT(showMessage(QString)));  // ❌ 错误
      

总结

  • 槽的参数个数 ≤ 信号的参数个数,且类型必须兼容。
  • 多余参数可忽略,但缺少参数或类型不匹配会导致编译/运行时错误。
  • 使用 Lambda 表达式可以灵活适配参数不匹配的情况。

如果有更复杂的需求(如动态修改参数),可能需要结合 QSignalMapper 或手动管理信号转发。

信号和槽函数多对多思想

QT中的槽函数其实在设计的时候就是一个比较独特的东西,它可以像MySQL那样,实现多对多(一个信号可以绑定多个槽函数,一个槽函数也可以被多个信号绑定)

我们可以再加一个信号:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QString>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
//槽函数
public slots:void myaction_1(const QString&);//声明信号
signals:void mysignal_1(const QString&); //设置参数为QStringvoid mysignal_2(const QString&); //再设置一个信号private:Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 连接 Widget 的自定义信号到槽函数connect(this, &Widget::mysignal_1, this, &Widget::myaction_1);connect(this, &Widget::mysignal_2, this, &Widget::myaction_1);//发射信号emit Widget::mysignal_1("this this my text");emit Widget::mysignal_2("this this my text2");
}//实现槽函数
void Widget::myaction_1(const QString& text)
{qDebug() << text;
}Widget::~Widget()
{delete ui;
}

在这里插入图片描述
其实这种设计放到现在会有点冗余,因为现在一对一的关系可以完全满足要求了。但不过QT诞生的时代还没有足够的开发经验以供参考,所以做出这样的设计情有可原。

disconnect

disconnect顾名思义就是断开连接:

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 连接 Widget 的自定义信号到槽函数connect(this, &Widget::mysignal_1, this, &Widget::myaction_1);disconnect(this, &Widget::mysignal_1, this, &Widget::myaction_1); //断开连接connect(this, &Widget::mysignal_2, this, &Widget::myaction_1);//发射信号emit Widget::mysignal_1("this this my text");emit Widget::mysignal_2("this this my text2");
}//实现槽函数
void Widget::myaction_1(const QString& text)
{qDebug() << text;
}Widget::~Widget()
{delete ui;
}

在这里插入图片描述

QT中使用lambda函数

我们使用connect的时候,最后一个参数其实我们是连接的一个函数,lambda是匿名函数,可以符合我们connect函数的参数要求:

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* newbutton = new QPushButton(this);connect(newbutton,&QPushButton::clicked,this,[=](){newbutton->setFixedSize(400,400);newbutton->setText("这是newbutton的文本");this->setWindowTitle("哈哈哈,我的标题已经改了");});
}//实现槽函数
void Widget::myaction_1(const QString& text)
{qDebug() << text;
}Widget::~Widget()
{delete ui;
}

在这里插入图片描述
在 Qt 的 connect 中使用 Lambda 表达式 可以方便地编写自定义槽函数,特别是在需要捕获局部变量或执行多行代码时。以下是代码片段及其 Lambda 表达式的详细解析:


Lambda 表达式基本结构

[ captures ] ( parameters ) -> return_type { body }

在你的代码中:

[=]() {newbutton->setFixedSize(400, 400);newbutton->setText("这是newbutton的文本");this->setWindowTitle("哈哈哈,我的标题已经改了");
}

对应部分:

  • [=]:捕获列表(Captures)
  • ():参数列表(Parameters,此处为空)
  • {}:函数体(Body)

1. 捕获列表 [ ]

定义 Lambda 如何访问外部变量:

捕获方式说明
[=]按值捕获(隐式捕获所有外部变量,副本)
[&]按引用捕获(直接修改外部变量)
[this]捕获当前类的 this 指针(可访问成员变量/函数)
[a, &b]混合捕获:a 按值,b 按引用
[]不捕获任何外部变量

代码分析
[=] 表示所有外部变量(如 newbuttonthis)按值捕获(实际由于它们是指针,仍能修改指向的对象)。


2. 参数列表 ( )

定义 Lambda 的输入参数(类似于普通函数的参数):

  • 如果连接的是无参数的信号(如 clicked()),参数列表可以为空 ()
  • 如果信号有参数(如 clicked(bool checked)),则需要声明参数:
    connect(button, &QPushButton::clicked, this, [=](bool checked) {qDebug() << "按钮状态:" << checked;
    });
    

你的代码分析
clicked() 信号无参数,所以 () 为空。


3. 函数体 { }

Lambda 的具体实现逻辑(可以包含多行代码)。
代码分析
在函数体中修改了按钮大小、文本和窗口标题:

{newbutton->setFixedSize(400, 400);      // 设置按钮大小newbutton->setText("这是newbutton的文本"); // 修改按钮文本this->setWindowTitle("哈哈哈,我的标题已经改了"); // 修改窗口标题
}

4. 返回值(可选)

如果 Lambda 有返回值,需通过 -> return_type 指定(你的例子中无返回值,可省略)。


常见用法示例

(1) 按值捕获局部变量
int count = 0;
connect(button, &QPushButton::clicked, this, [=]() {qDebug() << "当前计数:" << count; // 捕获的是 count 的副本
});
(2) 按引用捕获并修改局部变量
int count = 0;
connect(button, &QPushButton::clicked, this, [&]() {count++; // 直接修改外部变量qDebug() << "计数:" << count;
});
(3) 捕获 this 访问成员变量
class Widget : public QWidget {QString m_message = "Hello";
public:void setupButton() {connect(button, &QPushButton::clicked, this, [this]() {qDebug() << m_message; // 直接访问成员变量});}
};
(4) 带参数的 Lambda
connect(button, &QPushButton::toggled, this, [=](bool checked) {button->setText(checked ? "ON" : "OFF");
});

注意事项

  1. 生命周期问题

    • 按引用捕获([&])时,需确保外部变量在 Lambda 执行时仍然有效(避免悬空引用)。
    • 按值捕获([=])更安全,但可能增加拷贝开销。
  2. 默认捕获 [=][&] 的风险

    • 过度使用可能导致意外捕获不需要的变量(推荐显式指定捕获的变量,如 [this, button])。
  3. Qt 信号槽与 Lambda

    • Lambda 中可以直接调用类的成员函数(通过 [this] 捕获)。
    • 如果 Lambda 作为槽函数,确保其内部操作是线程安全的(跨线程时需小心)。

总结

  • [=]:安全捕获外部变量(副本),适合多数场景。
  • ():根据信号参数决定是否声明参数。
  • {}:实现自定义逻辑,支持多行代码。
  • 最佳实践:显式列出需要捕获的变量(如 [this, newbutton]),避免隐式捕获带来的混淆。

通过 Lambda 表达式,你可以灵活地替代传统槽函数,尤其在需要快速响应信号并操作局部变量时非常方便。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/78759.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式简述(十七)备忘录模式

备忘录模式 描述组件使用 描述 备忘录模式用于将对象的状态进行保存为备忘录&#xff0c;以便在需要时可以从备忘录会对象状态&#xff1b;其核心点在于备忘录对象及其管理者是独立于原有对象之外的。 常用于需要回退、撤销功能的场景。 组件 原有对象&#xff08;包含自身…

标签语句分析

return userList.stream().filter(user -> {String tagsStr user.getTags(); 使用 Stream API 来过滤 userList 中的用户 解析 tagsStr 并根据标签进行过滤 假设 tagsStr 是一个 JSON 格式的字符串&#xff0c;存储了一个标签集合。你希望过滤出包含所有指定标签的用户。…

【应用密码学】实验四 公钥密码1——数学基础

一、实验要求与目的 学习快速模幂运算、扩展欧几里得、中国剩余定理的算法思想以及代码实现。 二、实验内容与步骤记录&#xff08;只记录关键步骤与结果&#xff0c;可截图&#xff0c;但注意排版与图片大小&#xff09; 1.快速模幂运算的设计思路 快速模幂运算的核心思想…

WebSocket与Socket、TCP、HTTP的关系及区别

1.什么是WebSocket及原理 WebSocket是HTML5中新协议、新API。 WebSocket从满足基于Web的日益增长的实时通信需求应运而生&#xff0c;解决了客户端发起多个Http请求到服务器资源浏览器必须要在经过长时间的轮询问题&#xff0c;实现里多路复用&#xff0c;是全双工、双向、单套…

基于C++的IOT网关和平台4:github项目ctGateway交互协议

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。 源码指引:github源码指引_初级代码游戏的博客-CSDN博客 系…

【PPT制作利器】DeepSeek + Kimi生成一个初始的PPT文件

如何基于DeepSeek Kimi进行PPT制作 步骤&#xff1a; Step1&#xff1a;基于DeepSeek生成文本&#xff0c;提问 Step2基于生成的文本&#xff0c;用Kimi中PPT助手一键生成PPT 进行PPT渲染-自动渲染 可选择更改模版 生成PPT在桌面 介绍的比较详细&#xff0c;就是这个PPT模版…

拷贝多个Excel单元格区域为图片并粘贴到Word

Excel工作表Sheet1中有两个报表&#xff0c;相应单元格区域分别定义名称为Report1和Report2&#xff0c;如下图所示。 现在需要将图片拷贝图片粘贴到新建的Word文档中。 示例代码如下。 Sub Demo()Dim oWordApp As ObjectDim ws As Worksheet: Set ws ThisWorkbook.Sheets(&…

Spring是如何传播事务的?什么是事务传播行为

Spring是如何传播事务的&#xff1f; Spring框架通过声明式事务管理来传播事务&#xff0c;主要依赖于AOP&#xff08;面向切面编程&#xff09;和事务拦截器来实现。Spring的事务传播机制是基于Java Transaction API (JTA) 或者本地资源管理器&#xff08;如Hibernate、JDBC等…

Python-pandas-操作Excel文件(读取数据/写入数据)及Excel表格列名操作详细分享

Python-pandas-操作Excel文件(读取数据/写入数据) 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是pandas的使用语法。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系列文章】&#xff1a;每…

PHP分页显示数据,在phpMyadmin中添加数据

<?php $conmysqli_connect(localhost,root,,stu); mysqli_query($con,"set names utf8"); //设置字符集为utf8 $sql"select * from teacher"; $resultmysqli_query($con,$sql); $countmysqli_num_rows($result); //记录总条数$count。 $pagesize10;//每…

智能参谋部系统架构和业务场景功能实现

将以一个基于微服务和云原生理念、深度集成人工智能组件、强调实时性与韧性的系统架构为基础,详细阐述如何落地“智能参谋部”的各项能力。这不是一个简单的软件堆叠,而是一个有机整合了数据、知识、模型、流程与人员的复杂体系。 系统愿景:“智能参谋部”——基于AI赋能的…

企业级RAG架构设计:从FAISS索引到HyDE优化的全链路拆解,金融/医疗领域RAG落地案例与避坑指南(附架构图)

本文较长&#xff0c;纯干货&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习内容&#xff0c;尽在聚客AI学院。 一. RAG技术概述 1.1 什么是RAG&#xff1f; RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09; 是…

Spring Boot Validation实战详解:从入门到自定义规则

目录 一、Spring Boot Validation简介 1.1 什么是spring-boot-starter-validation&#xff1f; 1.2 核心优势 二、快速集成与配置 2.1 添加依赖 2.2 基础配置 三、核心注解详解 3.1 常用校验注解 3.2 嵌套对象校验 四、实战开发步骤 4.1 DTO类定义校验规则 4.2 Cont…

理清缓存穿透、缓存击穿、缓存雪崩、缓存不一致的本质与解决方案

在构建高性能系统中&#xff0c;缓存&#xff08;如Redis&#xff09; 是不可或缺的关键组件&#xff0c;它大幅减轻了数据库压力、加快了响应速度。然而&#xff0c;在高并发环境下&#xff0c;缓存也可能带来一系列棘手的问题&#xff0c;如&#xff1a;缓存穿透、缓存击穿、…

PyTorch_构建线性回归

使用 PyTorch 的 API 来手动构建一个线性回归的假设函数&#xff0c;数据加载器&#xff0c;损失函数&#xff0c;优化方法&#xff0c;绘制训练过程中的损失变化。 数据构建 import torch from sklearn.datasets import make_regression import matplotlib.pyplot as plt i…

005-nlohmann/json 基础方法-C++开源库108杰

《二、基础方法》&#xff1a;节点访问、值获取、显式 vs 隐式、异常处理、迭代器、类型检测、异常处理……一节课搞定C处理JSON数据85%的需求…… JSON 字段的简单类型包括&#xff1a;number、boolean、string 和 null&#xff08;即空值&#xff09;&#xff1b;复杂类型则有…

HarmonyOS 5.0 分布式数据协同与跨设备同步​​

大家好&#xff0c;我是 V 哥。 使用 Mate 70有一段时间了&#xff0c;系统的丝滑使用起来那是爽得不要不要的&#xff0c;随着越来越多的应用适配&#xff0c;目前使用起来已经和4.3的兼容版本功能差异无碍了&#xff0c;还有些纯血鸿蒙独特的能力很是好用&#xff0c;比如&am…

Linux云计算训练营笔记day02(Linux、计算机网络、进制)

Linux 是一个操作系统 Linux版本 RedHat Rocky Linux CentOS7 Linux Ubuntu Linux Debian Linux Deepin Linux 登录用户 管理员 root a 普通用户 nsd a 打开终端 放大: ctrl shift 缩小: ctrl - 命令行提示符 [rootlocalhost ~]# ~ 家目录 /root 当前登录的用户…

macOS 安装了Docker Desktop版终端docker 命令没办法使用

macOS 安装了Docker Desktop版终端docker 命令没办法使用 1、检查Docker Desktop能否正常运行。 确保Docker Desktop能正常运行。 2、检查环境变量是否添加 1、添加环境变量 如果环境变量中没有包含Docker的路径&#xff0c;你可以手动添加。首先&#xff0c;找到Docker的…

Gradio全解20——Streaming:流式传输的多媒体应用(5)——基于WebRTC的摄像头实时目标检测

Gradio全解20——Streaming&#xff1a;流式传输的多媒体应用&#xff08;5&#xff09;——基于WebRTC的摄像头实时目标检测 本篇摘要20. Streaming&#xff1a;流式传输的多媒体应用20.5 基于WebRTC的摄像头实时目标检测20.5.1 环境配置及说明1. WebRTC2. TURN服务器 20.5.2 …