QT跨平台应用程序开发框架(3)—— 信号和槽
目录
一,基本概念
二,connect函数使用
2.1 connect
2.2 Qt内置信号和槽
2.3 一些细节
三,自定义信号和槽
3.1 自定义槽函数
3.2 自定义信号
3.3 带参数的信号槽
四,信号和槽的意义
五,信号和槽断开连接
六,使用lamdba表达式定义槽函数
一,基本概念
- Qt中,用户和空间的每次交互过程我们称为一个事件,比如“点击按钮”和“关闭窗口”都是一个事件
- 每个事件发生时都会产生一个信号,比如点击按钮会产生“按钮被点击的信号”,用户关闭窗口会产生“窗口被关闭”的信号,这点我们前面已经介绍过,并且基本概念和Linux的信号有相似之处:Linux系统编程——进程信号-CSDN博客
在Qt中的信号主要涉及到三个要素:
- 信号源:由哪个空间发出
- 信号类型:用户进行不同的操作,就可能触发不同的信号
- 信号的处理方式:就是一个处理函数,这个处理函数在Qt中就叫做“槽函数”(slot),其实就是一个回调函数;Qt 可以用connect将一个信号和一个槽关联起来
注意:必须先把信号和槽用connect关联之后,再触发这个信号才会执行槽函数,顺序不能颠倒
二,connect函数使用
2.1 connect
这个函数是 QObject 类提供的一个静态成员函数
问题:为什么说是静态呢?
解答:
- 这个QObject 类是其它Qt内置类的“祖宗”
- 因为Qt的内置类有很多很多继承关系的,而绝大多数的类,往上深扒继承关系,最终都会看到有个 QObject类
- 所以在很多很多Qt内置内中,都可以直接使用connect这个函数
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跨平台应用程序开发框架(2)—— 初识QT-CSDN博客
上下面我们实现下点击按钮关闭窗口的代码:
这个close也是别人已经实现好了,作用就是关闭窗口,我们直接用就行
注意:我们在填第二个参数时会显示有两个click:
- 第一个click:左边小图标是锯齿的,表示这是一个slot函数,作用就是在调用的时候相当于点了一下按钮
- 第二个clicked:左边的是一个类似信号发射器的一个图标,这个表示信号;我们要选的是第二个,clicked表示过去式,就是“点完了”
2.2 Qt内置信号和槽
Qt 也提供了很多内置的信号和槽让我们使用,但是要想全部记住,几乎是不可能的,所以最好的方式就是多看文档,多写,所谓“熟能生巧”
在翻文档的时候,如果没有找到对应的条目,可以看看这个类的父类,并且文档也提供了这个类的父类叫什么,以QPushButton为例:
关于这个QAbstractButton类,首先 abstract 这个单词是“抽象的”的意思,因为Qt会提供好几种按钮,这些按钮 中存在一些功能相同的内容,所以就把这些相同的对东西搞出来,单独搞成了一个QAbstractButton这个类,其它很多控件类也是如此的
然后往下滑,就会看到一些内置的slot和signal,如果没有,就可以去父类看看,比如上面说到的QAbstractButton类,在它的页面往下滑,就可以看到:
再点击对应的绿色的,就能看到更多详细信息,比如clicked:
2.3 一些细节
我们再观察下connect函数的定义和使用:
问题:char* 和 函数指针是一个东西吗?
解答: 两个都是指针,但是不是同一个类型的指针
- 我们clicked函数的声明是:
- 所以指向这个函数的函数指针,也就是取地址后的指针就是 void(*)(),这个和char*是完全不同的,close同理;而在C++中,是不允许用两个不同类型的指针类型相互赋值的(函数传参,本质上就是赋值)
我们可以看下connect在文档中的声明:
这个函数声明是旧版本的Qt的connect的声明,所以在以前版本的传参和现在有区别:
- 给信号参数传参时,要搭配一个 SIGNAL 宏,主要是将传入的函数指针转成 char*
- 给槽函数传参时,要搭配一个 SLOT 宏,同上
所以旧版本需要进行的用法如下:
connect(button, SIGNAL(&QPushButton::clicked), this, SLOT(&Widget::close));
在Qt 5 开始,对上述操作进行了简化,去掉了两个宏,给connect提供了重载版本,第二个参数和第四个参数乘客泛型参数,允许传入任意类型的函数指针
这个就是Qt封装的一个类型萃取器,但是关于类型萃取,涉及模板特化等特性,这里不过多展开
有了泛型参数,此时这个connect函数就带有了一定的“参数检查”功能,如果传入的第一和第二或者第三和第四参数不匹配,那么代码就会直接编译出错,这个是宏做不到或者说很难做到的
三,自定义信号和槽
3.1 自定义槽函数
有时候Qt内置的信号和槽可能无法满足我们的需求,所以我们可以自己实现信号和槽,我们先说自定义槽
我们上篇文章已经用自定义槽实现了按按钮切换按钮里的文本:
所以所谓的槽函数,操作过程和自定义一个普通的成员函数没啥区别
除了上面这种最基础的,还有第二种更便捷的方法
先通过拖拽方式创建一个按钮,右键这个按钮,点击“转到槽”:
比如我实现一个切换窗口标题的按钮:
- 可以看到,我们通过这种方式生成的槽函数,并没有通过connect关联,因为在 Qt 中,除了通过connect 之外,还可以通过函数名字的方式来自动连接
- 比如上面的槽函数名字 on_pushButton_clicked ,on相当于固定前缀,中间的 pushButton 是按钮的 objectName ,后面的 clicked 就是信号的名字
- 所以当函数名符合上述规则之后,Qt就能自动把信号和槽进行关联
问题:如何做到自动识别的?
解答:我们把上面槽函数的声明和定义的clicked都换成click再次执行程序,可以看到输出有个:
而这个函数正是在 ui_widget.h 中调用的:
3.2 自定义信号
- 自定义槽函数非常重要,开发中大部分情况都是需要自定义槽函数的,因为槽函数就是用户触发某个操作之后要进行的业务逻辑,而业务逻辑通常是很复杂的,所以需要程序员自己去写
- 而对于自定义信号,就比较少见,实际开发中很少会需要自定义信号
- 因为信号对应着用户的某个操作,而在GUI中,用户能进行的操作是可以穷举的,Qt 内置的信号基本已经覆盖到了所有的用户操作
因此使用Qt 的内置信号,足以应付大部分的开发场景了,咱们的Widget虽然还没有定义任何信号,但是由于其继承了 QWidget 和 QBbject, 这里面已经提供了一些信号,可以直接用
但毕竟是大部分,那还有一小部分是内置信号解决不了的,所以Qt还是为我们提供了自定义信号的途径和方式
- 所谓 Qt 的信号,其实也是一个“函数”,槽函数和普通成员之间没啥差别
- 但是信号函数,则是一类非常特殊的函数,程序员只要写出函数声明并告诉 Qt 这是一个“信号”即可
- 这个函数的定义,是 Qt 在编译过程中自动生成的,并且这个过程我们无法干预
信号在 Qt 中是特殊的机制,Qt 生成的信号函数的实现,要配合 Qt 框架做很多既定的操作
然后关于信号函数声明:
- 信号函数的返回值必须是void
- 有没有参数都可以,甚至支持重载
在进行自定义信号创建之前,要明白几点:
- Qt 中内置的信号,都不需要通过咱们手动通过代码来触发,用户在 GUI 进行操作时,就会自动触发对应信号(发射信号的代码已经内置到 Qt 源码框架中了)
- 而对于我们的自定义信号,Qt 有个日俄欧美人你提供了一个关键字 emit ,也有发射的意思,具体用法下面代码会有演示
①首先是声明信号函数
②然后将自定义信号和自定义槽函数关联起来并使用emit关键字手动触发信号
③查看结果
emit手动触发信号的步骤可以在代码的任意位置,不一定非得在构造函数中
- 其实在 Qt 5 版本之后,emit现在其实啥也没干,真正的操作都包含在 mySignal 内部生成的函数定义中
- 就是上面的代码中不写emit,就写个mySignal() 相当于调用这个函数,一样可以完成触发信号
- 但即使如此,实际开发中建议加上emit,能增加代码可读性,标识这个语句是发射信号
- emit也可以手动发射Qt内置的信号
3.3 带参数的信号槽
- 信号和槽可以带参数,当信号带有参数的时候,槽的参数必须和信号的一致
- 此时发射信号的时候,就可以给信号函数传递实参,与之对应的这个参数就会被传递到对应的槽函数中,就可以起到让信号给槽传参效果了
①先在声明处带上参数(C++中形参的名字可以省略)
②给槽的定义带上参数
③查看结果
④也可以通过按钮来切换标题:
//通过拖拽方式创建按钮后,右键“转到槽”
void Widget::on_pushButton_clicked()
{emit mySignal("把标题设置为标题1");
}void Widget::on_pushButton_2_clicked()
{emit mySignal("把标题设置为标题2");
}
- Qt中很多内置的信号也是带有参数的,但是这些参数不是我们自己传的,比如 clicked 信号就有一个参数,是bool,表示当前按钮是否处于“选中”状态(对于QPushButton没啥作用,对QCheckBox复选框很有用,后期再讲)
- 信号函数的参数和槽参数数量可以不一致,但是信号参数数量需要 >= 槽的参数,否则会编译报错
问题:为什么允许信号参数数量 >= 槽参数个数 呢?
解答:
- 一个槽函数可能会绑定多个信号
- 如果我们严格要求参数个数一致,就意味着信号绑定槽的要求变高了,会有很多麻烦
- 换而言之,当下的规则就允许一个槽函数能够绑定更多的信号了
个数不一致,槽函数就会按照信号的参数顺序,拿到信号的前 N 个参数,总之就是要确保槽函数的每个参数是有值的
四,信号和槽的意义
信号和槽的主要面对的问题,就是“响应”用户的操作,执行一段业务逻辑(代码):
- Qt 的这种信号和槽,在各类 GUI 开发的框架中,是一个比较有特色的存在;这个有特色其实是贬义词,因为其它的 GUI 开发框架,搞的方式更简洁一些
- 网页开发中响应用户操作,主要就是挂“回调函数”,直接将函数赋值给对应的属性,不需要搞一个单独的connect完成上述的信号槽关联(大部分的 GUI 开发框架都是这样搞的)
Qt 这样的信号槽和connect机制,设想是这样的:
- 解耦合:把触发用户操作的控件 和 对应的处理逻辑进行解耦合
- “多对多”效果:比如一个信号可以 connect 到多个槽函数上,一个槽函数也可以被多个信号 connect
其实在GUI开发过程中,“多对多”其实是个伪需求,实际开发很少用到,绝大多数情况“一对一”够用了,而且新推出的一些图形化开发框架,很少有再继续支持这种多对多了
五,信号和槽断开连接
有连接就有断开,假设我们不再继续保持一个信号和槽的连接,那么可以使用 disconnect 函数来取消关联
- 但是disconnect用的是比较少的,大部分情况下把信号和槽连上之后就不必再管了
- 主动断开的场景往往是把信号重新绑定到另一个槽函数上
disconnect的用法和connect基本一致:
六,使用lamdba表达式定义槽函数
定义槽函数时,也可以用lamdba表达式的,lamdba表达式主要应用在“回调函数”场景中:C++ —— C++11新增语法-CSDN博客
废话不多说,直接上代码:
- 另外,我们也要确认捕获到 lamdba 内部的变量是有意义的,因为回调函数的执行时机是不确定的,所以就要保证无论用户点击了按钮,捕获到的变量都能正确使用
- lamdba 除了可以按照值得方式来捕获变量[=],也可以按照引用得方式来捕获[&],这时捕获到的一般就是各种控件的指针(但是Qt一般不用[&],因为可能会有很多意想不到的报错)
- 以上面的代码为例,如果是[&],那么运行后点击按钮就会报错,因为我们在构造函数里创建的button声明周期是随构造函数的,构造函数执行完后button就没了,这时候传递给lamdba的引用就是个空引用,直接闪退
- lamdba是C++11加入的,Qt 5 及更高版本默认就是按照C++11来编译的,如果使用Qt 4 或者更老版本,就需要在 .pro 文件里手动加上 C++11的编译选项哦
相关文章:

QT跨平台应用程序开发框架(3)—— 信号和槽
目录 一,基本概念 二,connect函数使用 2.1 connect 2.2 Qt内置信号和槽 2.3 一些细节 三,自定义信号和槽 3.1 自定义槽函数 3.2 自定义信号 3.3 带参数的信号槽 四,信号和槽的意义 五,信号和槽断开连接 六&…...

从 0 开始实现一个 SpringBoot + Vue 项目
从 0 开始实现一个 SpringBoot Vue 项目 从 0 开始实现一个 SpringBoot Vue 项目 软件和工具创建 SpringBoot 后端项目创建 MySQL 数据库配置文件实现增删改查接口 Model 层mapper 层service 层controller 层测试 实现项目功能接口 代码测试 创建 Vue 前端 安装 Node.js配置…...

【无标题】微调是迁移学习吗?
是的,微调(Fine-Tuning)可以被视为一种迁移学习(Transfer Learning)的形式。迁移学习是一种机器学习方法,其核心思想是利用在一个任务上学到的知识来改进另一个相关任务的性能。微调正是通过在预训练模型的…...

虚幻基础1:hello world
能帮到你的话,就给个赞吧 😘 文章目录 hello world创建项目创建关卡创建蓝图将蓝图插入关卡中运行 hello world 本文引擎为5.5.1 创建项目 如图 创建后如图。 创建关卡 如图 创建蓝图 如图 选择actor 双击进入蓝图节点 选择事件图表 创…...
C链表的一些基础知识
一、链表的基本概念 链表是一种常见的线性数据结构,它由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针(单链表情况)。通过指针将各个节点连接起来,与数组不同,链表在内存中的存储不是连续的…...

JDK长期支持版本(LTS)
https://blogs.oracle.com/java/post/the-arrival-of-java-23 jdk长期支持版本(LTS):JDK 8、11、17、21:...
【超详细】Python datetime(当前日期、时间戳转换、前一天日期等)【附:时区原理详解】
文章目录 相关文献当前时间前一天日期、后一天日期东八区(北京)时间时间戳转换datetime -> strstr -> datetimedatetime -> timestamp(时间戳)timestamp -> datetime 获取日期中的年、季度、月、周、日、小时、分、秒等时区原理时区问题复杂…...

【Excel】【VBA】双列排序:坐标从Y从大到小排列之后相同Y坐标的行再对X从小到大排列
Excel VBA 双列排序 功能概述 这段VBA代码实现了Excel中的双列排序功能,具体是: 跳过前3行表头先按C列数据从大到小排序在C列值相同的情况下,按B列从大到小排序排序时保持整行数据的完整性 流程图 #mermaid-svg-XJERemQluZlM4K8l {font-fa…...

为什么相关性不是因果关系?人工智能中的因果推理探秘
目录 一、背景 (一)聚焦当下人工智能 (二)基于关联框架的人工智能 (三)基于因果框架的人工智能 二、因果推理的基本理论 (一)因果推理基本范式:因果模型࿰…...
Nginx调优
Nginx 是一个高性能的反向代理服务器和负载均衡器,在处理大量并发请求时表现出色。但是,随着系统负载的增加,Nginx 的性能可能受到多方面的影响,因此进行适当的调优至关重要。以下是 Nginx 调优的几个方向和关键点: 1…...
联德胜w801开发板(四)实现腾讯云mqtt的订阅和发布
一、开发准备 在设备开发这里我们就能看到物模型的topic,跟之前用stm32esp8266一样 附上之前的链接: STM32ESP8266连接腾讯IOT上传数据(四)_stm32通过esp8266上传数据到云平台-CSDN博客https://blog.csdn.net/Try1harder/article/details/134914027?…...

LLM框架对比选择:MaxKB、Dify、FastGPT、RagFlow【RAG+AI工作流+Agent]
1.MaxKB MaxKB Max Knowledge Base,是一款基于 LLM 大语言模型的开源知识库问答系统,旨在成为企业的最强大脑。它能够帮助企业高效地管理知识,并提供智能问答功能。想象一下,你有一个虚拟助手,可以回答各种关于公司内…...

C语言内存之旅:从静态到动态的跨越
大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文一 动态内存管理的必要性二 动态…...
研1如何准备才能找到大厂实习?
研1如何准备才能找到大厂实习? 写在前面 2024已经走向尾声,迎来了我的2025,这一年我有许多难忘的回忆和经验想要分享给大家,希望对您能有所帮助和启发,希望准备找工作的同学可以少走一些弯路。 我深知目前就业压力大…...

游戏为什么失败?回顾某平庸游戏
1、上周玩了一个老鼠为主角的游戏,某平台喜1送的, 下载了很久而一直没空玩,大约1G,为了清硬盘空间而玩。 也是为了拔掉心中的一根刺,下载了而老是不玩总感觉不舒服。 2、老鼠造型比较写实,看上去就有些讨…...

QT 使用QTableView读取数据库数据,表格分页,跳转,导出,过滤功能
文章目录 效果图概述功能点代码分析导航栏表格更新视图表格导出表格过滤 总结 效果图 概述 本案例用于对数据库中的数据进行显示等其他操作。数据库的映射,插入等功能看此博客框架:数据模型使用QSqlTableModel,视图使用QTableView࿰…...

【前端】CSS学习笔记(1)
目录 CSS的简介CSS的概念语法 CSS的引入方式内联样式(行内样式)内部样式外部样式(推荐) 选择器全局选择器元素选择器类选择器ID选择器合并选择器后代选择器子选择器相邻兄弟选择器通用兄弟选择器伪类选择器:link:visited:hover:ac…...

Ubuntu离线docker compose安装DataEase 2.10.4版本笔记
1、先准备一个可以正常上网的相同版本的Ubuntu系统,可以使用虚拟机。Ubuntu系统需要安装好docker compose或docker-compose 2、下载dataease-online-installer-v2.10.4-ce.tar在线安装包,解压并执行install.sh进行安装和启动 3、导出docker镜像 sudo d…...

C 语言雏启:擘画代码乾坤,谛观编程奥宇之初瞰
大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。* 这一课主要是让大家初步了解C语言,了解我们的开发环境,main函数,库…...
npm操作大全:从入门到精通
引言 在现代前端开发中,npm(Node Package Manager)是不可或缺的工具。无论是安装依赖、管理项目,还是发布自己的包,npm都扮演着重要的角色。本文将带你从npm的基础操作开始,逐步深入到高级用法,…...

【Linux】sed 命令详解及使用样例:流式文本编辑器
【Linux】sed 命令详解及使用样例:流式文本编辑器 引言 sed 是 Linux/Unix 系统中一个强大的流式文本编辑器,名称来源于 “Stream EDitor”(流编辑器)。它允许用户在不打开文件的情况下对文本进行筛选和转换,是命令行…...
随访系统安装的记录
安装PG17.5 安装https://www.cnblogs.com/nulixuexipython/p/18040243 1、遇到navicat链接不了PG https://blog.csdn.net/sarsscofy/article/details/84985933 2、查看有无安装mysqlhttps://blog.51cto.com/u_16175430/7261412 3、 方案一:oracle不开日志 data…...

Redis:Hash数据类型
🌈 个人主页:Zfox_ 🔥 系列专栏:Redis 🔥 Hash哈希 🐳 ⼏乎所有的主流编程语⾔都提供了哈希(hash)类型,它们的叫法可能是哈希、字典、关联数组、映射。在Redis中&#…...
白银6月想法
一、市场回顾 2025年5月,SHFE白银主力合约总体呈现出震荡偏强的运行格局。从2025年5月1日至2025年5月30日,白银期货价格整体运行在7944元至8342元区间内,最高价出现在5月22日的8342.0元,最低价则为5月15日的7944元。最终在5月30日…...
在网页加载时自动运行js的方法(2025最新)
在网页加载时自动运行JavaScript方法有多种实现方式,以下是常见的几种方法: 1. 使用 DOMContentLoaded 事件 当初始HTML文档完全加载和解析后触发(无需等待图片等资源加载): document.addEventListener(DOMC…...

OpenCV计算机视觉实战(10)——形态学操作详解
OpenCV计算机视觉实战(10)——形态学操作详解 0. 前言1. 腐蚀与膨胀1.1 为什么要做腐蚀与膨胀1.2 OpenCV 实现 2. 开运算与闭运算2.1 开运算与闭运算原理2.2 OpenCV 实现 3. 形态学梯度与骨架提取3.1 形态学梯度3.2 骨架提取 小结系列链接 0. 前言 形态…...

从Copilot到Agent,AI Coding是如何进化的?
编程原本是一项具有一定门槛的技能,但借助 AI Coding 产品,新手也能写出可运行的代码,非专业人员如业务分析师、产品经理,也能在 AI 帮助下直接生成简单应用。 这一演变对软件产业产生了深远影响。当 AI 逐步参与代码生成、调试乃…...

Model Context Protocol (MCP) 是一个前沿框架
微软发布了 Model Context Protocol (MCP) 课程:mcp-for-beginners。 Model Context Protocol (MCP) 是一个前沿框架,涵盖 C#、Java、JavaScript、TypeScript 和 Python 等主流编程语言,规范 AI 模型与客户端应用之间的交互。 MCP 课程结构 …...

Prompt提示工程指南#Kontext图像到图像
重要提示:单个prompt的最大token数为512 # 核心能力 Kontext图像编辑系统能够: 理解图像上下文语义实现精准的局部修改保持原始图像风格一致性支持复杂的多步迭代编辑 # 基础对象修改 示例场景:改变汽车颜色 Prompt设计: Change …...

SDC命令详解:使用set_propagated_clock命令进行约束
相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html?spm1001.2014.3001.5482 目录 指定端口列表/集合 简单使用 注意事项 传播时钟是在进行了时钟树综合后,使用set_propagated_clock命令可以将一个理想时钟转换为传播时钟&#x…...