[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 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中的按钮触发事件。

运行:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

高效使用 cursor

设置 cursor 基础规则: 在 settings > General > Rules for AI 中设置自定义规则,以后 cursor 生成代码会基于该规则生成; 如果要编写复杂代码,可以在项目根目录创建一个 .cursorrules 文件,设置复杂的规则&…

【Kafka 消息队列深度解析与应用】

Kafka 消息队列深度解析与应用 一、Kafka 概述 (一)产生背景 Kafka 最初是由 LinkedIn 开发,旨在解决其内部海量数据的实时传输问题。在现代大数据环境下,企业需要处理海量的数据流入和流出,包括用户的行为数据、系…

【无线传感网】无线传感器网络覆盖技术

文章目录 覆盖算法设计思路及性能评价标准覆盖感知模型布尔感知模型概率感知模型 无线传感网络覆盖算法分类按照配置方式确定性覆盖随机性覆盖 根据覆盖目标面覆盖点覆盖栅栏覆盖 典型的WSN覆盖算法与协议基于网格的覆盖定位传感器配置算法圆周覆盖连通传感器覆盖轮换活跃/休眠…

canvas+fabric实现时间刻度尺(二)

前言 我们前面实现了时间刻度尺&#xff0c;鼠标移动显示时间&#xff0c;接下来我们实现鼠标点击某个时间进行弹框。 效果 实现 1.监听鼠标按下事件 2.编写弹框页面 3.时间转换 <template><div><canvas id"rulerCanvas" width"1200"…

Python-MNE-源空间和正模型04:头模型和前向计算

我们知道&#xff0c;在MNE分析中坐标是很重要的&#xff0c;这个前面也提及过了配准的一些方法&#xff0c;总的来说&#xff0c;MNE和freesurfer中使用的配准系统以及他们之间的关系如下图所示&#xff1a;除了传感器坐标之外&#xff0c;所有的坐标系都是笛卡尔坐标系&#…

Linux 内核调试

系列文章目录 Linux内核学习 Linux 知识 QEMU 虚拟机 Linux 调试视频 近阶段补充知识 WSL Ubuntu 文章目录 系列文章目录一、WSL二、QEMU1、安装2、退出 三、构建根文件系统1、下载 BusyBox2、编译3、构建文件目录&#xff1a;Makefileinit 四、内核编译1、下载2、构建 五、调试…

SpringBoot 事务

前情提要 飞书的文档不好转移,可以直接看我的飞书:Docs 什么是事务 是一组操作的集合,是一个不可分割的操作 事物会将所有操作当作一个整体,同时对数据库进行操作请求,这些操作要么全部成功,要么全部失败 总会有一些操作,需要同步进行,这个时候就需要使用事务 数据库中,自…

汇川Easy系列正弦信号发生器(ST源代码)

正弦余弦信号发生器CODESYS和MATLAB实现请参考下面文章链接: 正弦余弦信号发生器应用(CODESYS ST源代码+MATLAB仿真)_st语言根据输入值,形成正弦点-CSDN博客文章浏览阅读410次。本文介绍了如何在CODESYS编程环境中创建正弦和余弦信号发生器。通过详细的PLC梯形图和SCL语言代码…

【JMeter详解】

JMeter详解 Apache JMeter 是一个开源的、100%纯Java应用程序&#xff0c;设计用于负载测试和性能测量。它最初是为测试Web应用程序而设计的&#xff0c;但后来扩展到其他测试功能。JMeter可以用来对静态和动态资源&#xff08;如静态文件、Servlets、Perl脚本、Java对象、数据…

uniapp:微信小程序文本长按无法出现复制菜单

一、问题描述 在集成腾讯TUI后&#xff0c;为了能让聊天文本可以复制&#xff0c;对消息组件的样式进行修改&#xff0c;主要是移除下面的user-select属性限制&#xff1a; user-select: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms…

查看 GitHub 仓库的创建时间

查看 GitHub 仓库的创建时间 1. https://api.github.com/repos/{owner}/{repository}2. curl -s https://api.github.com/repos/{owner}/{repository} | jq .created_atReferences 1. https://api.github.com/repos/{owner}/{repository} REST API endpoints for repositories…

VScode怎么重启

原文链接&#xff1a;【vscode】vscode重新启动 键盘按下 Ctrl Shift p 打开命令行&#xff0c;如下图&#xff1a; 输入Reload Window&#xff0c;如下图&#xff1a;

【无线传感网】WSN数据管理技术

文章目录 WSN数据管理的基本概念以数据为中心的WSN数据库与分布式数据库相比具有的特殊性WSN数据管理技术的研究热点 WSN数据管理的关键技术无线传感器网络数据存储结构网外集中式存储方案网内分层存储方案网内本地存储方案以数据为中心的网内存储方案 数据查询处理技术查询类型…

python调用gemini2.0接口识别图片文字

import os import base64 import google.generativeai as genai# 配置 Google API Key # 可以在系统环境变量设置 GOOGLE_API_KEY GOOGLE_API_KEY os.getenv("GOOGLE_API_KEY", "AIzaSXXXXXXXXXXXXXX") # 替换成你的 API Key# 设置 Gemini 模型名称 mode…

Linux Debian安装ClamAV和命令行扫描病毒方法,以及用Linux Shell编写了一个批量扫描病毒的脚本

ClamAV是一个开源的跨平台病毒扫描引擎&#xff0c;用于检测恶意软件、病毒、木马等安全威胁。 一、Linux Debian安装ClamAV 在Linux Debian系统上安装ClamAV&#xff0c;你可以按照以下步骤进行&#xff1a; 更新软件包列表&#xff1a; 打开终端并更新你的软件包列表&#…

【机器学习篇】穿越数字迷雾:机器深度学习的智慧领航

引言&#xff1a; 在当今科技飞速发展的时代&#xff0c;机器深度学习已成为推动众多领域变革的核心力量&#xff0c;从语音识别到图像分类&#xff0c;从自然语言处理到自动驾驶&#xff0c;其影响力无处不在。深度学习模拟人类大脑的神经网络结构&#xff0c;使计算机能够自…

CAN总线波形中最后一位电平偏高或ACK电平偏高问题分析

参考&#xff1a;https://zhuanlan.zhihu.com/p/689336144 有时候看到CAN总线H和L的差值波形的最后一位电平会变高很多&#xff0c;这是什么原因呢&#xff1f; 实际上这是正常的现象&#xff0c;最后一位是ACK位。问题描述为&#xff1a;CAN总线ACK电平偏高。 下面分析下原因…

B2B营销的新篇章:开源AI智能名片S2B2C商城小程序的应用探索

摘要&#xff1a; B2B营销&#xff0c;作为企业间营销活动的总称&#xff0c;因其独特的业务特性而呈现出不同于B2C营销的显著特征。在数字化转型的大潮中&#xff0c;B2B企业正积极探索新的营销手段以提高效率和竞争力。本文旨在探讨B2B营销的基本特性&#xff0c;并重点引入…

Kotlin在医疗大健康域的应用实例探究与编程剖析(上)

一、引言 1.1 研究背景与意义 在当今数字化时代,医疗行业正经历着深刻的变革。随着信息技术的飞速发展,尤其是人工智能、大数据、物联网等新兴技术的广泛应用,医疗行业数字化转型已成为必然趋势。这种转型旨在提升医疗服务的效率和质量,优化医疗资源配置,为患者提供更加…

【电机控制】基于STC8H1K28的六步换向——方波驱动(软件篇)

【电机控制】基于STC8H1K28的六步换向——方波驱动&#xff08;软件篇&#xff09; 文章目录 [TOC](文章目录) 前言一、main.c二、GPIO.c三、PWMA.c四、ADC.c五、CMP.c六、Timer.c七、PMSM.c八、参考资料总结 前言 【电机控制】STC8H无感方波驱动—反电动势过零检测六步换向法 …