【QT】信号和槽


个人主页~


信号和槽

一、概述

在QT中,用户和控件的每次交互过程称为一个事件每个事件都会发出信号QT当中的每个控件都有接收信号的能力对信号做出相应动作就称之为槽

信号的本质就是事件 ,用户对窗口或控件进行操作,比如单击、双击,比如键盘输入,会导致窗口或者控件产生某个特定事件,这时QT对应的窗口类会发出某个信号,以此对用户的操作做出反应
信号的呈现形式是函数 ,产生事件后QT框架会调用相对应的信号函数

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

槽就是对信号响应的函数 ,槽函数除了可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行以外,其他方面与一般的普通C++函数都是一样的

信号和槽机制底层是通过函数间的相互调用实现的,每个信号都可以用函数来表示,成为信号函数,每个槽也可以用函数表示,称为槽函数

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

信号函数用signals关键词修饰,槽函数用public slots、protected slots、private slots修饰,signal和slots是QT在C++基础上扩展的关键字,专门用来指明信号函数和槽函数

信号函数只需要声明,不需要定义,而槽函数需要声明并定义

二、信号和槽的使用

连接信号和槽

QT中QIbject类提供了静态成员函数connect专门负责用来关联指定的信号函数和槽函数

connect函数原型:

cpp 复制代码
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

现在我们来写一个按钮,这个按钮可以用来关闭窗口

纯代码实现

cpp 复制代码
#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QPushButton* btn = new QPushButton("关闭窗口",this);
    connect(btn,&QPushButton::clicked,this,&QWidget::close);
}

Widget::~Widget()
{
}

可以实现点按按钮与关闭窗口的呼应

QT窗口信号和槽演示

可视化实现




在自动生成的函数中描述该按钮的槽

加一句关闭代码,由于此时的函数的隐藏参数为该按钮,所以直接操作就可以了

cpp 复制代码
this->close();

QT关闭窗口信号与槽可视化构建

三、自定义信号和槽

1、基本语法

在QT中允许自定义信号的发送方和接收方,也就是说可以自定义信号函数和槽函数,但是有一些书写规范

(1)自定义信号函数书写规范

自定义信号函数必须写到signal下

返回值为void,只需声明,无需定义

可以有参数,可以发生重载

(2)自定义槽函数书写规范

可以写到public slots或者public以及全局下

返回值为void,需要声明以及定义

可以有参数,可以发生重载

(3)发生信号

使用emit关键字发送信号,emit是一个空的宏,没有含义,只是为了提醒开发人员,并且提高代码的可读性


将信号和槽连接,当发送信号时,槽做出反应,也就是执行槽函数

2、带参数的信号和槽

上面我们展示的是无参的信号和槽,那么有参数的信号和槽是怎么工作的呢

QT的信号和槽也支持带有参数,同时可以支持重载 ,但是我们要求信号函数的参数列表要和对应的槽函数参数列表一致

信号的参数个数可以多于槽函数的参数个数,但是槽的参数个数不能多于信号参数个数,当然最好还是一致

四、信号与槽的连接方式

1、一对一

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

在上文3.1.3中就是一个信号连接一个槽的情况,这是最常用的方法

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

将按钮的点击信号与我的自定义信号连接,将我的自定义信号和我的自定义槽连接,这时,点击按钮就会触发我的自定义槽的效果

信号连接信号,信号连接槽

2、一对多

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


一个信号和三个槽连接,触发信号三个槽都响应

(2)一个槽连接多个信号


三个信号和一个槽连接,每触发一个信号槽就响应一次

五、其他说明

1、信号与槽的断开

connect可以连接信号和槽,与之对应的,disconnect可以断开这个关系,用法与connect一致

2、connect函数的解析

在Qt5以前的版本中,connect的第二个和第四个参数是不允许任意函数的,使用的时候只能搭配着宏来使用,类似下方的代码

cpp 复制代码
connect(this,SIGNAL(mysignal(),this,SLOT(myslot()));

这样会导致一个问题,它没有类型的检查,只要套上宏就可以用,如果出现以下情况,还是可以正常运行的,但信号与槽的参数列表不对应了,是错误的

cpp 复制代码
connect(this,SIGNAL(mysignal(),this,SLOT(myslot(QStirng)));

当然现在我使用的QT5以及现在最新版本的QT6都没有这个问题了,该位置的参数可以是任意类型的

3、Lambda表达式

Lambda表达式是可以直接在connect中编写槽函数的一种方式,是C++11新增的特性,用来简化编程工作

语法格式:

cpp 复制代码
[ capture ] ( params ) opt -> ret 
{ 
	Function body; 
};
参数 作用
capture 捕获列表
params 参数表
opt 函数选项
ret 返回值类型
Function body 函数体

①[capture]标识一个Lambda表达式的开始,不可省略

符号 说明
[ ] 局部变量捕获列表,Lambda表达式不能访问外部函数体的任何局部变量
[a] 在函数体内用值传递的方式访问a变量
[&a] 在函数体内用引用传递的方式访问a变量
[=] 以值传递的方式使用Lambda表达式外部的所有变量
[&] 以引用的方式使用Lambda表达式外部的所有变量
[=,&foo] foo使用引用方式传递,其余是值传递
[&,foo] foo使用值传递方式传递,其余是引用方式传递
[this] 在函数内部可以使用类的成员函数和成员变量


在Lambda表达式后加一个括号表示调用

②(params)函数参数表

值传递和引用传递,省略相当于无参

③opt选项

这部分可以省略,是一个选项,常用mutable声明

Lambda表达式外部的局部变量通过值传递进来时,默认为const,所以不能修改这个局部变量的拷贝,加上mutable就可以修改

mutable的使用

④->ret返回类型

可以指定Lambda表达式的返回类型,如果不指定则为编译器自己根据代码推导的一个返回类型,如果返回类型是void那不用写

⑤{Function body}函数体

函数定义在这大括号中

六、信号和槽的优缺点

优点:低耦合,信号和槽不是绑定在一起的,改变信号函数不会影响槽函数,改变槽函数也不会影响信号函数,它们只在发送信号的一瞬间建立联系

缺点:效率低,但这个低是相对于回调函数来说的,但是这个效率低的影响不大,因为对于人来说是感知不到的


今日分享就到这里~

相关推荐
学习前端的小z2 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
CV学术叫叫兽9 分钟前
一站式学习:害虫识别与分类图像分割
学习·分类·数据挖掘
神仙别闹10 分钟前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#
XINGTECODE11 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
我们的五年20 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
zwjapple27 分钟前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five28 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
前端每日三省30 分钟前
面试题-TS(八):什么是装饰器(decorators)?如何在 TypeScript 中使用它们?
开发语言·前端·javascript
gma99937 分钟前
Etcd 框架
数据库·etcd
爱吃青椒不爱吃西红柿‍️40 分钟前
华为ASP与CSP是什么?
服务器·前端·数据库