【Qt】—— 信号与槽

目录

(一)信号和槽概述

1.1 信号的本质

1.2 槽的本质

 (二)信号和槽的使用

2.1 信号和槽的连接

2.2 查看内置信号和槽

2.3 通过Qt Creator⽣成信号槽代码

(三)自定义信号和槽

3.1 基本语法

3.2 带参数的信号和槽

(四)信号与槽的连接⽅式

4.1 ⼀对⼀

4.2 ⼀对多

4.3 多对⼀

(五)信号和槽的其他说明

5.1 信号与槽的断开

5.2 Qt4版本信号与槽的连接

5.3 使⽤Lambda表达式定义槽函数

5.4 信号与槽的优缺点

 总结


(一)信号和槽概述

在Qt中,每次用户与控件互动的过程都被称为一个事件。举例来说,"用户点击按钮"是一个事件,"用户关闭窗口"也是一个事件。每个事件都会触发相应的信号,例如,当用户点击按钮时,会发出"按钮被点击"的信号;当用户关闭窗口时,会发出"窗口被关闭"的信号。这种事件和信号的机制使得在Qt应用程序中能够方便地处理用户交互和相应的行为。

在Qt中,每个控件都具备接收信号的能力,并且一个控件可以同时接收多个不同的信号。每当控件接收到信号时,它会执行相应的响应动作。举例来说,当窗口中的按钮接收到"按钮被点击"的信号时,它会执行"关闭自身"的响应动作;又如,当文本输入框接收到"文本框被点击"的信号时,它会执行"显示闪烁的光标,等待用户输入数据"的响应动作。在Qt中,对信号所做出的响应动作被称为槽函数

信号和槽是Qt独有的消息传递机制,它能够连接不同的控件并使它们相互影响。举例来说,"按钮"和"窗口"是两个独立的控件,单纯点击按钮并不会对窗口产生任何影响。通过信号和槽机制,可以将按钮和窗口连接起来,实现"点击按钮会导致窗口关闭"的效果。

1.1 信号的本质

信号是由用户对窗口或控件进行操作所触发的特定事件,这些事件会导致相应的窗口类或控件类发出特定的信号,从而对用户的操作作出响应。因此,从本质上讲,信号就是事件的一种体现

例如:

  • 按钮单击、双击
  • 窗⼝刷新
  • ⿏标移动、⿏标按下、⿏标释放
  • 键盘输⼊

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

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

在Qt中信号的发出者是某个实例化的类对象


1.2 槽的本质

 (Slot)是对信号进行响应的函数。槽函数与一般的C++函数类似,可以定义在类的任何位置(public、protected或private),可以具有任意参数,可以被重载,也可以直接调用(但不能有默认参数)。

  • 与一般函数不同的是:槽函数可以与一个信号相关联。当信号被发射时,与之关联的槽函数会自动执行。

1)信号和槽机制在底层通过函数间的相互调用来实现。每个信号可以用函数表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。例如,"按钮被按下"这个信号可以用clicked()函数表示,而"窗口关闭"这个槽可以用close()函数表示。因此,使用信号和槽机制实现"点击按钮会关闭窗口"的功能实质上是clicked()函数调用close()函数的效果。

2)信号函数和槽函数通常位于某个类中。相较于普通的成员函数,它们的特殊之处在于:

  • 信号函数用signals关键字修饰,槽函数用public slots、protected slots或private slots修饰。signals和slots是Qt在C++基础上扩展的关键字,专门用于指明信号函数和槽函数;
  • 信号函数只需声明,无需定义(实现),而槽函数需要定义(实现)。
  • 信号函数的定义是Qt⾃动在编译程序之前⽣成的.编写Qt应⽤程序的程序猿⽆需关注.
  • 这种⾃动⽣成代码的机制称为元编程(Meta Programming).这种操作在很多场景中都能⻅到.

 (二)信号和槽的使用

2.1 信号和槽的连接

信号与槽的连接是Qt中用于建立信号与槽关联关系的重要机制。通过连接,一个信号可以触发一个或多个槽函数的执行,实现对象之间的通信。 

在Qt中,QObject类(QObjectQt内置的⽗类.Qt中提供的很多类都是直接或者间接继承⾃QObject)提供了⼀个静态成员函数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::AutoConnection,通常不需要⼿动设定。

 


2.2 查看内置信号和槽

1、系统⾃带的信号和槽通常是通过"Qt帮助⽂档"来查询。
2、如上述⽰例,要查询"按钮"的信号,在帮助⽂档中输⼊:QPushButton

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

这⾥的clicked()就是要找的信号。槽函数的寻找⽅式和信号⼀样,只不过它的关键字是slot。
 

2.3 通过Qt Creator⽣成信号槽代码

Qt Creator可以快速帮助我们⽣成信号槽相关的代码。

代码示例:在窗⼝中设置⼀个按钮,当点击"按钮"时关闭"窗⼝".

1、新建项⽬,如下图为新建完成之后所包含的所有⽂件(创建时要⽣成UI设计⽂件)

2、双击widget.ui⽂件,进⼊UI设计界⾯;

3、在UI设计窗⼝中拖⼊⼀个"按钮",并且修改"按钮"的名称及字体大小等;

4、可视化⽣成槽函数;

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

  •  对于普通按钮来说,使⽤ clicked 信号即可.clicked(bool) 没有意义的.具有特殊状态的按钮(⽐如复选按钮)才会⽤到 clicked(bool) .

5、⾃动⽣成槽函数原型框架;
(1)在"widget.h"头⽂件中⾃动添加槽函数的声明;

【解释说明】
⾃动⽣成槽函数的名称有⼀定的规则。槽函数的命名规则为:on_XXX_SSS,其中:

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

如:"on_pushButton_clicked()",pushButton代表的是对象名,clicked是对应的信号。

(2)在"widget.cpp"中⾃动⽣成槽函数定义.


 6、在槽函数函数定义中添加要实现的功能.实现关闭窗⼝的效果(即当我们运行代码点击关闭按钮之后窗口就会自动关闭)

 


(三)自定义信号和槽
 

3.1 基本语法
 

在Qt中,可以自定义信号和槽函数以满足特定需求。然而,自定义的信号函数和槽函数应该遵循一定的书写规范。

1、⾃定义信号函数书写规范

  • ⾃定义信号函数必须写到"signals"下;
  • 返回值为void,只需要声明,不需要实现;
  • 可以有参数,也可以发⽣重载;

2、⾃定义槽函数书写规范

  • 早期的Qt版本要求槽函数必须写到"publicslots"下,但是现在⾼级版本的Qt允许写到类的"public"作⽤域中或者全局下;
  • 返回值为void,需要声明,也需要实现;
  • 可以有参数,可以发⽣重载;

3、发送信号

  • 使⽤"emit"关键字发送信号。"emit"是⼀个空的宏。"emit"其实是可选的,没有什么含义,只是为了提醒开发⼈员。

⽰例1:
1、在widget.h中声明⾃定义的信号和槽,如图所⽰;

2、在widget.cpp中实现槽函数,并且关联信号和槽

注意:图中的①和②的顺序不能颠倒
原因是,⾸先关联信号和槽,⼀旦检测到信号发射之后就会⽴⻢执⾏关联的槽函数。反之,若先发射信号,此时还没有关联槽函数,当信号发射之后槽函数不会响应.


3.2 带参数的信号和槽

Qt的信号和槽也⽀持带有参数,同时也可以⽀持重载.
此处我们要求,信号函数的参数列表要和对应连接的槽函数参数列表⼀致.
此时信号触发,调⽤到槽函数的时候,信号函数中的实参就能够被传递到槽函数的形参当中.

(💡 通过这样的机制,就可以让信号给槽传递数据了.)

示例:重载信号槽
(1)在"widget.h"头⽂件中声明重载的信号函数以及重载的槽函数;如下图所⽰:

(2)在"Widget.cpp"⽂件实现重载槽函数以及连接信号和槽。

  • 需要注意的是:在定义函数指针时要指明函数指针的作⽤域。

(3)执⾏结果如下图所⽰:

 


(四)信号与槽的连接⽅式

4.1 ⼀对⼀

主要有两种形式,分别是:⼀个信号连接⼀个槽⼀个信号连接⼀个信号
(1)⼀个信号连接⼀个槽
 

代码⽰例:
1、在"widget.h"中声明信号和槽以及信号发射函数;
 

2、在"widget.cpp"中实现槽函数,信号发射函数以及连接信号和槽;

(2)⼀个信号连接另⼀个信号

代码示例: 

在上述⽰例的基础上,在"widget.cpp"⽂件中添加如下代码:
 


4.2 ⼀对多

⼀个信号连接多个槽

⽰例:
(1)在"widget.h"头⽂件中声明⼀个信号和三个槽;

(2)在"widget.cpp"⽂件中实现槽函数以及连接信号和槽;
 

 


4.3 多对⼀

多个信号连接⼀个槽函数

⽰例:
(1)在"widget.h"头⽂件中声明两个信号以及⼀个槽;

 (2)在"widget.cpp"⽂件中实现槽函数以及连接信号和槽;


(五)信号和槽的其他说明

5.1 信号与槽的断开

在Qt中,可以使用 disconnect 函数来断开信号与槽之间的连接。disconnect 函数允许你在运行时动态地断开连接,以便停止两个对象之间的信号和槽的关联。(disconnect的⽤法和connect基本⼀致.)

代码示例:

  • 需要注意的是,断开连接时,必须提供与建立连接时相同的参数,包括信号函数和槽函数的指针或函数指针。

5.2 Qt4版本信号与槽的连接

Qt4中的connect⽤法和Qt5相⽐是更复杂的.需要搭配 SIGNAL 和 SLOT 宏来完成。⽽且缺少必要的函数类型的检查,使代码更容易出错。

代码示例:

(1)在"widget.h"头⽂件中声明信号和槽

(2)在"widget.cpp"⽂件中实现槽函数以及连接信号与槽;

Qt4版本信号与槽连接的优缺点:

  • 优点:参数直观;
  • 缺点:参数类型不做检测;
     

代码示例:


5.3 使⽤Lambda表达式定义槽函数

Qt5在Qt4的基础上提⾼了信号与槽的灵活性,允许使⽤任意函数作为槽函数。


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


在Qt中,可以使用Lambda表达式来定义槽函数,这使得代码更加简洁和可读。Lambda表达式是C++11引入的一种匿名函数形式,允许我们在需要函数的地方内联定义函数。

下面是一个使用Lambda表达式定义槽函数的示例:

// 假设有一个QPushButton对象 btn
connect(btn, &QPushButton::clicked, [=]() {
    qDebug() << "按钮被点击了";
    // 在这里写下按钮被点击时需要执行的操作
});

【解释说明】

  • 在这个示例中,我们将按钮的clicked信号与一个Lambda表达式连接起来。
  • Lambda表达式作为槽函数,使用了方括号[]来捕获外部变量,这里使用了捕获所有外部变量的方式[=]。
  • Lambda表达式中的代码将会在按钮被点击时执行。

5.4 信号与槽的优缺点


优点:松散耦合

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

缺点:效率较低

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

 总结

在Qt中,信号与槽是一种强大的通信机制,用于在对象之间进行异步通信。以下是关于信号与槽的简要小结:

  1. 信号

    • 信号是Qt中特有的概念,是一种特殊的成员函数,用于通知其他对象发生了某种特定的事件。
    • 信号由signals:关键字声明,在类的声明部分中定义。
    • 信号函数通常不包含实际的实现,只是用来发出信号。
    • 信号函数可以有参数,参数的类型必须是Qt元对象系统支持的数据类型。
    • 槽是用于响应信号的函数,可以执行特定的操作以响应信号的发生。
    • 槽函数由slots:关键字声明,在类的声明部分中定义。
    • 槽函数可以是普通成员函数、静态成员函数或者Lambda表达式。
    • 槽函数的参数类型必须与连接的信号的参数类型匹配。
  2. 连接

    • 连接是指建立信号与槽之间的关联,使得当信号被发出时,相关的槽函数会被调用。
    • 连接通过QObject::connect()函数来实现,可以连接两个QObject对象之间的信号和槽。
    • 在连接时,需要指定发送信号的对象、信号函数、接收信号的对象以及槽函数。
    • 连接还可以使用Qt 5中引入的新语法,使得连接更加类型安全。
  3. 自定义信号与槽

    • Qt允许自定义信号和槽函数,以满足特定需求。
    • 自定义的信号函数和槽函数应该遵循一定的书写规范,例如在类的声明部分中使用signals:slots:关键字声明。
    • 自定义的信号函数和槽函数可以有参数,参数的类型必须是Qt元对象系统支持的数据类型。

使用信号与槽机制可以实现对象之间的松耦合通信,使得代码更加模块化、可维护和可扩展。

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

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

相关文章

单例模式及线程安全的实践

&#x1f31f; 欢迎来到 我的博客&#xff01; &#x1f308; &#x1f4a1; 探索未知, 分享知识 !&#x1f4ab; 本文目录 引言基本的单例模式长啥样&#xff1f;怎样才能线程安全&#xff1f;**懒汉模式** ( 双 重 检 查 ) &#x1f389;总结&#x1f389; 引言 单例模式是个…

动态代理详解(原理+代码+代码解析)

动态代理 1.什么是动态代理&#xff1f; 动态代理是一种在运行的时候动态的生成代理对象的技术。它在不改变原始类的情况下&#xff0c;对原始类的方法进行拦截或者增强。 2.动态代理可以实现的功能&#xff1f; 使用动态代理可以实现如下常用功能&#xff1a; 1.AOP&#x…

为什么要使用数字档案管理系统

机关企事业单位使用数字档案管理系统&#xff0c;主要有以下几个原因&#xff1a; 1. 档案管理效率提升&#xff1a;玖拓智能数字档案管理系统可以帮助综合档案馆实现对档案的全面管理和翔实记录&#xff0c;包括档案的入库、整理、检索、借阅等工作。系统化的管理使得档案管理…

调整分区失败,硬盘难启:原因分析与数据恢复之道

在数字化时代&#xff0c;硬盘作为存储数据的重要工具&#xff0c;其稳定性和安全性至关重要。然而&#xff0c;有时在调整分区的过程中&#xff0c;我们可能会遭遇失败&#xff0c;导致硬盘无法打开&#xff0c;数据无法访问。这种情况不仅令人沮丧&#xff0c;更可能带来不可…

第16章——西瓜书强化学习

在强化学习中&#xff0c;智能体通过与环境的交互来学习如何做出决策。在每个时间步&#xff0c;智能体观察当前的环境状态&#xff0c;并根据其策略选择一个动作。环境会对智能体的动作做出响应&#xff0c;并给出一个奖励信号&#xff08;reward&#xff09;&#xff0c;该信…

crossover玩不了qq游戏大厅怎么办 仍有五亿人坚持用QQ crossover玩游戏 Mac电脑玩QQ游戏

从1999年2月&#xff0c;QQ首个版本QICQ&#xff08;OPEN-ICQ&#xff09;上线。到2024年&#xff0c;靠着5亿月活用户&#xff0c;守住社交领域TOP2位置。你还记得QQ经典的铃声吗&#xff1f; 根据月狐数据2023年12月的统计&#xff0c;QQ月活跃账户数比微博和知乎加在一起还要…

【C++庖丁解牛】STL之vector容器的介绍及使用 | vector迭代器的使用 | vector空间增长问题

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.1 vector的介绍2 v…

创造一款安卓自定义控件(4)——使用Matrix的setPolyToPoly方法实现图像纠正

接上文&#xff1a; 创造一款安卓自定义控件_任意4顶点裁剪框http://t.csdnimg.cn/vu1r5 创造一款安卓自定义控件_任意4顶点裁剪框2_为裁剪框添加放大镜功能http://t.csdnimg.cn/qkngh 创造一款安卓自定义控件_裁剪原理介绍http://t.csdnimg.cn/ORRRL 需求 随着需求修改&#x…

Linux系统部署火狐浏览器结合内网穿透实现公网访问

目录 前言 1. 部署Firefox 2. 本地访问Firefox 3. Linux安装Cpolar 4. 配置Firefox公网地址 5. 远程访问Firefox 6. 固定Firefox公网地址 7. 固定地址访问Firefox 结语 前言 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊Linux系统…

企业接入SD-WAN组网需要花费多少?

企业数字化转型的不断深入&#xff0c;越来越多的企业开始考虑采用SD-WAN&#xff08;软件定义广域网&#xff09;技术来优化其网络架构&#xff0c;提升网络性能和安全性。然而&#xff0c;对于企业来说&#xff0c;接入SD-WAN组网 需要花费多少是一个关键问题。以下是一些影响…

对接钉钉机器人实现点餐提醒,妈妈再也不用担心我错过点餐了

公司的点晚饭时间是11点半到下午3点。忙起来真的很容易忘记&#xff0c;今天话不多说&#xff0c;直接开搞一个机器人提醒我们点饭 ::(笑眼) 。本教程基于centos7版本 “前提要有一个服务器 和一个钉钉群” 要对接钉钉机器人&#xff0c;首先你要有钉钉的群。假设你已经有了钉…

算法——哈希王

242.有效的字母异位词 力扣题目链接(opens new window) 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 输入: s "anagram", t "nagaram" 输出: true 示例 2: 输入: s "rat", t "car&qu…

错误:npm ERR! code CERT_HAS_EXPIRED 解决

问题&#xff1a; 在打开项目用npm install安装依赖时报错&#xff1a;npm ERR! code CERT_HAS_EXPIRED如下图&#xff1a; 原因&#xff1a; 说明正在尝试访问的npm registry 淘宝npm镜像源 的SSL证书已经过期&#xff0c;导致无法建立安全连接。 解决&#xff1a; 配置不…

从内存管理的角度聊聊MMU的那些事

本文从内存管理的发展历程角度层层递进&#xff0c;介绍 MMU 的诞生背景&#xff0c;工作机制。而忽略了具体处理器的具体实现细节&#xff0c;将 MMU 的工作原理从概念上比较清晰的梳理了一遍。 MMU 诞生之前: 在传统的批处理系统如 DOS 系统,应用程序与操作系统在内存中的布…

如何选择海外代理ip?需要注意哪些因素?

选择合适的海外代理ip提供商是确保网络活动安全、高效和顺畅的关键。在众多提供商中做出明智选择需要考虑多个关键因素。 首先&#xff0c;讨论如何选择合适的海外代理ip服务提供商。一个好的服务提供商应该具备良好的市场声誉和客户反馈。在选择前&#xff0c;深入研究并比较…

【Java设计模式】九、桥接模式

文章目录 0、背景1、模式2、案例3、使用场景 0、背景 现要创建不同的图形&#xff0c;图形的形状有圆、长方形、正方形&#xff0c;且它们有不同的颜色 两个维度在变&#xff0c;使用类的继承可以实现&#xff0c;也符合开闭原则&#xff0c;但会类爆炸。 1、模式 将抽象与…

什么是高级编程语言?——跟老吕学Python编程

什么是高级编程语言&#xff1f;——跟老吕学Python编程 高级编程语言简介高级编程语言发展历程高级编程语言特点高级编程语言分类命令式语言函数式语言逻辑式语言面向对象语言 常见的高级编程语言及其特点和应用领域高级编程语言性能分析高级编程语言的工作方式 高级编程语言简…

【框架设计】MVC和MVVM对比图

1. MVC&#xff08;Model-View-Controller&#xff09; 单向通信View和Model通过Controller承上启下 2. MVVM&#xff08;Model-View-ViewModel&#xff09; 数据绑定M -> VM -> V DOM事件监听 V -> VM -> M 1. MVC是单向的&#xff0c;MVVM是双向的&#xff0c;…

服务器主机云主机在日常维护需要注意的几个点

服务器的日常维护对于确保服务器的稳定运行和安全性非常重要&#xff0c;以下是一些常见的服务器日常维护方面&#xff1a; 定期更新操作系统和软件&#xff1a;确保服务器的操作系统、应用程序以及安全补丁都是最新的&#xff0c;以填补已知的安全漏洞和提高系统性能。监视服务…

Stable Diffusion 详解

整体目标 文本生成图片&#xff1b;文本图片生成图片 网络结构 CLIP的文本编码器和图片生成器组成图像生成器&#xff0c;输入是噪声经过UNet得到图像特征&#xff0c;最后解码得到图像 前向扩散 模型直接预测图片难度比较大&#xff0c;所有让模型预测噪音然后输入-噪音…