【Qt学习笔记】(二)信号和槽

信号和槽

  • 1 信号和槽概述
  • 2 信号和槽的使用
  • 3 可视化生成槽函数
  • 4 自定义信号和槽
  • 5 带参数的信号和槽
  • 6 信号与槽的连接方式
  • 7 信号与槽的断开
  • 8 使用 Lambda 表达式来定义槽函数

1 信号和槽概述

  • 在Qt中,用户和控件的每次交互过程称为一个事件。比如"用户点击按钮"是一个事件,"用户关闭窗口"也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出"按钮被点击"的信号,用户关闭窗口会发出"窗口被关闭"的信号。
  • Qt中的所有控件都具有接收信号的能力,一个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作。例如,按钮所在的窗口接收到"按钮被点击"的信号后,会做出"关闭自己"的响应动作;再比如输入框自己接收到"输入框被点击"的信号后,会做出"显示闪烁的光标,等待用户输入数据"的响应动作。在Qt中,对信号做出的响应动作就称之为槽。
  • 信号和槽是Qt特有的消息传输机制,它能将相互独立的控件关联起来。比如,"按钮"和"窗口"本身是两个独立的控件,点击"按钮"并不会对"窗口"造成任何影响。通过信号和槽机制,可以将"按钮"和"窗口"关联起来,实现"点击按钮会使窗口关闭"的效果。

在这里插入图片描述
信号的本质
信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时Qt对应的窗口类会发出某个信号,以此对用户的操作做出反应。因此,信号的本质就是事件。如:

  • 按钮单击、双击
  • 窗口刷新
  • 鼠标移动、鼠标按下、鼠标释放,
  • 键盘输入

在 Qt 中信号是通过什么形式呈现给使用者呢?

  • 我们对哪个窗口进行操作,哪个窗口就可以捕捉到这些被触发的事件。
  • 对于使用者来说触发了一个事件我们就可以得到Qt框架给我们发出的某个特定信号。
  • 信号的呈现形式就是函数,也就是说某个事件产生了,Qt 框架就会调用某个对应的信号函数,通知使用者。

槽的本质

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

说明
(1) 信号和槽机制底层是通过函数间的相互调用实现的。每个信号都可以用函数来表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。 例如: "按钮被按下"这个信号可以用clicked()函数表示,"窗口关闭"这个槽可以用close()函数表示,假如使用信号和槽机制实现: "点击按钮会关闭窗口"的功能,其实就是clicked()函数调用close()函数的效果。

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

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

信号函数的定义是Qt自动在编译程序之前生成的.编写Qt应用程序的程序员无需关注.这种自动生成代码的机制称为元编程(Meta Programming) .这种操作在很多场景中都能见到.

2 信号和槽的使用

连接信号和槽
在 Qt 中,QObject 中提供了一个静态成员函数 connect() ,该函数专门用来关联指定的信号函数和槽函数。

                  关于 QObject

QObject 是 Qt 内置的父类,Qt 中提供的很多类都是直接或者间接继承自 QObject,比如 QWidget 就继承自 QObject

以下是 connect 的函数原型

1 connect (const QObject *sender,
2 const char * signal ,
3 const QObject * receiver ,
4 const char * method ,
5 Qt::ConnectionType type = Qt::AutoConnection )

参数说明:

  • sender:信号的发送者;
  • signal:发送的信号(信号函数) ;
  • receiver:信号的接收者;
  • method:接收信号的槽函数;
  • type:用于指定关联方式,默认的关联方式为Qt::AutoConnection,通常不需要手动设定。

connect 要求第一个参数和第二个参数是匹配的,比如第一个参数的类型如果是 QPushButton* ,那么,第二个参数的信号必须是 QPushButton 内置的信号(父类的信号),不能是其他的一个类。

实现一个点击按钮关闭窗口的功能

#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对象button->setText("关闭");//设置button上的文字button->move(200,200);//设置button的位置connect(button,&QPushButton::clicked,this,&Widget::close);
}Widget::~Widget()
{delete ui;
}

首先看connect,第一个参数和第二个参数要求是匹配的,表示button对象发出了clicked 信号,注意这里是 clicked,而不是 click
在这里插入图片描述
第三个参数表示信号的接收者,填写 this,Widget 接收
第四个参数表示接收信号的槽函数,也就是收到信号了以后接收者怎么处理。close 是 Qt 内置的槽函数,Widget 继承自 QWidget ,也就继承了父亲的槽函数,该槽函数的功能 Qt 内部已经实现好了。

运行程序后,点击按钮成功关闭窗口
在这里插入图片描述
关于connect函数的问题
在查看官方文档的时候,connect的原型如下
在这里插入图片描述
第二个参数和第四个参数是 char* 类型,而我们直接在用的时候传的确是函数指针。在C++中,是不允许使用两个不同的指针类型相互赋值的。
官方文档里的这个函数声明是旧版本的 connect 声明 ,正确写法是
在这里插入图片描述
旧版本要搭配 SIGNAL 和 SLOT 这两个宏。从 Qt5 开始,对该写法进行了简化,不再需要写这两个宏了,所以上面的代码才能直接传入函数指针。Qt5 开始,给 connect 提供了重载版本,第二个参数和第四个参数成了泛型参数,允许传入任意类型的函数指针了。
点击 ctrl 然后鼠标点击 connect ,跳转到源码中查看。
在这里插入图片描述
此时,connect 函数就带有一定的参数检查功能,如果传入的第一个参数和第二个参数不匹配,或者第三个参数和第四个参数不匹配。(不匹配指的是,第二个参数和第四个参数的函数指针不是第一个参数和第三个参数的成员函数),此时代码编译出错。

3 可视化生成槽函数

在 ui 界面,拖动 pushbutton 到编辑界面然后输入文字后,右键单击该按钮,选择 “转到槽”
在这里插入图片描述
这个窗口为我们提供了 QPushButton 的所有信号,还包括了 QPushButton的父类信号
选择第一个信号,点击确定
在这里插入图片描述
就会自动在 widget.cpp 文件里面为我们生成对应的槽函数
在这里插入图片描述
现在实现这样的功能:点击按钮,就会改变窗口的标题。
在这里插入图片描述
运行程序,点击按钮。窗口的标题改变。
在这里插入图片描述
为什么这种方式没有调用 connect 函数,却还是能将信号和槽联系起来呢?
原因是 Qt 对于这种命名规则的槽函数,会自动和对应信号进行连接。
说明:
自动生成槽函数的名称有一定的规则。槽函数的命名规则为: on_ XXX_ SSS, 其中:

  • 1、以"on "开头,中间使用下划线连接起来;
  • 2、" XXX "表示的是对象名(控件的obj ectName|属性)。
  • 3、" SSS "表示的是对应的信号。
  • 如: " on_ pushButton_ _clicked() " , pushButton代表的是对象名,clicked 是对应的信号。

4 自定义信号和槽

在以上的内容中,我们知道槽函数不仅仅可以用 Qt 内置的函数,还可以自定义。信号也可以由我们自定义,不过 Qt 提供的信号在大多数情况下已经足够我们使用了。本节内容是如何由自定义信号和槽。
在Qt中,允许自定义信号的发送方以及接收方,即可以自定义信号函数和槽函数。但是对于自定义的信号函数和槽函数有一定的书写规范。
自定义信号函数书写规范:

  • 自定义函数信号必须写到 “signals” 下
  • 返回值为 void ,只需要声明,不需要实现
  • 可以有参数,也可以发生重载

自定义槽函数书写规范:

  • 早期的 Qt 版本要求槽函数必须写到 “public slots” 下,但是高版本的 Qt 允许写到类的 “public” ,作用域或者全局下
  • 返回值为 void ,需要声明,也需要实现
  • 可以有参数,可以发生重载

发送信号

  • 使用 “emit” 关键字发送信号。“emit” 是一个空的宏。“emit” 其实是可选的,没有什么含义,只是为了提醒开发人员

示例1:
在 widget.h 中声明自定义信号和槽,如图所示:
在这里插入图片描述
在 widget.cpp 中实现槽函数,并且关联信号和槽
在这里插入图片描述
运行
在这里插入图片描述

5 带参数的信号和槽

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

通过这样的机制,就可以让信号给槽传递数据了.

示例1:重载信号槽
在"widget.h"头文件中声明重载的信号函数以及重载的槽函数;如下图所示:
在这里插入图片描述

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

注意:在定义函数指针时要指明函数指针的作用域。

在这里插入图片描述
执行结果如下图所示:
在这里插入图片描述
示例2:信号槽参数列表匹配规则

在"widget.h"头文件中声明信号和槽函数;
在这里插入图片描述
在"widget.cpp"文件中实现槽函数以及连接信号和槽;
在这里插入图片描述

其实信号的参数个数可以多于槽函数的参数个数,但是槽的参数个数不能多于信号参数个数. 但是实际开发中最好还是保持参数个数也能匹配一致.

6 信号与槽的连接方式

一对一
主要有两种形式,分别是:一个信号连接一个槽和一个信号连接一个信号。
一个信号连接一个槽
在这里插入图片描述
示例:
在"widget.h"中声明信号和槽以及信号发射函数;
在这里插入图片描述
在"widget.cpp"中实现槽函数,信号发射函数以及连接信号和槽;
在这里插入图片描述
一个信号连接另一个信号
在这里插入图片描述
示例:
在.上述示例的基础上,在"widget.cpp"文件中添加如下代码:
在这里插入图片描述

一对多
一个信号连接多个槽
在这里插入图片描述
示例:
在"widget.h"头文件中声明一个信号和三个槽;
在这里插入图片描述
在"widget.cpp"文件中实现槽函数以及连接信号和槽;
在这里插入图片描述
多对一

多个信号连接一个槽函数
在这里插入图片描述
示例:
在"widget.h"头文件中声明两个信号以及一个槽;
在这里插入图片描述
在"widget.cpp"文件中实现槽函数以及连接信号和槽;
在这里插入图片描述

7 信号与槽的断开

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

示例:
在这里插入图片描述

8 使用 Lambda 表达式来定义槽函数

Lambda 表达式具体的语法规则可以查看这篇文章 Lambda表达式,本节简单介绍一下。

Qt5在Qt4的基础上提高了信号与槽的灵活性,允许使用任意函数作为槽函数。
但如果想方便的编写槽函数,比如在编写函数时连函数名都不想定义,则可以通过Lambda表达式来达到这个目的。

Lambda表达式是C++11增加的特性。C++11 中的Lambda表达式用于定义并创建匿名的函数对
象,以简化编程工作。
Lambda表达式的语法格式如下:

[ capture ] ( params ) opt -> ret { Function body; 
};

在这里插入图片描述
局部变量引入方式 [ ]
[ ]:标识一个Lambda表达式的开始。不可省略。

在这里插入图片描述

  • 由于使用引用方式捕获对象会有局部变量释放了而L ambda函数还没有被调用的情况。如果执行Lambda函数,那么引用传递方式捕获进来的局部变量的值不可预知。所以绝大多数场合使用的形式为:={}
  • 早期版本的Qt,若要使用Lambda表达式,要在"pro"文件中添加:
CONFIG += C++11

因为Lambda表达式是C++11标准提出的。Qt5 以上的版本无需手动添加,在新建项目时会自动添加。

在这里插入图片描述
示例:Lambda 表达式的使用

使用 Lambda 表达式的方式填写槽函数。这里的功能是点击一下按钮,按钮就移动到相应位置。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

实时时钟芯片DS1307单片机C语言驱动程序

实时时钟RTC相关索引 1.单片机RTC及时钟芯片的时间到底从哪一年起始&#xff1f; 2.STM32F103单片机内部RTC实时时钟驱动程序 3.实时时钟芯片DS1302单片机C语言驱动程序 4.实时时钟芯片DS1307单片机C语言驱动程序 一、DS1307简介 DS1307是一款非易失性实时时钟&#xff08;R…

【Java程序设计】【C00209】基于SSM个人求职管理系统(论文+PPT)

基于SSM个人求职管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这个一个基于SSM的个人求职管理系统&#xff0c;本系统共分为三种权限&#xff1a;管理员、普通管理员、用户 管理员&#xff1a;首页、个人中心、用户管理、管理…

go并发编程-介绍与Goroutine使用

1. 并发介绍 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中的多个…

Go语言的100个错误使用场景(11-20)|项目组织和数据类型

前言 大家好&#xff0c;这里是白泽。 《Go语言的100个错误以及如何避免》 是最近朋友推荐我阅读的书籍&#xff0c;我初步浏览之后&#xff0c;大为惊喜。就像这书中第一章的标题说到的&#xff1a;“Go: Simple to learn but hard to master”&#xff0c;整本书通过分析100…

DevSecOps 参考模型介绍

目录 一、参考模型概述 1.1 概述 二、参考模型分类 2.1 DevOps 组织型模型 2.1.1 DevOps 关键特性 2.1.1.1 模型特性图 2.1.1.2 特性讲解 2.1.1.2.1 自动化 2.1.1.2.2 多边协作 2.1.1.2.3 持续集成 2.1.1.2.4 配置管理 2.1.2 DevOps 生命周期 2.1.2.1 研发过程划分…

leetcode刷题(剑指offer)54.螺旋矩阵

54.螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入&#xff1a;ma…

Java基础-集合框架

集合框架&#xff1a; 内存层面可考虑的数据存储容器&#xff1a;数组&#xff0c;集合 数组的特点&#xff1a;长度&#xff0c;存储元素类型确定&#xff0c;既可以放基本数据类型&#xff0c;也可以放引用数据类型 缺点&#xff1a;长度不可变&#xff0c;存储元素特点单…

从零开始 Linux(一):基础介绍与常用指令总结

从零开始 Linux 01. 概念理解 1.1 什么是 Linux&#xff1f; Linux 是一个开源免费的 操作系统&#xff0c;具有很好的稳定性、安全性&#xff0c;且有很强的处理高并发的能力 Linux 的应用场景&#xff1a; 可以在 Linux 下开发项目&#xff0c;比如 JavaEE、大数据、Python…

3D词云图

工具库 tagcanvas.min.js vue3&#xff08;框架其实无所谓&#xff0c;都可以&#xff09; 实现 <script setup> import { onMounted, ref } from vue; import ./tagcanvas.min.js;const updateFlag ref(false);// 词云图初始化 const initWordCloud () > {let …

RabbitMQ快速实战

目录 什么是消息队列&#xff1f; 消息队列的优势 应用解耦 异步提速 削峰填谷 总结 主流MQ产品特点比较 Rabbitmq快速上手 创建用户admin Exchange和Queue Connection和Channel RabbitMQ中的核心概念总结 什么是消息队列&#xff1f; MQ全称Message Queue&#xf…

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入) 反转(转移)控制(IOC Inverse of Control) 控制&#xff1a;对于成员变量赋值的控制权 反转控制&#xff1a;把对于成员变量赋值的控制权&#xff0c;从代码中反转(转移)到Spring⼯⼚和配置⽂件中完成好处&#xff1a;…

七、并发工具(上)

一、自定义线程池 1&#xff09;背景&#xff1a; 在 QPS 量比较高的情况下&#xff0c;我们不可能说所有的访问都创建一个线程执行&#xff0c;这会导致内存占用过高&#xff0c;甚至有可能出现 out of memory另外也要考虑 cpu 核数&#xff0c;如果请求超过了cpu核数&#…

【bitonicSort学习】

bitonicSort学习 什么是Bitonic Sort核心 什么是Bitonic Sort https://zhuanlan.zhihu.com/p/53963918 这个是用来并行排序的一个操作 之前学过一些CPU排序&#xff0c;快排 冒泡 归并啥的&#xff0c;有一些能转成并行&#xff0c;有一些不适合 像快排这种二分策略就可以考虑…

Vue3的自定义指令怎么迁移到nuxt3

一、找到Vue3中指令的源码 const DISTANCE 100; // 距离 const ANIMATIONTIME 500; // 500毫秒 let distance: number | null null,animationtime: number | null null; const map new WeakMap(); const ob new IntersectionObserver((entries) > {for (const entrie…

草图导入3d后模型贴材质的步骤?---模大狮模型网

3D模型在导入草图大师后出现混乱可能有多种原因&#xff0c;以下是一些可能的原因和解决方法&#xff1a; 模型尺寸问题&#xff1a;如果3D模型的尺寸在导入草图大师时与画布尺寸不匹配&#xff0c;可能导致模型混乱。解决方法是在3D建模软件中调整模型的尺寸&#xff0c;使其适…

FreeRTOS使用计数信号量进行任务同步与资源管理

FreeRTOS使用计数信号量进行任务同步与资源管理 介绍 在多任务系统中&#xff0c;任务之间的同步和对共享资源的管理是非常重要的。FreeRTOS 提供了丰富的同步机制&#xff0c;其中计数信号量是一种强大的工具&#xff0c;用于实现任务之间的同步和对资源的访问控制。 什么是…

figure方法详解之清除图形内容

figure方法详解之清除图形内容 一 clf():二 clear():三 clear()方法和clf()方法的区别&#xff1a; 前言 Hello 大家好&#xff01;我是甜美的江。 在数据可视化中&#xff0c;Matplotlib 是一个功能强大且广泛使用的库&#xff0c;它提供了各种方法来创建高质量的图形。在 Mat…

unity 拖入文件 窗口大小

目录 unity 拖入文件插件 设置窗口大小 unity 拖入文件插件 GitHub - Bunny83/UnityWindowsFileDrag-Drop: Adds file drag and drop support for Unity standalong builds on windows. 设置窗口大小 file build

Iceberg从入门到精通系列之二十一:Spark集成Iceberg

Iceberg从入门到精通系列之二十一&#xff1a;Spark集成Iceberg 一、在 Spark 3 中使用 Iceberg二、添加目录三、创建表四、写五、读六、Catalogs七、目录配置八、使用目录九、替换会话目录十、使用目录特定的 Hadoop 配置值十一、加载自定义目录十二、SQL 扩展十三、运行时配置…

电子电器架构——车载网关转发buffer心得汇总

电子电器架构——车载网关转发buffer心得汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力…