[Qt] 信号和槽(1) | 本质 | 使用 | 自定义
目录
一、信号和槽概述
二、本质
底层实现
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 slots
、protected slots
或private 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,其中:
- 以 "on" 开头,中间使用下划线连接起来。
- "XXX" 表示的是对象名(控件的 objectName 属性)。
- "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) 自定义槽函数书写规范
- 操作规程:
-
- 槽函数的定义与普通成员函数无异,但早期版本要求槽函数必须位于
public slots
、protected slots
或private slots
下。 - 现代版本允许槽函数放置于
public
作用域中或全局范围内。 - 返回类型为
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中的按钮触发事件。
运行:
相关文章:

[Qt] 信号和槽(1) | 本质 | 使用 | 自定义
目录 一、信号和槽概述 二、本质 底层实现 1. 函数间的相互调用 2. 类成员中的特殊角色 三、使用 四. 自定义信号和槽 1. 基本语法 (1) 自定义信号函数书写规范 (2) 自定义槽函数书写规范 (3) 发送信号 (4) 示例 A. 示例一 B. 示例二 —— 老师说“上课了”&…...
33. 简易内存池
1、题目描述 ● 请实现一个简易内存池,根据请求命令完成内存分配和释放。 ● 内存池支持两种操作命令,REQUEST和RELEASE,其格式为: ● REQUEST请求的内存大小 表示请求分配指定大小内存,如果分配成功,返回分配到的内存…...

win32汇编环境,对话框程序模版,含文本框与菜单简单功能
;运行效果 ;win32汇编环境,对话框程序模版,含文本框与菜单简单功能 ;直接抄进RadAsm可编译运行。 ;下面为asm文件 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&g…...

人工智能与传统编程的主要区别是什么?
传统编程:开发者预先编写软件行为规则,代码基于程序员定义逻辑处理输入并产生确定输出,具有确定性、手动编写规则和结构化逻辑特点,如垃圾邮件分类程序基于预设关键词等规则。AI 编程:从数据中学习而非手动编写规则&am…...
实战交易策略 篇十一:一揽子交易策略
文章目录 系列文章适用条件核心策略小额大量投资行业或主题聚焦同步操作优势系列文章 实战交易策略 篇一:奥利弗瓦莱士短线交易策略 实战交易策略 篇二:杰西利弗莫尔股票大作手操盘术策略 实战交易策略 篇三:333交易策略 实战交易策略 篇四:价值投资交易策略 实战交易策略…...

doris 2.1 -Data Manipulation-Transaction
注意:doris 只能控制读一致性,并不能rollback 1 Explicit and Implicit Transactions 1.1 Explicit Transactions 1.1.1 Explicit transactions require users to actively start, commit transactions. Only insert into values statement is supported in 2.1. BEGIN; …...

多模态融合:阿尔茨海默病检测
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、实验介绍 本实验包含 645 名阿尔茨海默病受试者,分为 AD、CN 和 MCI 组,数据集包含 3D MRI 图像与一份CSV数据,MRI数据…...

Ceph 手动部署(CentOS9)
#Ceph手动部署、CentOS9、squid版本、数字版本19.2.0 #部署服务:块、对象、文件 一、部署前规划 1、兼容性确认 2、资源规划 节点类型节点名称操作系统CPU/内存硬盘网络组件安装集群节点CephAdm01CentOS94U/8GOS:40G,OSD:2*100GIP1:192.169.0.9(管理&集群),IP2:…...

家政预约小程序05活动管理
目录 1 搭建活动管理页面2 搭建活动规则页面3 搭建规则新增页面3 配置规则跳转4 搭建活动参与记录总结 上一篇我们介绍了活动管理的表结构设计,本篇我们介绍一下后台功能。 1 搭建活动管理页面 我们一共搭建了三个表,先搭建主表的后台功能。打开我们的后…...
解决安装pynini和WeTextProcessing报错问题
点击这里,访问博客 0. 背景 最近在给别人有偿部署ASR-LLM-TTS项目时遇到安装pynini和WeTextProcessing依赖报错的问题,报错信息如下: IC:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" "-IC:\Program Files…...

【PCIe 总线及设备入门学习专栏 4.1 -- PCI 总线的地址空间分配】
文章目录 Overview 本文转自:https://blog.chinaaet.com/justlxy/p/5100053219 Overview PCI 总线具有32位数据/地址复用总线,所以其存储地址空间为 2324GB。也就是PCI上的所有设备共同映射到这4GB上,每个PCI设备占用唯一的一段PCI地址&…...

华为配置 之 RIP
简介: RIP(路由信息协议)是一种广泛使用的内部网关协议,基于距离向量算法来决定路径。它通过向全网广播路由控制信息来动态交换网络拓扑信息,从而计算出最佳路由路径。RIP易于配置和理解,非常适用于小型网络…...

探寻AI Agent:开启知识图谱自动生成新篇章(17/30)
一、AI Agent 与知识图谱:智能时代的双雄 在当今科技飞速发展的时代,人工智能如同一股汹涌澎湃的浪潮,正以前所未有的力量重塑着我们的世界。而在这股浪潮中,AI Agent 与知识图谱无疑是两颗最为璀璨的明珠,它们各自发挥…...

卸载wps后word图标没有变成白纸恢复
这几天下载了个wps教育版,后头用完了删了 用习惯的2019图标 给兄弟我干没了??? 其他老哥说什么卸载关联重新下 ,而且还要什么撤销保存原来的备份什么,兄弟也是不得不怂了 后头就发现了这个半宝藏博主&…...

LeetCode 热题 100_二叉树的直径(40_543_简单_C++)(二叉树;递归)
LeetCode 热题 100_二叉树的直径(40_543) 题目描述:输入输出样例:题解:解题思路:思路一(递归): 代码实现代码实现(思路一(递归)&#…...
【数据结构】线性数据结构——链表
1. 定义 链表是一种线性数据结构,由多个节点(Node)组成。每个节点存储数据和指向下一个节点的指针。与数组不同,链表的节点不需要在内存中连续存储。 2. 特点 动态存储: 链表的大小不固定,可以动态增加或…...

开源存储详解-分布式存储与ceph
ceph体系结构 rados:reliable, autonomous, distributed object storage, rados rados采用c开发 对象存储 ceph严格意义讲只提供对象存储能力,ceph的块存储能力实际是基于对象存储库librados的rbd 对象存储特点 对象存储采用put/get/delete…...
[算法] [leetcode-509] 斐波那契数
509 斐波那契数 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) 0,F(1) 1 F(n) F(n - 1) F(n - 2),其中 n…...
运维人员的Go语言学习路线
以下是一份更为详细的适合运维人员的Go语言学习路线图: 一、基础环境搭建与入门(第 1 - 2 周) 第 1 周 环境搭建 在本地开发机和常用的运维服务器环境(如 Linux 系统)中安装 Go 语言。从官方网站(https://…...

[创业之路-222]:波士顿矩阵与GE矩阵在业务组合选中作用、优缺点比较
目录 一、波士顿矩阵 1、基本原理 2、各象限产品的定义及战略对策 3、应用 4、优点与局限性 二、技术成熟度模型与产品生命周期模型的配对 1、技术成熟度模型 2、产品生命周期模型 3、技术成熟度模型与产品生命周期模型的配对 三、产品生命周期与产品类型的对应关系 …...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...