【Qt 学习笔记】详解Qt中的信号和槽


  • 博客主页:Duck Bro 博客主页
  • 系列专栏:Qt 专栏
  • 关注博主,后期持续更新系列文章
  • 如果有错误感谢请大家批评指出,及时修改
  • 感谢大家点赞👍收藏⭐评论✍

详解Qt中的信号与槽

文章编号:Qt 学习笔记 / 12

文章目录

  • 详解Qt中的信号与槽
    • 一、信号和槽的基本概念
      • 1. 什么是信号
        • 1.1 信号本质
        • 1.2 信号举例
      • 2. 什么是槽
        • 2.1 槽的本质
        • 2.2 说明
    • 二、信号和槽如何使用
      • 1. connect函数
        • 1.1 函数原型
        • 1.2 参数说明
        • 1.3 代码示例
      • 2. 如何查看内置信号和槽
        • 2.1 查询信号
        • 2.1 查询槽
      • 3. 使用 Qt Creator 生成信号槽代码(图形化快速生成信号槽代码)
        • 3.1 实现步骤
        • 3.2 实现结果
    • 三、自定义信号和槽
      • 1. 基础语法
        • 1.1 自定义信号函数书写规范
        • 1.2 自定义槽函数书写规范
        • 1.3 发送信号
        • 1.4 示例代码
      • 2. 带参数的信号和槽
        • 2.1 示例代码
    • 四、信号与槽的连接方式
      • 1. 一对一
        • 1.1 信号连接槽
        • 1.2 信号连接信号
      • 2. 一对多
      • 3. 多对一
    • 五、信号与槽的优缺点
      • 1. 优点: 松散耦合
      • 2. 缺点: 效率较低


一、信号和槽的基本概念

QT中的信号和槽是用于实现对象之间的通信的机制。每个对象都可以发出一个信号,其他对象可以通过连接到该信号的槽来接收并处理信号。

通过将信号和槽连接起来,可以实现对象之间的交互和通信。一个对象的信号可以连接到其他对象的槽,也可以将多个信号连接到同一个槽上。

Qt中可以使用connect函数,把一个信号和一个槽关联起来,后续只要信号触发,Qt就会自动执行槽函数。

在这里插入图片描述

信号源:由哪个控件发出信号
信号类型:用户进行不同的操作,就可能触发不同的信号
信号处理方式:槽(slot)== 函数

QT中的信号和槽是通过使用QObject类的特性来实现的,需要使用宏来声明信号和槽,并使用信号和槽的宏来进行连接。QT提供了一个QMetaObject系统来管理信号和槽的连接和调用。

使用信号和槽机制可以使代码更加灵活,模块化和可重用。它使得对象之间的交互变得简单而直观,并允许通过连接和断开连接来动态地改变交互方式。

在这里插入图片描述

1. 什么是信号

信号可以被认为是一个事件,当某些条件发生时,对象会发出一个信号。例如,鼠标点击、键盘输入或者是对象的状态改变都可以作为信号。

1.1 信号本质

信号是由于用户对窗⼝或控件进行了某些操作,导致窗⼝或控件产⽣了某个特定事件,这时 Qt 对
应的窗⼝类会发出某个信号,以此对⽤⼾的操作做出反应。

1.2 信号举例

信号的本质就是事件

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

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

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

2. 什么是槽

槽是接收信号的函数,当一个信号被发出时,连接到该信号的槽会被调用。槽可以执行任意代码,包括更新界面、处理数据等。

2.1 槽的本质

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

2.2 说明

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

例如: “按钮被按下” 这个信号可以⽤ clicked() 函数表示,“窗⼝关闭” 这个槽可以用 close() 函数表示,假如使⽤信号和槽机制-实现:“点击按钮会关闭窗口” 的功能,其实就是 clicked() 函数调⽤ close() 函数的效果。

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

  • 信号函数⽤ signals 关键字修饰,槽函数⽤ public slots、protected slots 或者 private slots 修饰。signalsslots 是 Qt 在 C++ 的基础上扩展的关键字,专⻔⽤来指明信号函数和槽函数;

  • 信号函数只需要声明,不需要定义(实现),而槽函数需要定义(实现)。

在这里插入图片描述


二、信号和槽如何使用

1. connect函数

1.1 函数原型
connect (const QObject * sender,  //sender:信号的发送者
 		 const char * signal ,    //signal:发送的信号(信号函数)
 		 const QObject * receiver , //receiver:信号的接收者
 		 const char * method , 		//method:接收信号的槽函数
 		 Qt::ConnectionType type = Qt::AutoConnection )  //目前阶段不用考虑,用的不多
		 //⽤于指定关联⽅式,默认的关联⽅式为 Qt::AutoConnection,通常不需要⼿动设定。
1.2 参数说明

• sender:信号的发送者;
• signal:发送的信号(信号函数);
• receiver:信号的接收者;
• method:接收信号的槽函数;
• type:用于指定关联方式,默认的关联⽅式为 Qt::AutoConnection,通常不需要手动设定。

1.3 代码示例

代码功能:在窗⼝中设置⼀个按钮,当点击 “按钮” 时关闭 “窗⼝”

使用connect进行信号和槽连接,实现点击按钮 关闭窗口的功能
在这里插入图片描述
示例代码:

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton* button = new QPushButton(this);
    button -> setText("按钮");    //设置按钮文本
    button->resize(100,100);     //设置按钮大小   
    button->move(200,200);       //设置按钮位置
    
    //连接信号和槽 实现点击按钮  关闭窗口的功能
    connect(button,&QPushButton::clicked,this,&Widget::close);  
}

Widget::~Widget()
{
    delete ui;
}


2. 如何查看内置信号和槽

在上述代码中使用到的信号和槽可以在“Qt帮助文档(Assistant)”中查看,下面介绍如何查看Qt内置的信号和槽,下面以查询“QPushButton(按钮)”的信号为例。

2.1 查询信号
  1. 打开Assistant,在索引栏中输入QPushButton
    在这里插入图片描述

  2. 然后可以在 “Contents” 中寻找关键字 signals,如果没有请看下一步
    在这里插入图片描述

  3. 如果没有找到, 继续去⽗类中查找.,点击父类QAbstractButton
    在这里插入图片描述

  4. 在⽗类 QAbstractButton 中继续查找关键字signals
    在这里插入图片描述

  5. 找到信号clicked()
    在这里插入图片描述

2.1 查询槽

槽函数的寻找⽅式和信号⼀样,只不过它的关键字是 slot

3. 使用 Qt Creator 生成信号槽代码(图形化快速生成信号槽代码)

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

3.1 实现步骤

代码示例如下:
代码功能:在窗⼝中设置⼀个按钮,当点击 “按钮” 时关闭 “窗⼝”

  1. 新建一个Qt项目,如下图为新建完成之后所包含的所有⽂件;
    在这里插入图片描述

  2. 打开widget.ui文件,进入UI界面
    在这里插入图片描述

  3. 在界面中放置一个按钮,并且修改按钮的大小及名称
    在这里插入图片描述

  4. 右键按钮,选择转到槽,生成槽函数
    在这里插入图片描述

  5. 选择信号clicked(),点击OK
    在这里插入图片描述

  6. 自动生成槽函数原型框架

  • 在 “widget.h” 头⽂件中⾃动添加槽函数的声明
    在这里插入图片描述

说明:
⾃动⽣成槽函数的名称有⼀定的规则。槽函数的命名规则为:on_XXX_SSS,其中:
1. 以 " on " 开头,中间使用下划线连接起来;
2. " XXX " 表示的是对象名(控件的 objectName 属性)。
3. " SSS "表示的是对应的信号。

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

在这里插入图片描述

  • 在 “widget.cpp” 文件中⾃动⽣成槽函数定义.
    在这里插入图片描述
  1. 在槽函数函数定义中添加要实现的功能. 实现关闭窗口的效果.
    在这里插入图片描述
3.2 实现结果

点击按钮窗口关闭。
在这里插入图片描述


三、自定义信号和槽

1. 基础语法

在Qt中,自定义信号和槽可以通过使用signals和slots关键字来定义,在日常项目中用到较少。

在 Qt 中,允许⾃定义信号的发送⽅以及接收⽅,即可以⾃定义信号函数和槽函数。但是对于⾃定义的信号函数和槽函数有⼀定的书写规范

需要注意的是,为了使用自定义信号和槽,类必须包含Q_OBJECT宏,并且需要使用Qt的元对象编译系统(MOC)。这意味着类定义必须位于一个.h文件中,并且在CMake或QMake构建系统中添加适当的语句来使用MOC编译器。

1.1 自定义信号函数书写规范
  • ⾃定义信号函数必须写到 “signals” 下;
  • 返回值为 void,只需要声明,不需要实现;
  • 可以有参数,也可以发⽣重载;
1.2 自定义槽函数书写规范
  • 早期的 Qt 版本要求槽函数必须写到 “public slots” 下,但是现在⾼级版本的 Qt 允许写到类的"public" 作⽤域中或者全局下;
  • 返回值为 void,需要声明,也需要实现;
  • 可以有参数,可以发⽣重载;
1.3 发送信号
  • 使⽤ “emit” 关键字发送信号 。“emit” 是⼀个空的宏。“emit” 其实是可选的,没有什么含义,只是为了提醒开发⼈员。
1.4 示例代码
  1. 在 widget.h 中声明⾃定义的信号和槽
    在这里插入图片描述
    2.在 widget.cpp 中实现槽函数,并且关联信号和槽
    在这里插入图片描述
    示例代码:
//widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

signals:
    void MySignal();//信号声明

public:
    void MySlots();//槽函数声明

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
//widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(this,&Widget::MySignal,this,&Widget::MySlots);
    //emit MySignal();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::MySlots()
{
    this->setWindowTitle("修改窗口1");
}


void Widget::on_pushButton_clicked()
{
    emit MySignal();
}

2. 带参数的信号和槽

Qt 的信号和槽也可以带有参数, 同时也可以⽀持重载.
信号函数的参数列表要和对应连接的槽函数参数列表⼀致.

此时信号触发, 调⽤到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中,就起到让信号给槽传参的效果

注意:为了使用自定义信号和槽,类必须包含Q_OBJECT宏,并且需要使用Qt的元对象编译系统(MOC)。这意味着类定义必须位于一个.h文件中,并且在CMake或QMake构建系统中添加适当的语句来使用MOC编译器。

2.1 示例代码

自定义信号和槽,参数必须一致,主要要求类型一致;个数如果不一致也可以,要求信号参数个数比槽参数个数多要多

注意:一个槽函数, 有可能会绑定多个信号,如果我们严格要求参数个数一致,就意味着信号绑定到槽的要求就变高了换而言之,当下这样的规则,就允许信号和槽之间的绑定更灵活了更多的信号可以绑定到这个槽函数上了

在这里插入图片描述
在这里插入图片描述

//widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


signals:
        void MySignals(const QString& text1,const QString& text2);        //此处text可以省略


public:
        void handleMySignal(const QString& text);   //此处text可以省略

private slots:
        void on_pushButton_clicked();          //UI自动生成的槽函数

        void on_pushButton_2_clicked();        //UI自动生成的槽函数

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

//widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(this,&Widget::MySignals,this,&Widget::handleMySignal);

}

Widget::~Widget()
{
    delete ui;
}

void Widget::handleMySignal(const QString& text)
{
    qDebug()<<text;
    this->setWindowTitle(text);
}


void Widget::on_pushButton_clicked()
{
    emit MySignals("按钮1修改参数","");
}

void Widget::on_pushButton_2_clicked()
{
    emit MySignals("按钮2修改参数","");
}


四、信号与槽的连接方式

1. 一对一

分为两种形式:⼀个信号连接⼀个槽 和 ⼀个信号连接⼀个信号。

1.1 信号连接槽

在这里插入图片描述

  • 在 “widget.h” 中声明信号和槽
    在这里插入图片描述
  • 在 “widget.cpp” 中实现槽函数,信号发射函数以及连接信号和槽
    在这里插入图片描述
1.2 信号连接信号

在这里插入图片描述

  • 在 “widget.cpp” ⽂件中添加如下代码:
    在这里插入图片描述
    在这里插入图片描述

2. 一对多

在这里插入图片描述

  • 在 “widget.h” 头⽂件中声明⼀个信号和三个槽
    在这里插入图片描述
  • 在 “widget.cpp” ⽂件中实现槽函数以及连接信号和槽;
    在这里插入图片描述

3. 多对一

在这里插入图片描述

  • 在 “widget.h” 头⽂件中声明两个信号以及⼀个槽
    在这里插入图片描述

  • 在 “widget.cpp” ⽂件中实现槽函数以及连接信号和槽
    在这里插入图片描述


五、信号与槽的优缺点

1. 优点: 松散耦合

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

2. 缺点: 效率较低

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


在这里插入图片描述

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

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

相关文章

【Node.js】短链接

原文链接&#xff1a;Nodejs 第六十二章&#xff08;短链接&#xff09; - 掘金 (juejin.cn) 短链接是一种缩短长网址的方法&#xff0c;将原始的长网址转换为更短的形式。短链接的主要用途之一是在社交媒体平台进行链接分享。由于这些平台对字符数量有限制&#xff0c;长网址可…

旋转花键有哪些优缺点?

旋转花键是在花键外筒的外径上装上专用的轴承外套&#xff0c;使之运转动作&#xff0c;适用于水平多关节机械手臂&#xff08;SCARA&#xff09;、产业用机器人、自动装载机、镭射加工机、搬送装置、机械加工中心的ATC装置等各项设备。 目前&#xff0c;旋转花键的应用越来越普…

redis 哨兵

文章目录 前言主从复制的问题怎么人工恢复故障主节点 Redis Setinel 架构使用 docker 来配置哨兵结构安装 docker编排 redis 主从节点编排 redis 哨兵节点 观察哨兵模式的作用主从切换的具体流程小结 前言 redis 主从复制模式下, 一旦主节点出现故障, 不能提供服务的时候, 就需…

刷题之Leetcode283题(超级详细)

283.移动零 283. 移动零https://leetcode.cn/problems/move-zeroes/ 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nu…

第十讲 Query Execution Part 1

1 处理模型【Processing Model】 DBMS 的处理模型【Processing Model】定义了系统如何执行【execute】查询计划【Query Plan】。 针对不同的工作负载进行不同的权衡。 方法1&#xff1a;迭代器模型【Iterator Model】 方法2&#xff1a;物化模型【Materialization Model】 方…

创建和启动线程

概述 Java语言的JVM允许程序运行多个线程&#xff0c;使用java.lang.Thread类代表线程&#xff0c;所有的线程对象都必须是Thread类或其子类的实例。 Thread类的特性 每个线程都是通过某个特定Thread对象的run()方法来完成操作的&#xff0c;因此把run()方法体称为线程执行体。…

数据结构之堆底层实现的循序渐进

题外话 把没写的都补回来! 正题 堆 概念 堆是一棵完全二叉树&#xff0c;因此可以层序的规则采用顺序的方式来高效存储&#xff0c; 大根堆:指根结点比左右孩子都大的堆 小根堆:指根结点比左右孩子都小的堆 性质 1.堆中某个节点的值总是不大于或不小于其父节点的值 2…

CCIE-14-MPLS_and_BGP

目录 实验条件网络拓朴 环境配置开始配置配置MPLSR1访问R6检测结果R6访问R1检测结果 实验条件 网络拓朴 环境配置 在我的资源里可以下载&#xff08;就在这篇文章的开头也可以下载&#xff09; 开始配置 R1<->R2&#xff1a;EBGP R2<->R5&#xff1a;IBGP&…

蓝桥杯备考3

P8196 [传智杯 #4 决赛] 三元组 题目描述 给定一个长度为 n 的数列 a&#xff0c;对于一个有序整数三元组 (i,j,k)&#xff0c;若其满足 1≤i≤j≤k≤n 并且&#xff0c;则我们称这个三元组是「传智的」。 现在请你计算&#xff0c;有多少有序整数三元组是传智的。 输入格式…

小米手机澎湃OS,不Root查看电池健康

首先&#xff0c;在键盘拨号界面&#xff0c;输入*#*#284#*#*&#xff0c;会调用问题反馈APP来生成当前系统的故障日志&#xff0c;如果提示你需要授权什么就点确认 稍等几分钟&#xff0c;会得到一个压缩包&#xff0c;保存在目录MIUI/debug_log下 这里为了方便&#xff0c;我…

肖恩带你学C语言·文件操作(上)

1. 为什么使用文件 如果没有文件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运行程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进行持久化的保存&…

打造自然资源“一张图”管理平台,推动生态文明建设新篇章

在信息化时代的浪潮下&#xff0c;自然资源管理正面临着前所未有的挑战与机遇。传统的资源管理模式已经难以满足当前生态环境保护与经济发展的双重需求&#xff0c;我们需要一个全新的平台&#xff0c;一个集信息集成、智能分析、决策支持于一体的自然资源“一张图”管理平台。…

数据可视化-地图可视化-Python

师从黑马程序员 基础地图使用 基础地图演示 视觉映射器 具体颜色对应的代码可以在http://www.ab173.com/中查询RGB颜色查询对照表 from pyecharts.charts import Map from pyecharts.options import VisualMapOpts#准备地图对象 mapMap() #准备数据 data[("北京",…

c语言结构体变量和结构体数组的练习(自用版)

结构体变量注释和结构体数组练习&#xff08;已注释&#xff09;代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> struct Student {char name[20];int age;char sex;float score;char addr[30]; };int main() {//练习结构体变量struct Student s…

SSL/TLS:网络安全中的基石

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

c# wpf LiveCharts 简单试验2

1.概要 1.1 说明 1.2 要点 1.2.1 添加命名控件 xmlns:lvc"clr-namespace:LiveCharts.Wpf;assemblyLiveCharts.Wpf" 1.2.2 图片控件 <lvc:CartesianChart Name"chart" LegendLocation"Right"/> 1.3 代码文件引用 using LiveCharts…

YOLOv5实战记录05 Pyside6可视化界面

个人打卡&#xff0c;慎看。 指路大佬&#xff1a;【手把手带你实战YOLOv5-入门篇】YOLOv5 Pyside6可视化界面_哔哩哔哩_bilibili 零、虚拟环境迁移路径后pip报错解决 yolov5-master文件夹我换位置后&#xff0c;无法pip install了。解决如下&#xff1a; activate.bat中修改…

刷题之Leetcode844题(超级详细)

844.比较退格的字符串 844. 比较含退格的字符串https://leetcode.cn/problems/backspace-string-compare/ 给定 s 和 t 两个字符串&#xff0c;当它们分别被输入到空白的文本编辑器后&#xff0c;如果两者相等&#xff0c;返回 true 。# 代表退格字符。 注意&#xff1a;如…

5G网络架构及技术(二):OFDM一

ToDo: 等把这些讲义看完后得单开一个文章整理思维导图   该部分由于内容比较重要&#xff0c;OFDM是5G物理层的基础&#xff0c;但学习时直接跳到5G OFDM去看它的那些参数设置感觉没什么意义&#xff0c;还得从发展的角度进行学习&#xff0c;先从最先用到OFDM的WiFi协议开始…

CSS-属性

&#x1f4da;详见 W3scholl&#xff0c;本篇只做快速思维索引。 CSS 背景 用于定义元素的背景效果。 background-colorbackground-imagebackground-positionbackground-repeatbackground-attachment background-color background-color 属性指定元素的背景色。 h1 {back…