Qt——信号 和 槽

news2024/9/28 21:21:02

目录

概述

信号和槽的使用

自定义信号和槽

带参数的信号和槽


概述

        在Linux系统中,我们也介绍了信号的产生、信号的检测以及信号的处理机制,它就是系统内部的通知机制,也可以是一种进程间通信的方式。在系统中有很多信号,我们可以通过signal()函数捕捉信号,重写一个信号处理函数。在Qt中的信号也和系统中的信号有相似之处。

        Qt中的信号也要涉及信号三要素:信号源、信号类型和信号处理方式

  • 信号源:Qt中的信号是由某个控件发出的,Linux系统中可以是一个进程发送的信号。
  • 信号类型:用户不同的操作会触发不同的信号,例如点击按钮就会触发点击信号(clicked)、在输入框中移动光标也会触发相应的信号,我们写这样的GUI程序就是为了和用户交互,所以必须知道当前用户的具体操作,通过不同的操作进行不同的处理
  • 信号处理方式:在Qt中就引入了一个概念就是槽(slot),说白了就是一个函数,再使用connect这样的函数把一个信号和一个槽关联起来,之后只要触发了信号,Qt就会自动执行槽函数,这种槽函数本质上也是一种回调函数。

        所以在Qt中一定要先关联信号和槽,也就是先要有槽函数并使用connect函数将二者关联起来,然后再触发这个信号,顺序不能颠倒。


信号和槽的使用

        在Qt中,QObject类提供了一个静态成员函数,就是connect(),这个函数就是关联信号和槽函数的。

        而且Qt中的类本身也存在着一定的继承关系,比如我们使用的QLabel、QPushButton、QLineEdit等,他们的父类都是QWidget,也就是我们创建项目时选择的要继承的类,这个QWidget类也是继承了QObject这个类。所以Qt中基本所有的类都可以使用connect()这个函数。

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

        这个函数上一篇我们已经介绍过了,再来说一下细节:

  • 前两个参数必须要匹配,比如是QPushButton对象发出的,那也必须是QPushButton内置的信号。
  • 第一个和第三个参数我们传入的是QObject的子类指针,所以没有问题,但是第二个和第四个参数传入的是函数指针,但是为什么使用char*来接收呢?这两个的意义可不一样.
  • 原因就是这是旧版本的connect函数声明,函数传参是时候需要给这两个参数分别放在SIGNAL()和SLOT()的括号中,通过宏替换就可以把函数指针转换成char*.
  • 所以从Qt 5开始,做出了简化,不需要写这两个宏了,给connect函数提供了重载版本。
    template <typename Func1, typename Func2>
    static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender,\
                                                  Func1 signal,\
                                                  const typename QtPrivate::FunctionPointer<Func2>::Object *receiver,\
                                                  Func2 slot,\
                                                  Qt::ConnectionType type = Qt::AutoConnection)
  • 这就是为什么传参的时候一定要匹配,这样也有了一定的参数检查功能。

        我们再写一个场景来使用一下。

// widget.cpp

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

#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPushButton* button = new QPushButton(this);
    button->setText("关闭");
    button->move(300, 200);

    connect(button, &QPushButton::clicked, this, &Widget::close);
}

Widget::~Widget()
{
    delete ui;
}
  • 创建一个QPushButton对象,想要点击这个按钮后就关闭这个窗口,发出信号的一定是QPushButton对象。
  • 发出的信号一定是QPushButton内置的clicked信号
  • 要交给的对象就是this也就是Widget对象
  • 处理函数就可以使用Widget继承的QWidget内置的close()槽函数

        运行后就可以通过点击这个按钮关闭这个界面了。

        

        但是像clicked这样的信号还有多少呢,想要知道就要看看文档了。

        

        我们打开这个程序就可以查看文档,在文档的索引框,查找QPushButton类。

        找了一遍后发现没有找到clicked这样的信号,既然这样就要向它的父类中查找。

        QPushButton的父类就是QAbstractButton,通过类名我们也可以得知这是一个抽象类,在这个页面向下查找就找到了Signals这块,这里就有clicked等信号,也就类似于函数。


自定义信号和槽

        有了上述的介绍,我们现在就可以自己写一个信号处理动作,这也是上一篇也用过的,先使用纯代码的方式实现一下自定义槽

  • 还是要先new一个QPushButton对象,把点击信号和槽函数关联起来。
  • 槽函数中就设置为,捕捉到了信号就把Widget界面的标题修改一下。

        

        下面我们再来看一下通过图形化界面的方式设置信号和槽。

  1. 打开Qt Disigner,通过拖拽的方式把Push Button控件添加到界面。
  2. 可以编辑一下按钮文本,然后右键点击控件,再点击转到槽
  3. 点击后就可以看到Push Button提供的信号,甚至还有它的父类的信号,常用的还是clicked信号
  4. 双击clicked就会跳转到编辑widget.cpp的界面,此时函数的声明和定义都已经自动生成好了,编写代码即可。

【注意】:这种方式是不会出现connect()函数的,Qt中除了connect可以连接信号和槽外,还可以通过函数名字的方式来自动连接,如上图所示:

  • on作为固定前缀
  • pushButton为控件的objectName
  • clicked为信号名字

当符合规则后,Qt就可以把信号和槽自动建立好,所以函数名必须是正确的,如果不正确就无法连接。

        这里名字故意写错,就不能达到我们想要的效果,这都是Qt中调用connectSlotsByName这个函数触发自动连接信号和槽,这个函数是在自动生成的ui_widget.h中setupUi函数中调用的。

        所以,如果是通过图形化界面创建控件,还是使用第二种方式快速连接信号和槽;如果是通过代码的方式创建控件,还是得手动调用connect函数,原因就是没有调用connectSlotsByName函数。

        虽然Qt中允许自定义信号,但是比较少见,开发过程中很少自定义信号,在GUI界面的操作是可以穷举出来的,Qt中内置的信号基本上已经覆盖了,所以使用Qt内置的信号就足够了。

        Widget类虽然没有定义任何信号,但是它继承了QWidget和QObject,所以他们两个的信号可以直接使用。

        信号本质上也是一个函数,它是是一个特殊的函数,只需要写出函数声明,告诉Qt这是一个信号即可,这个函数的定义在编译过程中是自动生成的。

        而且信号在Qt中是特殊的机制,Qt生成的信号函数的实现也要配合Qt框架做其他既定操作。

        作为信号函数,返回值必须是void,有无参数都可以,也可以支持重载。

        signals是Qt自己扩展的关键字,qmake会调用代码分析和生成的工具,识别到signals这个关键字时就会把下面的函数声明认为是信号,并自动生成函数定义。

        通过connect函数连接信号和槽函数就可以了,但是光连接还是不够的,还需要发送我们自定义的信号,这个emitu也是Qt中的关键字,作用就是发送信号

        或者我们把信号从构造函数拿出来,当点击按钮,就会触发on_pushButton_clicked函数,函数中就会发送mySignal信号,收到信号就会执行handleSignal自定义函数,之后就会修改窗口标题。


带参数的信号和槽

        上述的不管是我们自定义的还是Qt内置的信号和槽都是不带参数的,但是他们也可以带参数,并且信号和槽的参数必须一致,此时触发信号的时候,就可以给信号函数传递实参,这个参数就会被传递到对应的槽函数中。

        参数的类型必须要一致,个数不一致是可以的,但是要求信号的参数的个数必须要比槽的参数多。

        通过这一次连接信号和槽,并搭配不同参数就可以实现不同结果,可以让代码复用,就比如:

        而且信号的参数比槽函数多也是可以的,但是不允许槽函数中的参数比信号中的多,原因就是:

  • 一个槽函数可能绑定多个信号。
  • 如果严格要求就意味着信号绑定到槽的要求变高了。
  • 所以信号的参数个数可以大于槽的参数个数,这样让信号和槽之间的绑定变得更灵活更多的信号可以绑定到这个槽函数上
  • 虽然个数不一致,但是槽函数会按照参数顺序拿前N个参数,这样就可以确保槽函数的每个参数都有值

        还有一点就是,如果想要使用信号和槽的机制,就必须在类的一开始写上Q_OBJECT宏。

        当我们转到定义就可以看到这个宏中展开的代码,这里也有很多的宏,也会继续展开,最终实现相应的功能。

        

        信号和槽最主要就是要解决响应用户的操作,它在GUI框架中是一个有特色的机制,但是它的实现就没有那么简洁,但是它还要这样做就是为了:

  • 触发用户操作的控件 和 处理用户的操作逻辑 解耦合
  • 也想起到多对多的效果一个信号可以connect到多个槽函数上,一个槽函数也可以被多个信号connect。

这就是可以把多个信号和多个槽函数绑定到一起。

【补充】:

  1. 可以使用disconnect断开信号和槽的连接。但是大部分情况下,把信号和槽连接好就不用管了,主动断开的情况就是要把信号重新绑定到另一个槽函数上,如果不断开,这个信号发送就会触发两个槽函数。断开连接前,标题修改为旧标题,当点击下方pushButton后,上方原来的信号和槽断开了连接,重新绑定后,再点击上方pushButton,标题修改为新标题。
  2. connect函数连接的槽函数也可以是一个lambda表达式。还可以这样使用。但是要注意lambda表达式的捕捉条件,“=”是值的方式捕捉,“&”是引用的方式,要是使用引用的方式就要注意这个变量的生命周期。

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

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

相关文章

镜舟科技亮相2024中国移动算力网络大会、Qcon、DTC等多项活动

在刚刚过去的 4 月份&#xff0c;镜舟科技受邀参与一系列技术交流活动&#xff0c;与移动云、金科创新社、infoQ、墨天轮、开科唯识等媒体及合作伙伴展开积极交流&#xff0c;并分享其在数据技术、金融等垂直行业领域的创新实践&#xff0c;从产业侧、业务侧、技术侧洞察需求、…

React:Router-3.路由懒加载

在 React&#xff1a;Router-1.BrowserRouter组件式 和 React&#xff1a;Router-2. createBrowserRouter函数式 两篇文章中我们已经完成了路由的创建。但是这种方式&#xff0c;会全量加载路由资源&#xff0c;如果项目较复杂&#xff0c;会产生性能问题。 为了优化项目性能&…

螺栓扭矩设计多大?原来如此简单!——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 螺栓扭矩设计&#xff0c;看似复杂&#xff0c;实则遵循一定的科学原理和实践经验。本文将深入浅出地探讨螺栓扭矩设计的原理和方法&#xff0c;帮助读者轻松掌握这一技能。 首先&#xff0c;我们需要了解螺栓扭矩的基…

Simulink从0搭建模型04-练习_一阶低通滤波器的实现

Simulink从0搭建模型04-练习_一阶低通滤波器的实现 1. 前言1.1. 参考1.2. 好习惯&#xff08;初始设置&#xff09; 2. 一阶低通滤波的实现2.1. 根据公式在Simulink中搭模型2.1.1. 一阶低通滤波公式2.1.2. 搭建一阶低通滤波 2.2. 把模型装进子系统的2种方式2.2.1. 方式12.2.2. …

【联通支付注册/登录安全分析报告】

联通支付注册/登录安全分析报告 前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨…

26、Qt使用QFontDatabase类加载ttf文件更改图标颜色

一、图标下载 iconfont-阿里巴巴矢量图标库 点击上面的链接&#xff0c;在打开的网页中搜索自己要使用的图标&#xff0c;如&#xff1a;最大化 找到一个自己想用图标&#xff0c;选择“添加入库” 点击“购物车”图标 能看到刚才添加的图标&#xff0c;点击“下载代码”(需要…

安全工程师基础模拟试题

安全工程师基础模拟试题作为一名安全工程师&#xff0c;掌握基本的安全知识和技能是必不可少的。下面是一些基础模拟试题&#xff0c;帮助您检验自己的安全工程师能力。1.在网络安全中&#xff0c;什么是… 1安全工程师基础模拟试题 作为一名安全工程师&#xff0c;掌握基本的…

【机器学习300问】85、Adam梯度下降优化算法的原理是什么?

Adam优化算法取了两个算法名称的首字母——Adaptive Moment Estimation的缩写&#xff0c;结合了Momentum算法和RMSprop算法的优点。在Momentum中&#xff0c;会计算前一时刻的梯度&#xff0c;并将其用于当前时刻的梯度更新&#xff1b;而RMSprop会对梯度的大小进行自适应调整…

PyCharm2024安装教程

PyCharm是一款功能强大的Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;它提供了许多工具和功能来帮助开发者编写、调试和测试Python代码。以下是使用PyCharm的基本步骤&#xff1a; 安装PyCharm&#xff1a;首先&#xff0c;你需要从JetBrains官方网站下载并安装…

服务器直连电脑(盒子直连电脑)电脑需要设置为固定ip才能访问盒子

文章目录 现象盒子设置为固定ip&#xff0c;pc设置成固定ip&#xff08;以太网网卡&#xff0c;realtak那个&#xff0c;不是tap-windows那个&#xff0c;tap-windows不用管&#xff09;&#xff0c;在pc上用ip搜索工具搜索&#xff0c;可以搜到盒子ip。盒子设置为固定ip&#…

基于D1开发板和腾讯云nginx服务器构建家庭视频监控方案

腾讯云服务器使用nginx搭建rtmp服务器 什么是nginx&#xff1f; nginx是一款优秀的反向代理工具&#xff0c;通过nginx可以实现搭建高可用的轻量级web服务器&#xff0c;除此之外&#xff0c;通过Nginx自带的rtmp模块&#xff0c;也可以实现rtmp服务器的搭建。 安装nginx 安装编…

常见排序算法——希尔排序

基本原理 希尔排序在插入排序的基础之上&#xff0c;将待排序序列分成组&#xff0c;分成 gap 个组&#xff0c;组的数量通过 length / 2 获得&#xff0c;比如6个元素的序列&#xff0c;那么就是 3 个组&#xff0c;每个组两个元素&#xff0c;然后将每个组的元素进行插入排…

Ardupilot Rpanion iperf网络性能测试

Ardupilot Rpanion iperf网络性能测试 1. 源由2. 分析3. 安装4. 测试4.1 第一次测试4.1.1 iperf测试参数A4.1.1.1 测试链路14.1.1.2 测试链路24.1.1.3 测试链路3 4.1.2 iperf测试参数B - 测试链路34.1.2.1 测试数据4.1.2.2 数据简单分析4.1.2.3 数据深入分析4.1.2.4 模拟测试网…

霍金《时间简史 A Brief History of Time》书后索引(E--H)

A–D部分见&#xff1a;霍金《时间简史 A Brief History of Time》书后索引&#xff08;A–D&#xff09; 图源&#xff1a;Wikipedia INDEX E Earth: circumference, motion, shape Eclipses Eddington, Arthur Einstein, Albert: biography, see also Relativity; Special…

解决数据丢失烦恼,Tenorshare 4DDiG 数据恢复工具助您一键找回珍贵文件

在数字化时代&#xff0c;我们的生活和工作几乎完全依赖于电脑和移动设备。然而&#xff0c;意外情况时常发生&#xff0c;误删除、格式化、系统崩溃等问题可能会导致重要数据丢失&#xff0c;给我们带来不便和困扰。如何有效地解决数据丢失问题&#xff1f;不用担心&#xff0…

QT---day5,通信

1、思维导图 2、TCp 服务器 #ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> #include <QTcpServer> #include <QList> #include <QTcpSocket> #include <QMessageBox> #include <QDebug> #include <QTcpServer> QT_B…

如何更好地使用Kafka? - 故障时解决

要确保Kafka在使用过程中的稳定性&#xff0c;需要从kafka在业务中的使用周期进行依次保障。主要可以分为&#xff1a;事先预防&#xff08;通过规范的使用、开发&#xff0c;预防问题产生&#xff09;、运行时监控&#xff08;保障集群稳定&#xff0c;出问题能及时发现&#…

大文件传输的好帮手Libarchive:功能强大的开源归档文件处理库

在数字化时代&#xff0c;文件的存储和传输对于企业的日常运作至关重要。但是&#xff0c;服务器中的压缩文件往往无法直接查看或预览&#xff0c;这给用户带来了不便。为了解决这一问题&#xff0c;在线解压功能的开发变得尤为重要。接下来&#xff0c;小编将介绍一个能够实现…

【Web后端】Tomcat简介_安装_解决乱码_idea配置

1.1 简介 tomcat是在oracle公司的ISWDK(lavaServer Web DelevopmentKit)的基础上发展起来的一个优秀的开源的servlet容器tomcat使用java语言编写。运行稳定、可靠、效率高&#xff0c;可以和目前 主流web服务器一起工作(如IIS、Apache、 Nginx)tomcat是Apache软件基金会(Apach…

初识指针(4)<C语言>

前言 前面的文章&#xff0c;已经对指针的基础概念以及运用有了初步了解&#xff0c;我们可以进一步探究指针比较深入的知识&#xff0c;下文将主要介绍&#xff1a;使用指针数组模拟二维数组、字符指针变量、数组指针、二维数组传参的本质、函数指针、typedef关键字等。 目录…