[Qt] 信号和槽(1) | 本质 | 使用 | 自定义

news2025/1/5 6:16:53

目录

一、信号和槽概述

二、本质

底层实现

1. 函数间的相互调用

2. 类成员中的特殊角色

三、使用

四. 自定义信号和槽

1. 基本语法

(1) 自定义信号函数书写规范

(2) 自定义槽函数书写规范

(3) 发送信号

(4) 示例

A. 示例一

B. 示例二 —— 老师说“上课了”,学生回到座位学习

C. 示例三 —— 老师点击按钮触发学生上课


一、信号和槽概述

  • 事件与信号
    • 在 Qt 中,用户与控件的交互(如点击按钮或关闭窗口)产生事件,每个事件触发相应的信号。
    • 信号是事件的通知形式,通过函数表示。
  • 响应与槽
    • 控件接收信号并作出响应动作,称为槽。
    • 槽为普通 C++ 函数,可定义在类的不同访问级别中,并能被关联到一个或多个信号上自动执行。


二、本质

1. 信号的本质

信号本质上是事件,由用户操作触发,通过特定函数形式通知开发者。

例如:

  • 按钮单击、双击
  • 鼠标移动、鼠标按下、鼠标释放
  • 键盘输入

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

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

2. 槽的本质

槽是回调函数,用于响应信号,当关联的信号发射时,槽函数会被自动调用。

关于 回调函数

C 语言阶段 - 函数指针

  • 实现转移表,降低代码的 “圈复杂度”
  • 实现回调函数效果(qsort)

C++ 阶段

  • STL 中,函数对象 / 仿函数
  • lambda 表达式

Linux

  • 信号处理函数
  • 线程的入口函数
  • epoll 基于回调的机制

底层实现

1. 函数间的相互调用

在Qt框架中,信号和槽机制本质上是通过函数间的相互调用来实现的。具体来说:

  • 信号函数:每个信号都可以用一个函数来表示。例如,“按钮被按下”的事件可以用clicked()信号函数来表示。
  • 槽函数:同样地,每个槽也可以用一个函数表示,比如“窗口关闭”的动作可以用close()槽函数来表示。

当使用信号和槽机制来实现特定功能时,如点击按钮关闭窗口,实际上是在连接clicked()信号与close()槽函数,使得点击按钮(触发clicked())会导致窗口关闭(执行close())的效果。

2. 类成员中的特殊角色

信号函数和槽函数通常位于某个类中,但它们与普通成员函数相比有一些特别之处:

  • 修饰关键字

这些关键字是Qt对C++语言的扩展,专门用于标识信号和槽函数

    • 信号函数使用signals关键字进行修饰。
    • 槽函数则使用public slotsprotected slotsprivate slots关键字修饰。
  • 声明与定义
    • 信号函数只需要声明而无需定义;其定义由Qt自动处理,这种自动生成代码的机制称为 “ 元编程(Meta Programming),这种操作在很多场景中都能见到。
    • 槽函数需要像普通函数一样定义和实现,因为它们包含了具体的响应逻辑。

三、使用

1. 连接信号和槽

  • QObject 是 Qt 内置的父类,Qt 中提供的很多类都是直接或者间接继承自 QObject。(在 Java 中也存在相似的设定)
  • 使用 QObject::connect() 函数关联信号与槽,指定发送者、信号类型、接收者及方法。
connect (const QObject *sender,    //描述当前信号是哪个控件发出的
        const char * signal ,      //信号类型
        const QObject * receiver , //信号如何处理(哪个对象处理)
        const char * method ,      //信号如何处理(这个对象该怎么处理——要处理信号的对象提供的成员函数)
        Qt::ConnectionType type = Qt::AutoConnection ) //暂时不考虑,很少使用

参数说明

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

示例:

在窗口中设置一个按钮,当点击 “按钮” 时关闭 “窗口”:

tip:

2. 查看内置信号和槽

  • 利用 Qt 帮助文档查询系统自带的信号和槽,通常在类或其父类中查找。

如上述示例,要查询 “按钮” 的信号,在帮助文档中输入:QPushButton

首先可以在 "Contents" 中寻找关键字 signals如果没有找到,继续去父类中查找,因此我们去他的父类 QAbstractButton 中继续查找关键字 signals

这里的 clicked() 就是我们要找的信号。槽函数的寻找方式和信号一样,只不过它的关键字是 slot。


3. 通过 Qt Creator 生成代码

  • Qt Creator 提供可视化界面帮助快速生成信号槽代码,简化开发流程。

示例:点击按钮关闭窗口

  • 新建项目并创建 UI 文件。
  • 在 UI 设计界面添加按钮并配置属性。

可视化生成槽函数

当鼠标单击 “转到槽...” 之后,出现如下界面:对于按钮来说,当点击时发送的信号是:clicked(),所以此处选择:clicked()

这个窗口列出了 QPushButton 给我们提供的所有信号(还包含了 QPushButton 父类的信号)。

对于普通按钮来说,使用 clicked 信号即可。

clicked(bool) 没有意义的,具有特殊状态的按钮(比如:复选按钮)才会用到 clicked(bool)。

  • 然后 就会跳转到 Qt Creator 自动生成槽函数原型框架,并在槽函数中添加关闭窗口逻辑。

说明:自动生成槽函数的名称有一定的规则,槽函数的命名规则为:on_XXX_SSS,其中:

  1. 以 "on" 开头,中间使用下划线连接起来。
  2. "XXX" 表示的是对象名(控件的 objectName 属性)。
  3. "SSS" 表示的是对应的信号

如:"on_pushButton_clicked() ",pushButton 代表的是对象名,clicked 是对应的信号。按照这种命名风格定义的槽函数,就会被 Qt 自动的和对应的信号进行连接

但是我们日常写代码的时候,除非是 IDE 自动生成,否则最好还是不要去依赖命名规则,而是显式使用 connect 更好。

  • 一方面,显式 connect 可以更清晰直观的描述信号和槽的连接关系。
  • 另一方面,也是防止信号或者槽的名字拼写错误导致连接失效。

当然,是配置大于约定,还是约定大于配置,哪种更好。这样的话题业界尚存在争议,这里我个人还是更建议 日常优先考虑显式 connect。

"widget.cpp" 中自动生成槽函数定义 ,在槽函数函数定义中添加要实现的功能,实现关闭窗口的效果


四. 自定义信号和槽

1. 基本语法

在 Qt 中,允许开发者自定义信号的发送方及接收方,即 可以定义自己的信号函数和槽函数。为了实现这一点,必须遵循一定的 书写规范。

  • Q_OBJECT 宏
    • 在类中使用信号槽机制的前提是类最开始处需要声明Q_OBJECT宏。这个宏展开大量代码,使编译器能够识别并处理信号和槽。
    • Qt Creator通常会自动添加此宏。

(1) 自定义信号函数书写规范

规范要点

  • 自定义信号较少见,因为Qt内置信号已足够满足大多数需求。
  • 信号本质上是特殊的函数,仅需声明无需实现,返回类型为void
  • 可以有参数,并支持重载。
  • 必须放在signals关键字下,这是Qt扩展的关键字,用于标识信号。

构建过程

头文件的 关键字下 定义

  • qmake工具在构建项目时会扫描到signals关键字,并自动生成相应的函数定义。
(2) 自定义槽函数书写规范
  • 操作规程
    1. 槽函数的定义与普通成员函数无异,但早期版本要求槽函数必须位于public slotsprotected slotsprivate slots下。
    2. 现代版本允许槽函数放置于public作用域中或全局范围内。
    3. 返回类型为void,需要声明和实现,支持参数和重载。
  • slots 关键字

    • 同样是Qt扩展的关键字,用于指示qmake生成相关代码。
    • 我们上面有提到过,会进行 元编程
(3) 发送信号
  • 使用emit关键字来触发信号。
  • 尽管emit是一个空宏且可选,但它有助于提醒开发人员当前正在发射信号。
(4) 示例
A. 示例一
  • widget.h中声明自定义信号和槽。

  • widget.cpp中实现槽函数,并连接信号和槽。

运行

B. 示例二 —— 老师说“上课了”,学生回到座位学习
  • 创建老师类和学生类,分别声明信号和槽。

在源文件中新建两个类,一个是老师类,一个是学生类;首先选中项目名称,鼠标右键 ——> "add new..."

注意:在 Qt 中新建类时,要选择新建类的父类。

  • 显然,当前项目中还没有什么类适合做新类的父类,同时新的类也不是一个 “窗口” 或者 “控件”,这种情况一般选择 QObject 作为基类。
  • 这样做的好处是这个新类的对象可以搭配 Qt 的对象树机制,便于对象的正确释放。

对于 “学生类” 以上述同样的方式进行添加,添加完成之后,项目目录新增文件如下:

  • widget.h中实例化这两个类的对象。

  • student.cpp中实现槽函数。

  • widget.cpp中连接信号和槽。

运行

C. 示例三 —— 老师点击按钮触发学生上课
  • 实现逻辑同上,通过UI中的按钮触发事件。

运行:

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

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

相关文章

2024 年发布的 Android AI 手机都有什么功能?

大家好,我是拭心。 2024 年是 AI 快速发展的一年,这一年 AI 再获诺贝尔奖,微软/苹果/谷歌等巨头纷纷拥抱 AI,多款强大的 AI 手机进入我们的生活。 今年全球 16% 的智能手机出货量为 AI 手机,到 2028 年,这…

Mac连接云服务器工具推荐

文章目录 前言步骤1. 下载2. 安装3. 常用插件安装4. 连接ssh测试5. 连接sftp测试注意:ssh和sftp的区别注意:不同文件传输的区别解决SSL自动退出 前言 Royal TSX是什么: Royal TSX 是一款跨平台的远程桌面和连接管理工具,专为 mac…

StarRocks 存算分离在得物的降本增效实践

编者荐语: 得物优化数据引擎布局,近期将 4000 核 ClickHouse 迁移至自建 StarRocks,成本降低 40%,查询耗时减半,集群稳定性显著提升。本文详解迁移实践与成果,文末附丁凯剑老师 StarRocks Summit Asia 2024…

【操作系统进程与线程管理:从PCB到多线程并发编程】

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​💫个人格言:“没有罗马,那就自己创造罗马~” 文章目录 操作系统管理进程PCB核心属性线程&多线程编程为什么线程比进程更轻量?为什么线程创…

超越TF-IDF:信息检索之BM25

深入解析BM25:信息检索的优化利器 搜索系列相关文章(置顶) 1.原始信息再加工:一文读懂倒排索引 2.慧眼识词:解析TF-IDF工作原理 3.超越TF-IDF:信息检索之BM25 4.深入浅出 Beam Search:自然语言处…

C#控件开发4—仪表盘

目录 思路(GDI绘图)1.定义属性2.绘制图形3.最后生成(自定义各种监控值显示)End 如何让温度、湿度、压力等有量程的监控值如仪表盘(DashBoard)一样显示? 思路(GDI绘图) 定…

提升口语发音水平,中英文发音评测系统实现

在全球化的浪潮中,语言不再是障碍,而是连接世界的桥梁。掌握一门流利的英语,意味着打开了通往世界的大门。但是,如何确保你的英语口语如同母语者一样自然流畅?这正是我们存在的意义。 我们的中英文口语发音评测服务&a…

JVM对象创建过程

1 类加载检查 jvm通过new指令开始创建对象jvm执行new指令时,首先通过指令参数从常量池中取到需要创建的类名检查该类是否被加载,解析,和初始化过如果没有,则执行类的加载过程new指令对应到java语言具体的操作为 new 关键字创建对象…

什么是Sight Words(信号词)

🧡什么是Sight Words(信号词) 简单来说,Sight Words就是我们在日常英语中常用的一些基本词汇。可以把它想象成是学练英语的“基础词汇”,这些词在各种考试中经常出现,也是在生活中必不可少的。 &#x1f…

秒鲨后端之MyBatis【3】自定义映射resultMap、动态SQL、MyBatis的缓存、MyBatis的逆向工程、分页插件(30000字)

这里我分享一下尚硅谷的pdf100页笔记和代码,大家可以参考学习。 笔记: 通过网盘分享的文件:MyBatis.pdf 链接: https://pan.baidu.com/s/14Iu1Zs-_5vZoRjBEjmagag?pwdyjh6 提取码: yjh6 --来自百度网盘超级会员v1的分享代码: …

12.31【Linux】shell脚本【运行方式,修改环境变量,数组】思维导图 内附练习

1.思维导图 2练习: 1.尝试将下列指令放到脚本中运行 在家目录下创建目录文件dir1,把/etc/passwd拷贝到dir1中,把/etc/group拷贝到dir1中并重命名为grp.txt,使用tree指令,显示dir1目录的文件树,把dir1&am…

云计算学习架构篇之HTTP协议、Nginx常用模块与Nginx服务实战

一.HTTP协议讲解 1.1rsync服务重构 bash 部署服务端: 1.安装服务 [rootbackup ~]# yum -y install rsync 2.配置服务 [rootbackup ~]# vim /etc/rsyncd.conf uid rsync gid rsync port 873 fake super yes use chroot no max connections 200 timeout 600 ignore erro…

【项目】智能BI洞察引擎 测试报告

目录 一、项目背景BI介绍问题分析项目背景 二、项目功能三、功能测试1、登录测试测试用例测试结果 2、注册测试测试用例测试结果出现的bug 3、上传文件测试测试用例测试结果 4、AI生成图表测试测试用例测试结果 5、分析数据页面测试(异步)测试用例测试结…

权限菜单之菜单管理 SpringBoot + VUE

一、 数据表设计 新建表sys_menu 表内数据 添加实体类Menu package com.example.demo.demos.web.demo.entity;import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.Ta…

【AIGC篇】AIGC 引擎:点燃创作自动化的未来之火

:羑悻的小杀马特.-CSDN博客 未来都是惊喜。你生来本应为高山。并非草芥。 引言: 在当今数字化的时代,人工智能生成内容(AIGC)正以一种前所未有的力量改变着我们的创作领域。它就像一个神秘而强大的魔法师,…

UnityRenderStreaming使用记录(三)

测试UnityRenderStreaming在Ubuntu24.04.1LTS上的表现 先放上运行图操作系统 Ubuntu24.04.1LTSUnity测试工程环境相关修改遇到的问题 先放上运行图 操作系统 Ubuntu24.04.1LTS 系统下载地址 https://cn.ubuntu.com/download/desktop安装UnityHub https://blog.csdn.net/AWNUXC…

从0开始的docker镜像制作-ubuntu22.04

从0开始的docker镜像制作-ubuntu22.04 一、拉取基础ubuntu22.04镜像二、进入拉取的docker镜像中,下载自己需要的安装包三、安装需要的系统软件四、打包现有镜像为一个新的镜像五、推送打包的镜像到私有docker服务器1.编辑docker文件,使其允许http传输和对…

多模态论文笔记——CogVLM和CogVLM2(副)

大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍多模态模型的LoRA版本——CogVLM和CogVLM2。在SD 3中使用其作为captioner基准模型的原因和优势。 文章目录 CogVLM论文背景VLMs 的任务与挑战现有方法及…

gitlab-runner的卸载与安装

如果你使用rpm方式安装gitlab-runner,则可以参考本教程。 卸载 停止和卸载gitlab-runner 停止 gitlab-runner stopchkconfig gitlab-runner off卸载 gitlab-runner uninstall删除rpm包 查询出rpm包名,根据包名删除rpm。 [rootEuler02 ~]# rpm -qa …

Nacos配置中心总结

Nacos配置中心总结 Nacos配置文件的加载顺序和优先级 加载顺序 nacos作为配置中心时,需要在bootstrap.yml文件中添加nacos config相关的配置,这样系统启动时就能先去拉取nacos server上的配置了。拉取过来后会和本地配置文件进行合并。 bootstrap.ym…