【从零开始学习QT】信号和槽

目录

一、信号和槽概述

信号的本质

槽的本质

二、信号和槽的使用

[2.1 连接信号和槽](#2.1 连接信号和槽)

[2.2 查看内置信号和槽](#2.2 查看内置信号和槽)

[2.3 通过 Qt Creator 生成信号槽代码](#2.3 通过 Qt Creator 生成信号槽代码)

自定义槽函数

自定义信号

自定义信号和槽

[2.4 带参数的信号和槽](#2.4 带参数的信号和槽)

三、信号与槽的连接方式

[3.1 一对一](#3.1 一对一)

(1)一个信号连接一个槽

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

[3.2 一对多](#3.2 一对多)

[3.3 多对一](#3.3 多对一)

四、信号与槽的连接

[五、使用 Lambda 表达式定义槽函数](#五、使用 Lambda 表达式定义槽函数)


QT专栏:QT_uyeonashi的博客-CSDN博客

一、信号和槽概述

在 Qt 中,用户和控件的每次交互过程称为一个事件 。比如 "用户点击按钮" 是一个事件,"用户关闭窗口" 也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出 "按钮被点击" 的信号,用户关闭窗口会发出 "窗口被关闭" 的信号。

Qt 中的所有控件都具有接收信号的能力,一个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作。例如,按钮所在的窗口接收到 "按钮被点击" 的信号后,会做出 "关闭自己" 的响应动作;再比如输入框自己接收到 "输入框被点击" 的信号后,会做出 "显示闪烁的光标,等待用户输入数据" 的响应动作。在 Qt 中,对信号做出的响应动作就称之为槽

信号和槽是 Qt 特有的消息传输机制,它能将相互独立的控件关联起来。比如,"按钮" 和 "窗口"

本身是两个独立的控件,点击 "按钮" 并不会对 "窗口" 造成任何影响。通过信号和槽机制,可以将 "按钮" 和 "窗口" 关联起来,实现 "点击按钮会使窗口关闭" 的效果。

信号的本质

信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时 Qt 对

应的窗口类会发出某个信号,以此对用户的操作做出反应。因此,信号的本质就是事件 。如:

• 按钮单击、双击

• 窗口刷新

• 鼠标移动、鼠标按下、鼠标释放

• 键盘输入

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

• 我们对哪个窗口进行操作, 哪个窗口就可以捕捉到这些被触发的事件。

• 对于使用者来说触发了一个事件我们就可以得到 Qt 框架给我们发出的某个特定信号。

信号的呈现形式就是函数, 也就是说某个事件产生了, Qt 框架就会调用某个对应的信号函数, 通知使用者。

槽的本质

槽(Slot)就是对信号响应的函数。 槽就是一个函数,与一般的 C++ 函数是一样的,可以定义在类的任何位置( public、protected 或 private ),可以具有任何参数,可以被重载,也可以被直接调用(但是不能有默认参数)。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

说明

(1)信号和槽机制底层是通过函数间的相互调用实现的。每个信号都可以用函数来表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。例如: "按钮被按下" 这个信号可以用 clicked() 函数表示,"窗口关闭" 这个槽可以用 close() 函数表示,假如使用信号和槽机制-

实现:"点击按钮会关闭窗口" 的功能,其实就是 clicked() 函数调用 close() 函数的效果。

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

• 信号函数用 signals 关键字修饰,槽函数用 public slots、protected slots 或者 private slots 修饰。signals 和 slots 是 Qt 在 C++ 的基础上扩展的关键字,专门用来指明信号函数和槽函数;
• 信号函数只需要声明,不需要定义(实现),而槽函数需要定义(实现)。

二、信号和槽的使用

2.1 连接信号和槽

在 Qt 中,QObject 类提供了一个静态成员函数connect(),该函数专门用来关联指定的信号函数和槽函数。

++QObject 是 Qt 内置的父类. Qt 中提供的很多类都是直接或者间接继承自 QObject++

connect() 函数原型:

cpp 复制代码
connect (const QObject *sender,
        const char * signal ,
        const QObject * receiver ,
        const char * method ,
        Qt::ConnectionType type = Qt::AutoConnection )

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

2.2 查看内置信号和槽

系统自带的信号和槽通常是通过 "Qt 帮助文档" 来查询

如上述示例,要查询 "按钮" 的信号,在帮助文档中输入:QPushButton,

• 首先可以在 "Contents" 中寻找关键字 signals,

• 如果没有找到, 继续去父类 中查找. 因此我们去他的父类 QAbstractButton 中继续查找关键字signals

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

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

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

自定义槽函数

所谓的slot就是一个普通的成员函数

自定义一个槽函数,操作过程和自定义一个普通的成员函数,没啥区别

第一种方式:一个简单的代码

第二种方式:

->

QT Creator 直接给我们生成好了一个函数;

在 "widget.h" 头文件中自动添加槽函数的声明;在 "widget.cpp" 中自动生成槽函数定义.

自定义信号

Qwidget :咱们的Widget虽然还没有定义任何信号,由于继承自QWidget和QObject这两类已经提供了一些信号量可以直接使用

所谓的QT信号,本质上也是一个"函数",Qt 5及更高版本中,槽函数和普通成员函数之间,没啥区别

  1. 信号是一类非常特殊的函数,程序员只需要写出函数声明,并告诉Qt这是一个信号即可。这个函数的定义是Qt在编译过程中自动生成的(自动生成的过程,程序员无法干预)

信号在Qt中是特殊的机制,Qt生成的信号函数实现要配合Qt框架做很多既定的操作

  1. 作为信号函数,这个函数的返回值必须是void,有没有函数都可以,甚至也可以支持重载

signals:这个也是Qt自己扩展出来的关键字~

qmake的时候调用一些代码的分析/生成工具,扫描到类中包含signals这个关键字的时候,此时就会自动把下面的函数声明认为是信号,并且把这些信号函数自动的生成函数定义

举个栗子:

我们运行之后发现并窗口没有变化

这里qt提供了一个关键字emit,使用 "emit" 关键字发送信号


自定义信号和槽

2.4 带参数的信号和槽

Qt 的信号和槽也支持带有参数, 同时也可以支持重载.

此处我们要求, 信号函数的参数列表要和对应连接的槽函数参数列表一致.

此时信号触发, 调用到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中.

传参可以起到复用代码的效果;有多个逻辑,逻辑上基本整体一致,但是涉及到的数据不同

就可以通过函数-参数来复用代码,并且在不同的场景中传入不同的参数即可~

举个栗子:

注意:带有参数的信号,要求信号的参数和槽的参数要一致;类型要一直,参数个数要满足信号的参数个数要多于槽的参数个数


三、信号与槽的连接方式

3.1 一对一

主要有两种形式,分别是:一个信号连接一个槽一个信号连接一个信号

(1)一个信号连接一个槽

举个栗子:

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

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

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

举个栗子:

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

3.2 一对多

一个信号连接多个槽

举个栗子:

(1)在 "widget.h" 头文件中声明一个信号和三个槽;

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

3.3 多对一

多个信号连接一个槽函数

举个栗子:

(1)在 "widget.h" 头文件中声明两个信号以及一个槽;

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

四、信号与槽的连接

如果没有disconnect,就会构成一个信号绑定了两个槽函数,触发信号的时候就会两个槽函数都执行

使用disconnect来断开信号的连接,disconnect的使用方式和connect是非常类似的

五、使用 Lambda 表达式定义槽函数

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

cpp 复制代码
[ capture ] ( params ) opt -> ret {
Function body;
};

说明:

举个栗子:

注意:

lambda为了解决上述问题,引入了"变量捕获",通过变量捕获,获取到外层作用域中的变量,即将变量名称写到[ ]中

如过变量特别多课以写成[=],这个写法的含义就是把上层作用域中所有的变量名都给捕获进来!

注意lambda在捕获的时候一定要保证对象是可用的(注意生命周期)


总结:信号与槽的优缺点

优点: 松散耦合

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

缺点: 效率较低

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


本篇完!

相关推荐
鑫鑫向栄1 小时前
[蓝桥杯]剪格子
数据结构·c++·算法·职场和发展·蓝桥杯
白总Server1 小时前
C++语法架构解说
java·网络·c++·网络协议·架构·golang·scala
敲键盘的小夜猫1 小时前
Milvus向量Search查询综合案例实战(下)
数据库·python·milvus
羊儿~1 小时前
P12592题解
数据结构·c++·算法
.Vcoistnt2 小时前
Codeforces Round 1028 (Div. 2)(A-D)
数据结构·c++·算法·贪心算法·动态规划
钢铁男儿2 小时前
深入剖析C#构造函数执行:基类调用、初始化顺序与访问控制
java·数据库·c#
156082072192 小时前
在QT中,利用charts库绘制FFT图形
开发语言·qt
有时间要学习2 小时前
MySQL——事务
数据库·mysql
翻滚吧键盘2 小时前
Spring Boot,注解,@ComponentScan
java·数据库·spring boot
not coder2 小时前
Pytest Fixture 详解
数据库·pytest