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://xiahunao.cn/news/3032453.html

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

相关文章

MySQL —— 约束

一、概念介绍 MySQL是数据管理的最后一层防线&#xff0c;因此在对数据进行各种操作的时候&#xff0c;我们尽可能的从技术的角度去对用户进行各种合理的约束&#xff0c;使得各种数据的操作尽可能的合理&#xff0c;这就是约束的概念&#xff0c;本篇将整理常见的基本约束&am…

SOCKET编程(4):SOCKET实战

SOCKET实战 Writen()、Readn()函数 send()函数存在需要发送的字符数len小于函数返回的已发送的字符数(ssize_t)的问题 recv()函数存在需要接收的字符数len小于函数返回的已接收的字符数(ssize_t)的问题 解决上述问题通过Writen()、Readn()函数实现 //buff是数据存储地址&a…

资源管理游戏模版进入The Sandbox

我们非常高兴地向您介绍 Game Maker 的最新模板&#xff1a;资源管理游戏&#xff01; 这一全新的模板让您能够深入身临其境的游戏体验中&#xff0c;同时掌握令人兴奋的新机制。通过揭开模板的神秘面纱&#xff0c;您可以锤炼您的游戏设计技能。 什么是资源管理游戏&#xff1…

手机电脑通用便签推荐 好用便签下载

便签软件作为一种日常记录和管理工具&#xff0c;其实用性和便捷性深受用户喜爱。一款优秀的便签软件不仅能帮助我们随时随地记录重要信息&#xff0c;还能有效提高工作效率。然而&#xff0c;市场上很多便签应用仅限于单一平台使用&#xff0c;对于需要在手机和电脑间频繁切换…

条件平差——以水准网平差为例 (python详细过程版)

目录 一、原理概述二、案例分析三、代码实现四、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、原理概述 条件平差的函数模型和随机模型为: A V + W = 0

已解决【nvidia-smi】Failed to initialize NVML: Driver/library version mismatch解决方法

本文摘要&#xff1a;【nvidia-smi】Failed to initialize NVML: Driver/library version mismatch解决方法。 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专…

服务器内存占用不足会怎么样,解决方案

在当今数据驱动的时代&#xff0c;服务器对于我们的工作和生活起着举足轻重的作用。而在众多影响服务器性能的关键因素当中&#xff0c;内存扮演着极其重要的角色。 服务器内存&#xff0c;也称RAM&#xff08;Random Access Memory&#xff09;&#xff0c;是服务器核心硬件部…

做视频号小店,怎么找达人合作?这里有详细讲解

大家好&#xff0c;我是电商笨笨熊 做视频号小店是没有自然流量的&#xff0c;这点刚入驻的新玩家还不清楚&#xff1b; 因此很多老电商玩家们还想着继续拿其他平台动销自然流的玩法去做视频号&#xff1b; 只能说这种方式在视频号是完全行不通的&#xff0c;当下想要推广售…

高效电源测试设备助力自动化测试和数据分析

在当今电子产品的研发和生产过程中&#xff0c;电源测试设备的重要性不言而喻。一款优秀的电源测试设备能够显著提升测试效率&#xff0c;确保电源模块的性能达到设计要求。 纳米软件NSAT-8000电源测试系统是一款自动化电源测试设备&#xff0c;在测试电源模块时&#xff0c;通…

C++笔试强训day16

目录 1.字符串替换 2.神奇数 3.DNA序列 1.字符串替换 链接 简单的遍历替换即可&#xff1a; class Solution { public:string formatString(string str, vector<char>& arg) {string ret;int k 0;for (int i 0; i < str.size(); i){if (str[i] %){ret arg…

2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷3(私有云)

#需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包…

Ecoinvent中system model中的 cutoff、consequential、apos的区别:

一&#xff1a;解释 Cutoff (截断)模型:只考虑主要的生产过程,不考虑副产品的进一步影响。比如说牛奶厂在生产牛奶的同时会产生奶酪,cutoff模型只考虑牛奶的影响,不考虑奶酪的后续利用。 Consequential (后果)模型:考虑某个决策或变化会引起的一系列连锁反应和影响。比如说我们…

【Pip】pip 安装第三方包异常:[SSL:CERTIFICATE_VERIFY_FAILED]解决方案

pip 安装第三方包异常:[SSL:CERTIFICATE_VERIFY_FAILED] 大家好 我是寸铁&#x1f44a; 总结了一篇pip 安装第三方包异常:[SSL:CERTIFICATE_VERIFY_FAILED]✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 报错 今天在安装第三方包时报错如下: 解决方案 本质上是需要指定信任的镜像…

云效 Pipeline as Code 来了!这些场景,用好它效率翻倍!

从可视化编排到支持 YAML 编排 云效流水线 Flow 是开箱即用的企业级持续集成和持续交付工具&#xff0c;支持丰富的代码源、构建、自动化测试工具、多种部署类型和部署方式&#xff0c;与阿里云深度集成&#xff0c;还提供多种企业级特性&#xff0c;助力企业高效完成从开发到…

itextpdf 7生成pdf(主要是文字和表格,支持中文)

我们经常会遇到要导出pdf的需求,方式有很多种 今天的教程是采用itextpdf的方式生成pdf itextpdf是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF文档&#xff0c;而且可以将Html文件转化为PDF文件。 这里先展示一下效果图 首先在pom.xml中引入相关依赖 <dep…

Vue3 - 前端项目代码防止被调试/被爬,阻止浏览器F12开发者工具

项目背景 大家都知道浏览器的开发者工具能干啥&#xff0c;正经的用法&#xff1a;开发时调试代码逻辑&#xff0c;修改布局样式&#xff1b;不正经的用法&#xff1a;改改元素骗骗人&#xff0c;找找网站接口写爬虫&#xff0c;逆向js破解加密等等&#xff0c;所以说前端不安…

怎么制作流程图?介绍制作方法

怎么制作流程图&#xff1f;在日常生活和工作中&#xff0c;流程图已经成为我们不可或缺的工具。无论是项目规划、流程优化&#xff0c;还是学习理解复杂系统&#xff0c;流程图都能帮助我们更直观地理解和表达信息。然而&#xff0c;很多人可能并不清楚&#xff0c;其实制作流…

进程间通信(一)

IPC 在之前我们也有涉及到进程间通信的知识点&#xff0c;比如fork或exec或父进程读取子进程的退出码等&#xff0c;但是这种通信方式很有限&#xff0c;今天来学习进程间通信的其他技术——IPC&#xff08;InterProcess Communication&#xff09;。 IPC的方式通常有管道&…

Windows 10 Manager (Win10优化工具),中文破姐版 v3.9.3

01 软件介绍 Windows 10 Manager是一款为Win10操作系统设计的综合优化工具。包含逾40种不同的功能模块&#xff0c;旨在全方位地提升系统性能。其核心效用体现在对Win10的优化、调整、清理、加速和修复方面。能够显著提高系统的运行速度&#xff0c;并有效地排查及解决系统问题…

无管理员权限linux系统手动切换cuda版本

查看当前计算机cudatoolkit的版本 nvcc -V下载 如果想切换到指定版本&#xff0c;则去官网下载&#xff08;10.1版本为例&#xff09;&#xff1a; cuda下载 cudnn下载 将下载好的文件放到服务器的文件夹中 安装 安装cuda sh cuda_10.1.243_418.87.00_linux.run选择接受 …