【Qt】—— 信号与槽

news2024/12/22 23:02:12

目录

(一)信号和槽概述

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元对象系统支持的数据类型。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TCP多线程模型、IO模型(select、poll、epoll)

我要成为嵌入式高手之3月11日Linux高编第十九天&#xff01;&#xff01; ———————————————————————————— TCP并发模型 一、TCP多线程模型&#xff1a; 缺点&#xff1a;创建线程会带来资源开销&#xff0c;能够现的并发量比较有限 二、IO模型&…

产品设计 - 尼尔森交互设计原则

文章目录 前言1. 状态可见原则1.1 理论介绍1.2 实践应用 2. 环境贴切原则2.1 理论介绍2.2 实践应用 3. 用户可控原则3.1 理论介绍3.2 实践应用 4. 一致性原则4.1 理论介绍4.2 实践应用 5. 易用原则5.1 理论介绍5.2 实践应用 6. 灵活高效原则6.1 理论介绍6.2 实际应用 7. 优美简…

opengl 学习(五)-----变换

变换 分类向量向量与标量运算向量取反向量加减向量相乘点乘叉乘 矩阵矩阵的加减矩阵的数乘矩阵相乘 矩阵与向量相乘单位矩阵缩放位移 旋转GLMdemo效果解析教程 分类 OpenGL C 向量 下面有一个解释的非常好的理解: 向量有一个方向(Direction)和大小(Magnitude&#xff0c;也叫…

网络编程(3/6)

使用C语言完成数据库的增删改 #include<myhead.h> int do_add(sqlite3 *ppDb) {int numb;char name[50];int salary;printf("请输入员工信息&#xff1a;工号、姓名、薪水\n");scanf("%d %s %d",&numb,name,&salary);char sql[128];char *e…

关于遗传力常见的误解

大家好&#xff0c;我是邓飞&#xff0c;今天看了一篇非常好的文章&#xff0c;介绍了遗传力相关概念和计算方法&#xff0c;里面提到了常见的误解&#xff0c;这里汇总一下。 文献链接&#xff1a;https://excellenceinbreeding.org/sites/default/files/manual/EiB-M2_Herit…

Ping工作原理

文章目录 目的ping网络协议 OSIICMP什么是ICMP作用功能报文类型查询报文类型差错报文类型ICMP 在 IPv4 和 IPv6 的封装ICMP 在 IPv4 协议中的封装ICMP 在 IPv6 协议中的封装ICMP 头部日常ping 排除步骤ping 查询报文使用code扩展目的 本文主要是梳理ping的工作原理- 揭开 ICMP…

FPGA AXI4总线操作教程

AXI&#xff08;Advanced Extensible Interface&#xff09;总线是一种高性能、低延迟的片上系统&#xff08;SoC&#xff09;接口标准&#xff0c;广泛应用于现代数字系统设计中。它允许不同的硬件组件以高效、可靠的方式进行数据传输和控制。本教程将介绍AXI总线的基本操作和…

C++面向对象..

1.面向对象的常见知识点 类、 对象、 成员变量(属性)、成员函数(方法)、 封装、继承、多态 2.类 在C中可以通过struct、class定义一个类 struct和class的区别&#xff1a; struct的默认权限是public(在C语言中struct内部是不可以定义函数的) 而class的默认权限是private(该权…

上位机图像处理和嵌入式模块部署(qmacvisual旋转和镜像)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 旋转和镜像是图像处理中经常遇到的一个情况。很多时候&#xff0c;摄像头面对物体进行拍摄&#xff0c;未必是正对着进行拍摄的&#xff0c;这个时…

谷粒商城【成神路】-【10】——缓存

目录 &#x1f9c2;1.引入缓存的优势 &#x1f953;2.哪些数据适合放入缓存 &#x1f32d;3.使用redis作为缓存组件 &#x1f37f;4.redis存在的问题 &#x1f9c8;5.添加本地锁 &#x1f95e;6.添加分布式锁 &#x1f95a;7.整合redisson作为分布式锁 &#x1f697…

JavaScript实现通过键盘弹钢琴的效果

本片文章通过触发键盘事件来触发对应的音乐&#xff0c;而且给页面添加了渐变的active类名&#xff0c;通过触发不同的鼠标事件&#xff0c;然后active类移动来实现按下钢琴键的视觉效果。 关键代码&#xff1a; <!DOCTYPE html> <html lang"en"><h…

提示并输入一个字符串,统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C++风格字符串完成

#include <iostream> #include <array> using namespace std;int main() {cout<<"请输入一个字符串"<<endl;//array<string,100> str;string str;getline(cin,str);int daxie0,xiaoxie0,num0,space0,other0;int lenstr.size();;for(in…

Java随手记

equals和的区别 使用基本数据类型&#xff08;char&#xff0c;int&#xff0c;long等&#xff09;的时候&#xff0c;比较的是它们的值 使用引用数据类型的时候&#xff0c;比较的是地址 equals如果不重写&#xff0c;那么和 是没差别的 下面来看String的比较&#xff0c;这…

Spring Security自定义认证授权过滤器

自定义认证授权过滤器 自定义认证授权过滤器1、SpringSecurity内置认证流程2、自定义Security认证过滤器2.1 自定义认证过滤器2.2 定义获取用户详情服务bean2.3 定义SecurityConfig类2.4 自定义认证流程测试 3、 基于JWT实现无状态认证3.1 认证成功响应JWT实现3.2 SpringSecuri…

Kafka MQ 生产者和消费者

Kafka MQ 生产者和消费者 Kafka 的客户端就是 Kafka 系统的用户&#xff0c;它们被分为两种基本类型:生产者和消费者。除 此之外&#xff0c;还有其他高级客户端 API——用于数据集成的 Kafka Connect API 和用于流式处理 的 Kafka Streams。这些高级客户端 API 使用生产者和消…

如何保证消息的可靠传输

数据的丢失问题&#xff0c;可能出现在生产者、MQ、消费者中 生产者丢失&#xff1a; 生产者将数据发送到 RabbitMQ 的时候&#xff0c;可能数据就在半路给搞丢了&#xff0c;因为网络问题啥的&#xff0c;都有可能。此时可以选择用 RabbitMQ 提供的事务功能&#xff0c;就是生…

脚手架cli快速创建Vue2/Vue3项目

前言&#xff1a; 本文的nodejs版本是14.21.3 第一步 进入cmd窗口 1、全局安装webpack npm install webpack-g&#xff0c; npm install webpack-g 第二步 2、全局安装vue脚手架 npm install -g vue/cli 第三步 3、初始化vue项目 &#xff08;vue脚手架使用webpack模…

资料下载-嵌入式 Linux 入门

学习的第一步是去下载资料。 1. 有哪些资料 所有资料分 4 类&#xff1a; ① 开发板配套资料(原理图、虚拟机的映像文件、烧写工具等)&#xff0c;放在百度网盘 ② 录制视频过程中编写的文档、源码、图片&#xff0c;放在 GIT 仓库 ③ u-boot、linux 内核、buildroot 等比较大…

STM32CubeMX学习笔记18——FSMC(TFT-LCD屏触摸)

1.触摸屏简介 目前最常用的触摸屏有两种&#xff1a;电阻式触摸屏和电容式触摸屏 1.1 电阻式触摸屏 电阻式的触摸屏结构如下图示&#xff0c;它主要由表面硬涂层、两个ITO层、间隔点以及玻璃底层构成&#xff0c;这些结构层都是透明的&#xff0c;整个触摸屏覆盖在液晶面板上…

45、C++/基础练习20240311

一、提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求 使用C风格字符串完成。 代码&#xff1a; #include <iostream>using namespace std;int main() {string buf;//定义字符串类型变量bufcout << &…