Qt——信号 和 槽

目录

概述

信号和槽的使用

自定义信号和槽

带参数的信号和槽


概述

        在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.rhkb.cn/news/323896.html

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

相关文章

设计模式学习笔记 - 回顾总结:在实际软件开发中常用的设计思想、原则和模式

概述 本章&#xff0c;先来回顾下整个专栏的知识体系&#xff0c;主要包括面向对象、设计原则、编码规范、重构技巧、设计模式五个部分。 面向对象 相对于面向过程、函数式编程&#xff0c;面向对象是现在最主流的编程范式。纯面向过程的编程方法&#xff0c;现在已经不多见了…

数据结构中的栈(C语言版)

一.栈的概念 栈是一种常见的数据结构&#xff0c;它遵循后进先出的原则。栈可以看作是一种容器&#xff0c;其中的元素按照一种特定的顺序进行插入和删除操作。 压栈&#xff1a;栈的插入操作叫做进栈/压栈/入栈&#xff0c;入数据在栈顶。 出栈&#xff1a;栈的删除操作叫做…

uniapp/微信小程序实现加入购物车点击添加飞到购物车动画

1、预期效果 2、实现思路 每次点击添加按钮时&#xff0c;往该按钮上方添加一个悬浮元素&#xff0c;通过位移动画将元素移到目标位置。 1. 为每个点击元素设置不同的class&#xff0c;才能通过uni.createSelectorQuery来获取每个元素的节点信息&#xff1b; 2. 添加一个与…

在51单片机里面学习C语言

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「&#xff23;语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 说出来你们可能都…

0510_IO5

练习题&#xff1a; #include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>#include <sys/stat.h>#include <fcntl.h>#include <pthread.h>#include <semaphore.h>#incl…

【智能算法应用】基于麻雀搜索算法-支持向量回归预测(SSA-SVR)

目录 1.算法原理2.数学模型3.结果展示4.调试记录5.参考文献6.代码获取 1.算法原理 【智能算法】麻雀搜索算法&#xff08;SSA&#xff09;原理及实现 2.数学模型 支持向量机(SVM)是针对二分类问题&#xff0c;支持向量回归(SVR)基于SVM应用与回归问题。SVR回归与SVM分类的区…

【数据库原理及应用】期末复习汇总高校期末真题试卷08

试卷 一、选择题(每题 2 分&#xff0c;共 30 分)    1. ___ ____是长期存储在计算机内的有组织,可共享的数据集合. A.数据库管理系统 B.数据库系统 C.数据库 D.文件组织 2. 数据库类型是按照 来划分…

使用 Gitea 进行私有 Git 仓库管理

在本文中&#xff0c;我们将介绍如何使用 Gitea 搭建并管理私有 Git 仓库。Gitea 是一个轻量级的 Git 服务&#xff0c;提供了类似于 GitHub 的功能&#xff0c;适合个人和小团队使用。我们将通过以下步骤来完成搭建和配置 Gitea 服务器。 步骤一&#xff1a;安装 Gitea 首先…

自定义表单元素组件内容变化触发ElForm重新校验

对于下图中“付费类型”怎么实现有很多种方式&#xff0c;我能想到的是以下两种&#xff1a; Element Plus的RadioButton自定义组件 1. RadioButton 它本质上就是一个单选组件&#xff0c;它跟Element Plus的RadioButton本质上没有区别&#xff0c;无非是外观上的差别。那么…

Docker容器:Docker-Consul 的容器服务更新与发现

目录 前言 一、什么是服务注册与发现 二、 Docker-Consul 概述 1、Consul 概念 2、Consul 提供的一些关键特性 3、Consul 的优缺点 4、传统模式与自动发现注册模式的区别 4.1 传统模式 4.2 自动发现注册模式 5、Consul 核心组件 5.1 Consul-Template组件 5.2 Consu…

kaldi学习参考

HMM模型 https://www.cnblogs.com/baixf-xyz/p/16777438.htmlhttps://www.cnblogs.com/baixf-xyz/p/16777438.htmlGMM-HMM 基于GMM-HMM的语音识别系统https://www.cnblogs.com/baixf-xyz/p/16777439.html https://www.cnblogs.com/baixf-xyz/p/16777426.htmlhttps://www.cnbl…

【SRC实战】利用APP前端加密构造数据包

挖个洞先 https://mp.weixin.qq.com/s/ZnaRn222xJU0MQxWoRaiJg “ 以下漏洞均为实验靶场&#xff0c;如有雷同&#xff0c;纯属巧合” 01 — 漏洞证明 “ 参数加密的情况&#xff0c;不会逆向怎么办&#xff1f;” 1、新用户首次设置密码时抓包&#xff0c;此处设置为0000…

Oracle -在线回缩表

conn scott/tiger DROP TABLE EMP1 PURGE; CREATE TABLE EMP1 AS SELECT * FROM EMP; alter table emp1 enable row movement; -- 启动回缩特性 insert into emp1 select * from emp1; / / commit; -- 增加到14000行 -- 分析表的结构 analyze table emp1 comput…

<Linux> 权限

目录 权限人员相对于文件来说的分类更改权限文件的拥有者与所属组umask粘滞位 权限 权限是操作系统用来限制对资源访问的机制&#xff0c;权限一般分为读、写、执行。系统中的每个文件都拥有特定的权限、所属用户及所属组&#xff0c;通过这样的机制来限制哪些用户、哪些组可以…

Oracle count的优化-避免全表扫描

Oracle count的优化-避免全表扫描 select count(*) from t1; 这句话比较简单&#xff0c;但很有玄机&#xff01;对这句话运行的理解&#xff0c;反映了你对数据库的理解深度&#xff01; 建立实验的大表他t1 SQL> conn scott/tiger 已连接。 SQL> drop table t1 purge…

基于SWIFT框架的Phi-3推理、微调实战教程

近期&#xff0c; Microsoft 推出 Phi-3&#xff0c;这是 Microsoft 开发的一系列开放式 AI 模型。Phi-3 模型是一个功能强大、成本效益高的小语言模型 (SLM)&#xff0c;在各种语言、推理、编码和数学基准测试中&#xff0c;在同级别参数模型中性能表现优秀。为开发者构建生成…

OpenHarmony 实战开发——移植通信子系统

通信子系统目前涉及Wi-Fi和蓝牙适配&#xff0c;厂商应当根据芯片自身情况进行适配。 移植指导 Wi-Fi编译文件内容如下&#xff1a; 路径&#xff1a;“foundation/communication/wifi_lite/BUILD.gn” group("wifi") {deps [ "$ohos_board_adapter_dir/ha…

AOP底层实现原理

一、JDK 核心思想&#xff1a; 原始类和代理类实现相同的接口 使用JDK自带api创建动态代理 public class JDKTest{public static void main(String[] args){// 获取原始对象UserService userService new UserServiceImpl();ClassLoader classLoader JDKTest.class.getClas…

外包干了6天,技术明显进步

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

数据结构——图

链接: 来源&#xff1a;link 1、基础知识 2、图的存储结构 1、邻接矩阵 注意&#xff1a; 邻接矩阵表示法的空间复杂度为O(n^2)&#xff0c; 其中n为图的顶点数∣V∣。用邻接矩阵法存储图&#xff0c;很容易确定图中任意两个顶点之间是否有边相连。但是&#xff0c;要确定图…