当前位置: 首页 > news >正文

【Qt】9.信号和槽_信号和槽存在的意义

文章目录

  • 1. 信号和槽存在的意义
  • 2. 信号和槽的其他说明
    • 2.1 信号与槽的断开
  • 3. 使用 Lambda 表达式定义槽函数
  • 4. 信号与槽的优缺点


1. 信号和槽存在的意义

所谓的信号槽,终究要解决的问题,就是响应用户的操作。

信号槽,其实在GUI开发的各种框架中,是一个比较有特色的存在。

其他的GUI开发框架,搞的方式都要更简洁一些。不需要搞一个单独的connect完成上述的信号槽连接。

网页开发中响应用户操作,主要就是挂回调函数。

处理函数,就像控件的一个属性/成员一样

大部分的GUI开发框架都是这么搞的:

  • —对—
  • 一个事件,只能对应一个处理函数
  • 一个处理函数也只能对应到一个事件上

Qt信号槽,connect这个机制,设想很美好的

  1. 解耦合,把触发用户操作的控件和处理对应用户的操作逻辑解耦合

  2. "多对多"效果

    • 一个信号,可以connect(绑定)到多个槽函数上

    • 一个槽函数,也可以被多个信号connect

Qt中谈到的信号和槽“多对多”就和数据库中的多对多非常类似的。

一个信号,可以connect到多个槽函数上。

一个槽函数,也可以被多个信号connect

综上,Qt引入信号槽机制,最本质的目的(初心)就是为了能够让信号和槽之间按照“多对多”的方式来进行关联。

其他的GUI框架往往也不具备这样的特性。

实际上,随着程序开发这个事情,大家经验越来越多。

其实在GUI开发的过程中,“多对多”这件事,其实是个“伪需求”,实际开发很少会用到。绝大部分情况,一对一就够用了。

新出现的一些图形化开发框架,很少有再继续支持这种多对多的了


2. 信号和槽的其他说明

2.1 信号与槽的断开

使用disconnect来断开信号槽的连接。

disconnect使用的方式和connect是非常类似的。

disconnect用的比较少的。

大部分的情况下,把信号和槽连上了之后,就不必管了。

主动断开往往是把信号重新绑定到另一个槽函数上。

485233c9d1995ffd0091efdc9057a52a

ff979df7a0230343fb2ae2f689ebeb3d

运行:

4ee48ca9ec35c08ebfff00e0ad1bde42

点击修改窗口标题按钮

1d7dee8c8ca7c7df4712aa103428256a

点击切换槽函数按钮,再点击修改窗口标题按钮

51ad097f6d84ed94693863d9228c1150

不过切换后就切不回去了,因为没有设置。

为了方便观察,我添加了QDebug:

handleclick//点击“修改窗口标题”按钮 
handleclick//点击“修改窗口标题”按钮 
//点击下面按钮
handleclick2//点击“修改窗口标题”按钮 
handleclick2//点击“修改窗口标题”按钮 
//点击下面按钮
handleclick2//点击“修改窗口标题”按钮 
handleclick2//点击“修改窗口标题”按钮 

如果没有disconnect,就会构成一个信号绑定两个函数。

handleclick//点击“修改窗口标题”按钮 
handleclick//点击“修改窗口标题”按钮 
//点击下面按钮
handleclick//点击“修改窗口标题”按钮 
handleclick2
handleclick//点击“修改窗口标题”按钮 
handleclick2
//点击下面按钮
handleclick//点击“修改窗口标题”按钮 
handleclick2
handleclick2
handleclick//点击“修改窗口标题”按钮 
handleclick2
handleclick2

这个很有趣了,怎么点一次下面按钮,多一次click2呢?

  1. 第一次点击“下面按钮” (pushButton_2):
    on_pushButton_2_clicked() 被调用。
    connect 函数被执行,为 pushButtonclicked 信号 新增 了一个连接到 handleclick2
    • 现在,pushButtonclicked 信号同时连接了两个槽:handleclickhandleclick2
  2. 第二次点击“修改窗口标题”按钮:
    clicked 信号被发射。Qt会按连接顺序调用所有与之连接的槽函数。
    • 先调用 handleclick -> 输出 handleclick
    • 再调用 handleclick2 -> 输出 handleclick2
    • 结果:你看到了 handleclickhandleclick2 两行输出。
  3. 第二次点击“下面按钮” (pushButton_2):
    on_pushButton_2_clicked() 再次被调用。
    connect 函数又一次被执行,为 pushButtonclicked 信号 又新增 了一个连接到 handleclick2
    • 现在,pushButtonclicked 信号连接了三个槽:handleclickhandleclick2handleclick2
  4. 第三次点击“修改窗口标题”按钮:
    clicked 信号被发射。
    • 调用 handleclick -> 输出 handleclick
    • 调用第一个 handleclick2 -> 输出 handleclick2
    • 调用第二个 handleclick2 -> 输出 handleclick2
    • 结果:你看到了 handleclick 和两行 handleclick2 输出。

这个过程会不断重复,每点击一次 pushButton_2,就会多一个 handleclick2 的连接,导致输出越来越多。


3. 使用 Lambda 表达式定义槽函数

Qt5Qt4 的基础上提高了信号与槽的灵活性,允许使用任意函数作为槽函数。

但如果想方便的编写槽函数,比如在编写函数时连函数名都不想定义,则可以通过 Lambda表达式 来达到这个目的。

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

Lambda表达式 的语法格式如下:

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

capture:捕获列表

params:参数表

opt:函数选项

ret:返回值类型

Function body:函数体

点击按钮后,日志出现:lambda 被执行了!

226898ed77346bb4a76084ea8c09a485

如果我们往lambda里面写move就会报错

11d6cef436d44b8a04c199378120019e

因为,lambda表达式,是一个回调函数。C++中这个函数,无法直接获取到上层作用域中的变量的。

lambda为了解决上述问题,引入了“变量捕获”语法。通过变量捕获,获取到外层作用域中的变量。

d08c273c25ee4d26d6c74d9e025337e6

运行后点击按钮,按钮就到300,300了。

也可以再改一下 :

d4cc2635362297d4b35e0b05d02a2938

运行:

cd981b98c6f466876759c48ca70a310b

点击后:

0135b942c4c505809a359590f91ca8ce

如果当前lambda里面想使用更多的外层变量咋办?

写作[=]

这个写法的含义就是把上层作用域中所有的变量名都给捕获进来!

效果和上面一样

485057915a32b5e554398fee436035a1

后续如果我们对应的槽函数比较简单,而且是一次性使用的,就经常会写作这种lambda的形式

另外也要确认捕获到lambda内部的变量是有意义的

因为回调函数执行时机是不确定的(用户啥时候点击按钮不知道的)

无论何时用户点击了按钮,捕获到的变量都能正确使用

QPushButton* button = new QPushButton(this);

由于此处buttonnew出来的变量,生命周期跟随整个窗口(挂到对象树上,窗口关闭才会释放)

这个东西就可以在后面随时使用了。

类似的,this指向的对象widget

8389809537e76c8643791220943e4416

lambda除了可以按照值的方式来捕获变量[=]还可以按照引|用的方式来捕获[&]Qt中很少这么写)捕获到的变量一般就是各种控件的指针,指针变量按照值传递或者引用来传递,都无所谓。

如果按引用,还得更关注这个引用的变量本身的生命周期。

lambda语法是C++11中引入的。

对于Qt5及其更高版本,默认就是按照C++11来编译的。

如果使用Qt4或者更老的版本,就需要手动在.pro文件中加上C++11的编译选项。

CONFIG += c++11

4. 信号与槽的优缺点

优点: 松散耦合

信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了自己,Qt的信号槽机制保证了信号与槽函数的调用。支持信号槽机制的类或者父类必须继承于 QObject 类。

缺点: 效率较低

与回调函数相比,信号和槽稍微慢一些,因为它们提供了更高的灵活性,尽管在实际应用程序中差别不大。通过信号调用的槽函数比直接调用的速度慢约10倍(这是定位信号的接收对象所需的开销;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队),这种调用速度对性能要求不是非常高的场景是可以忽略的,是可以满足绝大部分场景。

一个客户端程序中, 最慢的环节往往是 “人”。

假设本身基于回调的方式是 10us, 使用信号槽的方式是 100us。对于使用程序的人来说, 是感知不到的。

http://www.dtcms.com/a/491672.html

相关文章:

  • 力扣热题100道之3无重复字符的最长字串
  • java无法写入到系统盘下文件
  • java中final关键字的含义
  • wordpress封采集站ip微信营销平台有哪些
  • Golang相关知识总结
  • LeetCode算法日记 - Day 73: 最小路径和、地下城游戏
  • 设计案例网站网站自身seo优化怎么做
  • 手绘风格制图新选择:Excalidraw+cpolar让视觉化工作流无缝协作
  • apt 安装任意软件产生 `libc6:amd64 package post-installation` 异常问题
  • Product Hunt 每日热榜 | 2025-10-16
  • 2025最新如何申请Google Translate API免费版图文教程
  • 提供常州微信网站建设单页企业网站模板
  • 证件阅读机在酒店与旅游业场景的应用
  • 深圳分销网站设计费用常平镇网站建设公司
  • 华为 FreeBuds SE4 ANC 如何手势调节音量?
  • Git怎么管理软件版本(代码,模型,配置等)
  • 翁虹庆爱女刘莳18岁生日 中式成人礼传承华夏底蕴
  • 苏州seo建站微信网站多少钱
  • Process Monitor 学习笔记(5.9):Procmon 的自动化操作——命令行选项
  • 荣耀手机Magic8系列都有哪些,分别通过硬件参数、性能参数、价格等方面进行详细对比
  • 合肥网站开发培训学校网站怎么做图片按按钮跳转
  • 西安专业做网站建设电子商务网站建设期中
  • 生态文明建设网站中城投建设集团网站
  • C++--- override 关键字 强制编译器验证当前函数是否重写基类的虚函数
  • LLM对话框项目技术栈重难点总结
  • 常州企业网站建设价格湛江宇锋网站建设
  • 网站开发实用吗搞钱路子一天两万
  • Ubuntu Server 系统安装图形界面远程工具(RDP)
  • 新版电脑微信4.1.x.x小程序逆向之——寻找小程序存放位置目录和__APP__.wxapkg
  • 我在高职教STM32(新05)——呼吸灯实验(基础版)