[Qt的学习日常]--信号和槽

前言

作者:小蜗牛向前冲

名言:我可以接受失败,但我不能接受放弃

  如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正

本期学习:什么是信号和槽,自定义槽函数和信号函数,信号和槽的传参,断开,对lambda表达式的使用

目录

一、信号和槽

1、信号和槽的理解

2、信号的本质 

3、槽的本质

二、信号和槽的使用 

1、 connect()函数

2、自定义槽函数二种实现方法

3、自定义信号

4、信号和槽的带参传递 

三、 信号和槽的其他说明

1、信号与槽的断开

2、使⽤ Lambda 表达式定义槽函数

3、信号与槽的优缺点


一、信号和槽

1、信号和槽的理解

在Qt中用户和控件的每一次交互都称为一个事件,⽐如 "⽤户点击按钮" 是⼀个事件,"⽤户关闭窗⼝" 也是⼀个事件。每个事件都回发送一个信号,当用户点击按钮,就会发送按钮被点击的信号。

Qt中所有的控件都具备接收信号的能力,一个控件可以接受多种信号,对每种信号都会做出相应的响应动作。例如,按钮所在的窗⼝接收到 "按钮被点击" 的信号后,会做 出 "关闭⾃⼰" 的响应动作;在Qt中,对信号做出响应动作就称为槽。

信号和槽是 Qt 特有的消息传输机制,它能将相互独⽴的控件关联起来。⽐如,"按钮" 和 "窗⼝" 本⾝是两个独⽴的控件,点击 "按钮" 并不会对 "窗⼝" 造成任何影响。通过信号和槽机制,可以将 "按 钮" 和 "窗⼝" 关联起来,实现 "点击按钮会使窗⼝关闭" 的效果。

2、信号的本质 

信号的本质就是事件。

如:按钮单击、双击 • 窗⼝刷新 • ⿏标移动、⿏标按下、⿏标释放 • 键盘输⼊

 信号的呈现形式就是函数, 也就是说某个事件产⽣了, Qt 框架就会调⽤某个对应的信号函数, 通 知使⽤者。

3、槽的本质

槽(Slot)就是对信号响应的函数。槽就是⼀个函数,与⼀般的 C++ 函数是⼀样的,可以定义在 类的任何位置( public、protected 或 private ),可以具有任何参数,可以被重载,也可以被直接调 ⽤(但是不能有默认参数)。槽函数与⼀般的函数不同的是:槽函数可以与⼀个信号关联,当信号被 发射时,关联的槽函数被⾃动执⾏

注意:

(1)信号和槽机制底层是通过函数间的相互

调⽤实现的每个信号都可以⽤函数来表⽰,称为信号函数;每个槽也可以⽤函数表⽰,称为槽函数

例如: "按钮被按下" 这个信号可以⽤ clicked() 函数表 ⽰,"窗⼝关闭" 这个槽可以⽤ close() 函数表⽰,假如使⽤信号和槽机制实现:"点击按钮会关闭窗⼝" 的功能,其实就是 clicked() 函数调⽤ close() 函数的效果。

(2)信号函数和槽函数通常位于某个类中,和普通的成员函数相⽐,它们的特别之处在于:

  • 信号函数⽤ signals 关键字修饰,槽函数⽤ public slots、protected slots 或者 private slots 修 饰。signals 和 slots 是 Qt 在 C++ 的基础上扩展的关键字,专⻔⽤来指明信号函数和槽函数;
  •  信号函数只需要声明,不需要定义(实现),⽽槽函数需要定义(实现)。

二、信号和槽的使用 

1、 connect()函数

在 Qt 中,QObject 类提供了⼀个静态成员函数 connect() ,该函数专⻔⽤来关联指定的信号函数和槽函数。

connect() 函数原型:

​
connect(const QObject* sender,//信号的发送者(哪个控件)
        const char* signal,//发送信息的函数
        const QObject* receiver,//信号的接受者
        const char* method,//接受信号的槽函数
        Qt::ConnectionType type = Qt::AutoConnection);
//type: ⽤于指定关联⽅式,默认的关联⽅式为 Qt::AutoConnection,通常不需要⼿动设定。

代码⽰例: 在窗⼝中设置⼀个按钮,当点击 "按钮" 时关闭 "窗⼝" .:

大家看到这里可能会有疑惑,为什么我们传递的参数类型没有疑惑是对的, 我们明明是要给第一个参数(信号的发送者)传给QObject类的,怎么就变成了传QPushButton类呢?

这是因为在QT中QObject是所有类继承的基类,通过层层的继承关系,QPushButton也继承了QObject,根据继承关系这里也可以相当与QObject使用,这里我们理解了参数1和参数3.

那为什么参数2和参数4明明传递的是一个函数指针,怎么能和char*类型的指针匹配。

其实最初的Qt为了能给信号参数和槽参数传递参数,是要给这二个参数搭配二个厷

SIGBNAL和SLOT厷。

connect(but,SIGNAL(&QPushButton::licked),this,SLOT(&Widget::close));

 但是从Qt5开始就对是上面的内容进行了简单化,给connect提供了重载版本,其实参数2和参数4变成了泛形编程,就可以允许传递任意类型的函数指针。

QMetaObject::Connection QObject::connect(
const QObject *sender,
PointerToMemberFunction signal,
const QObject *receiver, 
PointerToMemberFunction slot,
Qt::ConnectionType type = Qt::AutoConnection);

2、自定义槽函数二种实现方法

基本语法:

1. 包含Q_OBJECT宏

在你的类定义中,必须包含 Q_OBJECT 宏。这是因为 Q_OBJECT 宏允许类使用Qt的元对象系统,包括信号和槽的机制。

2. 类继承

确保你的类继承自 QObject 或其子类(如 QWidgetQMainWindow 等),这样类才能支持信号和槽。

3. 声明槽函数

在类声明中,槽函数可以在 public slots:protected slots:private slots: 部分声明,这取决于你希望槽函数的访问级别。

4. 连接信号和槽

使用 QObject::connect 方法将信号连接到槽。

这里我们要完成在窗⼝中设置⼀个按钮,当点击 "按钮" 时改变窗口的名称"。

方法1:代码实现:

这里我们要在widget.h头文件中,对槽函数进行声明

 在widget.cpp中进行对函数的编写,这里我们让如果开关被按下就对窗口进行显示更改为“按钮已经被按下"。

方法2: 通过图形化界面

 这里会自动帮我们生成一个函数

 函数名的说明

 这里我们发送,我们并没有借助connect函数将信号和槽链接起来,但是其实Qt会通过函数名字自动连接。

3、自定义信号

其实Qt中内置的信号,基本就够覆盖用户的所以操作了。我们知道,信号的本质其实就是函数,也就是说如果我能要进行自定义信号,就需要自定义信号函数

在widget.h中,我们完成了对信号的定义

 在widget.cpp中调用connect完成对信号和槽的连接

4、信号和槽的带参传递 

Qt 的信号和槽也⽀持带有参数, 同时也可以⽀持重载. 此处我们要求, 信号函数的参数列表要和对应连接的槽函数参数列表⼀致. 此时信号触发, 调⽤到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中。

在 "widget.h" 头⽂件中声明重载的信号函数以及重载的槽函数

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
 signals:
    void MySignal(const QString& text);
 public:
    void MYStols(const QString& text);

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

在 "Widget.cpp" ⽂件实现重载槽函数以及连接信号和槽。

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
   connect(this,&Widget::MySignal,this,&Widget::MYStols);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::MYStols(const QString & text)
{
    this->setWindowTitle(text);
}


void Widget::on_pushButton_clicked()
{
    //发出自定义的信号
    //这里我们就可以通过信号,把我们想要传递的参数给槽的回调函数
    emit MySignal("信号发送");

}

点击允许程序,在点击按钮输出就可以改变窗口名称 

对于这种带参传递的作用最大的好处就是可以进行进行代码复用,因为信号和槽的关系,可以是一对一,一对多的,多对多关系。也就是说,我们可以有多个信号,但我点击不同信号的时候,在同一槽中处理(回调函数),只是不同信号,传递给槽函数的参数不同,从而达到代码复用。

是我们要注意:信号传递给槽函数的参数,可以多但是不能少

多了就会用槽能接受几个就用几个但是少了一定是会报错误的。

三、 信号和槽的其他说明

1、信号与槽的断开

使⽤ disconnect 即可完成断开. disconnect 的⽤法和 connect 基本⼀致

在 "widget.h" 头⽂件中声明重载的信号函数以及重载的槽函数

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
 public:
    void MySltos1();
    void MySltos2();



private slots:
    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

在 "Widget.cpp" ⽂件实现重载槽函数以及连接信号和槽。

 

#include "widget.h"
#include "ui_widget.h"
#include"QDebug"
#include"QPushButton"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
   connect(ui->pushButton,&QPushButton::clicked,this,&Widget::MySltos1);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::MySltos1()
{
    this->setWindowTitle("修改窗口1");
    qDebug()<<"MySltos1修改";
}

void Widget::MySltos2()
{
    this->setWindowTitle("修改窗口2");
    qDebug()<<"MySltos2修改";
}




void Widget::on_pushButton_2_clicked()
{
    //首先断开连接
    disconnect(ui->pushButton,&QPushButton::clicked,this,&Widget::MySltos1);
    //然后重新绑定连接
     connect(ui->pushButton,&QPushButton::clicked,this,&Widget::MySltos2);
}

这里我们允许程序,点击修改,首先是窗口名称变成 修改窗口1

当我们切换修改就变为,在点击修改就变为修改窗口2 。

注意如果没有用disconnect 断开连接,在点击切换后,会调用二个槽函数

2、使⽤ Lambda 表达式定义槽函数

但如果想⽅便的编写槽函数,⽐如在编写函数时连函数名都不想定义,则可以通过 Lambda表达式 来 达到这个⽬的。 Lambda表达式 是 C++11 增加的特性。C++11 中的 Lambda表达式 ⽤于定义并创建匿名的函数对 象,以简化编程⼯作。

对于lambda表达式这里进行简单介绍:

Lambda表达式 的语法格式如下:

[ capture ] ( params ) opt -> ret { 
 Function body; 
};
  • capture 捕获列表
  • params 参数表
  • opt 函数选项
  • ret 返回值类型
  • Function body 函数

 局部变量引⼊⽅式 [ ]

符号说明
[ ]局部变量捕获列表。Lambda表达式不能访问外部函数体的任何局部变量
[a]在函数体内部使⽤值传递的⽅式访问a变量
[&b]在函数体内部使⽤引⽤传递的⽅式访问b变量
[=]函数外的所有局部变量都通过值传递的⽅式使⽤, 函数体内使⽤的是副本
[&]以引⽤的⽅式使⽤Lambda表达式外部的所有变量
[=, &foo]foo使⽤引⽤⽅式, 其余是值传递的⽅式
[&, foo]foo使⽤值传递⽅式,其余引⽤传递
[this]在函数内部可以使⽤类的成员函数和成员变量,= 和 & 形式也都会默认引⼊

 

运用实例:

3、信号与槽的优缺点

优点: 松散耦合

信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了⾃⼰,Qt的信号槽机制保证了信号与槽函数的调⽤。⽀持信号槽机制的类或者⽗类必须继承于 QObject 类

缺点: 效率较低

与回调函数相⽐,信号和槽稍微慢⼀些,因为它们提供了更⾼的灵活性,尽管在实际应⽤程序中差别不大。通过信号调⽤的槽函数⽐直接调⽤的速度慢约10倍(这是定位信号的接收对象所需的开销;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队),这种调⽤速度对性能要求不是 ⾮常⾼的场景是可以忽略的,是可以满⾜绝⼤部分场景。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PyQt6 优化操作:建立侧边栏,要求可拖拽改变宽度,可用按钮控制侧边栏的展开和收起

1. 官方文档 QSplitter — PyQt Documentation v6.6.0 2. 效果展示 可拖拽改变宽度比例 点击按钮快速收起或展开侧边栏 点击按钮&#xff0c;侧边栏收起&#xff0c;同时按钮图标变为向左箭头 (对应展开功能)&#xff0c;再次点击按钮&#xff0c;侧边栏展开&#xff0c;同…

Pycharm新建工程时使用Python自带解释器的方法

Pycharm新建工程时使用Python自带解释器的方法 新建Project时最好不要新建Python解释器&#xff0c;实践证明&#xff0c;自己新建的Python解释器容易出现各种意想不到的问题。 那么怎样使用Python安装时自带的解释器呢&#xff1f; 看下面的三张截图大家就清楚了。 我的Pyth…

英智数字孪生机器人解决方案,赋能仓库物流模式全面升级

工业机械臂、仓储机器人、物流机器人等模式的机器人系统在现代产业中扮演着愈发重要的角色&#xff0c;他们的发展推动了自动化和智能化水平的提高&#xff0c;有助于为制造业、物流业、医疗保健业和服务业等行业创造新效率并提升人们的生活质量。 行业面临的挑战 机器人开发、…

Windows安装Elasticsearch 7.9.2

1 下载 https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.9.2-windows-x86_64.zip 2 配置 进入config目录&#xff0c;打开elasticsearch.yml文件&#xff0c;给集群和节点配置名称。 cluster.name: my-es node.name: node-1 3 启动 打开bin目录&am…

Docker之常见FAQ记录清单

一、前言 本文记录Docker使用过程中遇见的问题&#xff0c;供后续回顾参考。 关联资源&#xff1a;网络Docker博客、官方FAQ、文档、Docker 从入门到实践、中文社区、riptutorial 二、问题及处理记录 2.1、docker容器内没有vi,nano等编辑器 1&#xff09;如果宿主机本地有&a…

vs2019 - warning LNK4098 : 默认库“msvcrt.lib”与其他库的使用冲突

文章目录 vs2019 - warning LNK4098 : 默认库“msvcrt.lib”与其他库的使用冲突概述笔记实验 - 编译静态库实验 - 编译主工程&#xff0c;包含静态库实验主工程和静态库编译设置不同时的编译报错和警告备注备注 - 判断/Mdd, /MdEND vs2019 - warning LNK4098 : 默认库“msvcrt.…

[SWPUCTF-2022-新生赛]ez_sql

title:[SWPUCTF 2022 新生赛]ez_sql 审题 根据提示&#xff0c;POST传参 得到假的flag 判断类型 字符型注入 判断列数 发现空格和’or’被过滤 重新构造 nss-1/**/oorrder/**/by/**/4#发现为3个字段 采用联合注入union 爆库 发现union被过滤&#xff0c;双写union绕过 发…

以生命健康为中心的物联网旅居养老运营平台

随着科技的飞速发展和人口老龄化的日益加剧&#xff0c;养老问题逐渐成为社会关注的焦点。传统的养老模式已经难以满足现代老年人的多元化需求&#xff0c;因此&#xff0c;构建一个以生命健康为中心的物联网旅居养老运营平台显得尤为重要。 以生命健康为中心的物联网旅居养老运…

两大成果发布!“大规模量子云算力集群”和高性能芯片展示中国科技潜力

在当前的科技领域&#xff0c;量子计算的进步正日益引起全球的关注。中国在这一领域的进展尤为显著&#xff0c;今天&#xff0c;北京量子信息科学研究院&#xff08;以下简称北京量子院&#xff09;和中国科学院量子信息与量子科技创新研究院&#xff08;以下简称量子创新院&a…

【c++】深入剖析与动手实践:C++中Stack与Queue的艺术

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来到STL新的内容&#xff0c;stack和queue 目录 1. stack的介绍与使用函数介绍例题一&#xff1a;最小栈例题二&#xff1a;栈的压入、弹出队列栈的模…

Docker 的数据管理 与 Docker 镜像的创建

目录 一、Docker 的数据管理 1.1.数据卷 1.2.数据卷容器 1.3.容器互联&#xff08;使用centos镜像&#xff09; 二、Docker 镜像的创建 2.1.基于现有镜像创建 2.2.基于本地模板创建 2.3.基于Dockerfile创建 2.3.1联合文件系统&#xff08;UnionFs&#xff09; 2.3.2…

GDPU 竞赛技能实践 天码行空9

1. 埃式筛法 求区间[2, n]内所有的素数对 &#x1f496; Main.java import java.util.Scanner;public class Main {static int N (int) 1e8, cnt 0;static int[] p new int[N];static boolean[] st new boolean[N];public static void main(String[] args){Scanner sc …

使用grasshopper修改梁的起始点方向

一般北方向朝上的情况&#xff0c;梁的方向从南向北&#xff0c;从西向东。 现在使用grasshopper来判断起始点坐标&#xff0c;分辨是否错误。 交换起始点这个&#xff0c;我实在不会用电池操作&#xff0c;只好敲python代码实现了。代码如下&#xff1a; 如果会敲代码的同学…

66.网络游戏逆向分析与漏洞攻防-利用数据包构建角色信息-重新规划游戏分析信息的输出

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

Apache Seata的可观测实践

title: Seata的可观测实践 keywords: [Seata、分布式事务、数据一致性、微服务、可观测] description: 本文介绍Seata在可观测领域的探索和实践 author: 刘戎-Seata 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 Seata简介 Seata的…

STM32单片机通过ST-Link 烧录和调试

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 1. ST-LINK V2 ST LINK v2下载器用于STM32单片机&#xff0c;可以下载程序、调试程序、读取芯片数据&#xff0c;解除芯片读写保护等等&#xff0c;辅助软件用的是STM32 ST-LINK Utility。 STM32 ST-LINK Utility…

电脑上的任务管理器不见了?如何把它打开?

前言 今天小白在睡觉的时候突然梦见回到了学校的电脑教室…… 相信大家都会有体验&#xff1a;每次上电脑课的时候&#xff0c;老师都会通过某些软件监控和控制学生的电脑。 想退出被控端的软件&#xff1f;没机会&#xff01;毕竟任务管理器也被禁用了&#xff0c;想整活都…

算法学习之单调栈

发射站 题目描述 某地有 N N N 个能量发射站排成一行&#xff0c;每个发射站 i i i 都有不相同的高度 H i H_i Hi​&#xff0c;并能向两边&#xff08;两端的发射站只能向一边&#xff09;同时发射能量值为 V i V_i Vi​ 的能量&#xff0c;发出的能量只被两边最近的且比…

Opencv_14_多边形填充与绘制

绘制多边形&#xff1a; 1&#xff09;coInvert.polyline_drawing(src); 2&#xff09;void ColorInvert::polyline_drawing(Mat& image) { Mat canvas Mat::zeros(Size(512, 512), CV_8UC3); Point p1(100, 100); Point p2(150, 100); Point p3(200…

TR6 - Transformer实战 单词预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目录 理论知识关于数据集 Wikitext-2 模型结构代码实现0. 环境1. 加载数据集2. 模型搭建3. 创建模型4. 单轮训练和评估的流程5. 训练 模型效果总结与心得体会 …