信号信号槽

news2024/11/20 12:31:02

三、信号槽

  1. 概念

信号和槽是两种函数,这是Qt在C++基础上新增的特性,类似于其他技术中的回调的概念。

信号槽通过程序员提前设定的“约定”,可以实现对象之间的通信,有两个先决条件。

  • 通信的对象都是在QOBject类中派生出来的。

QOBject类是Qt所有类型的基类。

  • 类中要有Q_OBJECT宏。

  1. 函数原型

信号槽需要在使用进行“约定”。这个约定也称为连接。

【例子】:如果新周考试考100分,那么宵宾请新周吃饭。

// 参数1:发射者,表示因发起的对象【新周】
// 参数2:信号函数,表示因发起的动作【考100】
// 参数3:接收者,表示果发起的对象【宵宾】
// 参数4:槽函数,表示果发起的动作【请吃饭】
connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method)[static]

  1. 实现

为了学习,把信号槽分为三种实现的方式。

  • 自带信号→自带槽
  • 自带信号→自定义槽
  • 自定义信号

3.1 自带信号→自带槽

这种连接方式是最简单的,因为信号函数和槽函数都是Qt内置的,只需要在文档中查询出函数后,使用connect函数连接即可。

【例子】:点击按钮,关闭窗口。

// 点击按钮,发射此信号
void QAbstractButton::​clicked(bool checked = false)[signal]

// 关闭窗口槽函数
bool QWidget::​close()[slot]

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn; // 成员变量
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口的宽高
    resize(500,500);

    btn = new QPushButton("关闭",this);
    // 设置按钮位置
    btn->move(200,250);

    // 连接信号槽【点击按钮,关闭窗口】
    // 参数1:按钮对象
    // 参数2:点击信号函数clicked
    // 参数3:窗口对象
    // 参数4:关闭窗口槽函数close
    connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}

Dialog::~Dialog()
{
    // 堆内存回收
    delete btn;
}

3.2 自带信号→自定义槽

Qt不可能内置所有执行的动作代码,特别是一些复杂的动作,需要开发者手动编写槽函数,这种方式是所有连接方式中使用最多的。

槽函数实际上是一种特殊的成员函数,在声明的时候权限的作用主要是修饰其作为普通成员函数的使用效果,不影响信号槽的连接效果。

【例子】:点击按钮,向右边和下边移动窗口10个相似,同时输出当前窗口的坐标。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn; // 成员变量

private slots:
    void mySlot(); // 小驼峰命名:第一个单词小写,其他单词首字母大写

};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口的宽高
    resize(500,500);

    btn = new QPushButton("关闭",this);
    // 设置按钮位置
    btn->move(200,250);
    // 连接信号槽
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}

// 自定义槽函数实现
void Dialog::mySlot()
{
    // 先获取当前的坐标
    int x = this->x();
    int y = this->y();

    // 移动坐标位置
    move(x+10,y+10);

    // 输出当前位置
    qDebug() << x+10 << y+10;
}

Dialog::~Dialog()
{
    // 堆内存回收
    delete btn;
}

3.3 自定义信号

为了讲解,强行使用自定义信号,并非问题的最优解,主要学习写法。

信号函数是一种非常特殊的函数,因为只有声明,没有定义。即没有函数体,因此无法调用,只能使用emit关键字发射。

【例子】:点击按钮,关闭窗口。

3.1 的信号连接方式。

本节中强行在中间加一层自定义信号的转发过程。

上图中→表示信号槽连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
private:
    QPushButton *btn;

private slots:
    void mySlot();

    // 自定义信号
signals:
    void mySignal();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 创建按钮对象
    btn = new QPushButton("关闭",this);
    btn->move(100,150);

    // 信号槽连接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));

    // 第二次槽函数连接
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}


void Dialog::mySlot()
{
    // 发射自定义信号
    emit mySignal();
}

Dialog::~Dialog()
{
    delete btn;
}

4、信号槽传参

【例子】点击按钮,按钮上显示点击的次数。

 QPushButton的按钮文字属性为text : QString,可以使用setter更改按钮文字。

// 设置按钮显示的文字
// 显示的文字,QString类型
void	setText(const QString & text)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QPushButton *btn;

private slots:
    void mySlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    btn = new QPushButton("0",this);
    btn->move(100,150);
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}

Dialog::~Dialog()
{
    delete btn;
    delete ui;
}

void Dialog::mySlot()
{
    // 静态局部变量
   static int count = 0;
   count++;
   // 类型转换 int → QString
   QString text = QString::number(count);

   // 更改按钮文字
   btn->setText(text);

}

把上面的案例强行改为信号槽传参:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QPushButton *btn;

private slots:
    void mySlot();
    void mySlot2(int); // 与mySignal(int)连接的自定义槽函数
signals:
    void mySignal(int); // 带参数的信号函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    btn = new QPushButton("0",this);
    btn->move(100,150);
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(this,SIGNAL(mySignal(int)),
            this,SLOT(mySlot2(int)));
}

Dialog::~Dialog()
{
    delete btn;
    delete ui;
}

void Dialog::mySlot()
{
    // 静态局部变量
    static int count = 0;
    count++;

    emit mySignal(count);
}

void Dialog::mySlot2(int count)
{
    // 类型转换 int → QString
    QString text = QString::number(count);

    // 更改按钮文字
    btn->setText(text);
}

需要注意的是:

  • 理论上可以传递多个参数,建议最多写两个参数,多了会很冗余。如果非得传递多个参数,可以定义成一个类,传递对象。
  • 信号的参数个数必须大于等于槽函数参数个数。
  • 信号的参数类型要与槽的参数相匹配。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Demo
{
public:
    int a = 10;
    int b = 20;
    double c = 3.23;
    float d = 1.1;
};


class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn;

private slots:
    void mySlot();  // 自定义槽函数
    void mySlot2(const Demo &); // 与mySignal(int)连接的自定义槽函数

signals:
    void mySignal(const Demo &); // 带参数的信号函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);
    btn = new QPushButton("0",this);
    btn->move(150,150);

    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(this,SIGNAL(mySignal(const Demo &)),this,SLOT(mySlot2(const Demo &)));
}

void Dialog::mySlot()
{
    Demo demo;
    // 发射带参数的自定义信号函数
    emit mySignal(demo);
}

void Dialog::mySlot2(const Demo &demo)
{
    qDebug() << demo.a;
    qDebug() << demo.b;
    qDebug() << demo.c;
    qDebug() << demo.d;
}

Dialog::~Dialog()
{
    delete btn;
}

5、对应关系

5.1 一对多

一对多指的是一个信号可以连接多个槽函数。

对于一对多的连接关系,可以合并为一对一,因为槽函数也是一个成员函数,可以整合到一个槽函数中进行连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn1; // 一对多
    QPushButton *btn2; // 一对一

private slots:
    void mySlot1();
    void mySlot2();
    void mySlot3();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);
    btn1 = new QPushButton("一对多",this);
    btn1->move(200,200);
    // 一对多的优势就是可以灵活处理每个对应关系
    // 例如可以断开某个信号槽的连接
    // 断开连接的函数与连接槽函数一样,只需要在函数名称前面加dis
    disconnect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));

    // 一对多
    connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot1()));
    connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));

    // 一对一
    btn2 = new QPushButton("一对一",this);
    btn2->move(200,250);
    connect(btn2,SIGNAL(clicked()),this,SLOT(mySlot3()));

    disconnect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));
}

Dialog::~Dialog()
{

}

void Dialog::mySlot1()
{
    qDebug() << "A" ;
}
void Dialog::mySlot2()
{
    qDebug() << "B" ;
}


void Dialog::mySlot3()
{
    mySlot1();
    mySlot2();
}

5.2 多对一

多对一指的是多个信号连接同一个槽函数,多对一的问题在于槽函数无法直接判断那个信号触发的槽函数调用,但是可以通过sender函数在槽函数中获得发射者对象,通过对象的比对判断来源。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
private:
    QPushButton *btn1;
    QPushButton *btn2;

private slots:
    // 多对一的槽函数
    void btnClickedSlot();

};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);
    btn1 = new QPushButton("多对一A",this);
    btn1->move(200,200);

    btn2 = new QPushButton("多对一B",this);
    btn2->move(200,250);

    // 多对一
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
    connect(btn2,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}

Dialog::~Dialog()
{
    delete btn1;
    delete btn2;
}

void Dialog::btnClickedSlot()
{
    if(btn1 == sender())
    {
        qDebug() << "A" ;
    }
    else if(btn2 == sender())
    {
        qDebug() << "B" ;
    }
    else
    {
        qDebug() << "对象错误" ;
    }
}

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

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

相关文章

Linux环境非root用户配置SSH免密登录,并解决登录仍提示输入密码

Linux环境非root用户配置SSH免密登录&#xff0c;并解决登录仍提示输入密码 ssh免密登录的简单理解 以A和B进行举例&#xff1a;A免密登录B &#xff08;即在A服务器输入命令&#xff1a;ssh 非root用户名B的IP地址&#xff09;可以直接免密码直接登录 A生成私钥和公钥&#…

​​​​​​​Sora:OpenAI的革命性AI视频模型与其对未来影像创作的影响

随着深度学习技术和计算能力的进步&#xff0c;人工智能不仅在图像识别、自然语言处理等领域取得了卓越成就&#xff0c;同时也在不断突破视频处理和生成的边界。在这一背景下&#xff0c;OpenAI推出了Sora——一种新型的AI视频模型&#xff0c;标志着AI在视频内容创作领域的又…

云呐智能维运技术有哪些?智能运维活动有哪些

智能运维&#xff08;AIOps&#xff09;技术是指利用人工智能、机器学习、大数据分析等先进技术手段&#xff0c;来提高IT运维效率和质量的一系列技术和工具。目前常见的智能运维技术核心功能和应用场景。一些具体的智能运维活动案例&#xff0c;包括但不限于故障预测、自动化修…

[hgame 2024 week3] crypto/pwn

第2周作完了不知道扔哪去了&#xff0c;先记录下第3周&#xff0c;因为官方WP已经出来&#xff0c;顺便把没出的题复现一下。最近的比赛都比较不错&#xff0c;相当于近期知识点的总结&#xff0c;有点心经的意思。 Crypto matrix_equation 题目很短&#xff0c;结了一个式子…

数据可视化在商业领域有哪些重要性?

数据可视化在商业领域的重要性体现在多个方面&#xff0c;它通过将复杂的数据集转化为直观、易于理解的图形和图表&#xff0c;帮助企业和组织做出更明智的决策。以下是数据可视化对商业的一些关键重要性&#xff1a; 提高决策效率&#xff1a;通过直观的图表和图形&#xff0c…

防御保护第八、九、十、十一天笔记

一、内容安全 1、DFI和DPI技术 --- 深度检测技术 DPI是一种基于应用层的流量检测和控制技术&#xff0c;它会对流量进行拆包&#xff0c;分析包头和应用层的内容&#xff0c;从而识别应用程序和应用程序的内容。这种技术增加了对应用层的分析&#xff0c;识别各种应用&#xf…

主流开发语言和开发环境:探索编程世界的基础

在当今这个快速发展的技术时代&#xff0c;软件开发已经成为推动创新的重要力量。无论是构建下一代应用、开发先进的算法还是创建复杂的系统&#xff0c;选择合适的编程语言和开发环境都是至关重要的。在本文中&#xff0c;我们将探讨当前流行的几种主流开发语言以及它们常用的…

敏捷项目管理在现代软件开发中的应用

在现代软件开发领域&#xff0c;项目管理起着至关重要的作用。随着技术的不断进步和市场需求的快速变化&#xff0c;传统的项目管理方法已逐渐无法满足软件开发的需求。因此&#xff0c;敏捷项目管理应运而生&#xff0c;成为许多软件开发团队的首选方法。本文将探讨敏捷项目管…

基于Python3的数据结构与算法 - 04 快速排序

一、快速排序思路 快速排序特点&#xff1a;快 步骤&#xff1a; 取一个元素p&#xff08;第一个元素&#xff09;&#xff0c;使元素p归为&#xff1b;列表被p分成两部分&#xff0c;左边都比p小&#xff0c;右边都比p大&#xff1b;递归完成排序。 因此我们可以得到快速排…

数字化转型导师坚鹏:政府数字化转型案例研究(包括省市政府)

政府数字化转型案例研究&#xff08;包括省市政府&#xff09; 课程背景&#xff1a; 很多地方政府存在以下问题&#xff1a; 不清楚标杆省政府数字化转型的成功案例 不清楚直辖市政府数字化转型的成功案例 不清楚地级市政府数字化转型的成功案例 课程特色&#xff1a…

实验室电磁铁工作环境及操作方法

1、工作环境 &#xff08;1&#xff09; 环境温度5℃-30℃ &#xff08;2&#xff09; 相对湿度不大于70% &#xff08;3&#xff09; 无腐蚀性气体以及对绝缘有损害的气体 &#xff08;4&#xff09;无其他电磁干扰设备 2、电磁铁使用操作方法 &#xff08;1&#xff09…

有哪些适合程序员的副业

如果你经常玩知乎、看公众号&#xff08;软件、工具、互联网这几类的&#xff09;你就会发现&#xff0c;好多资源连接都变成了夸克网盘、迅雷网盘的资源链接。 例如&#xff1a;天涯神贴&#xff0c;基本上全是夸克、UC、迅雷网盘的资源链接。 有资源的前提下&#xff0c;迅雷…

VBA代码实现excel表格输入内容自动调整行高、列宽

打开excel表&#xff0c;如图1 右键点击表标签名&#xff0c;如&#xff1a;“sheet1”&#xff0c;弹出菜单&#xff0c;点击查看代码 代码编辑窗口 点击图中蓝色部分 点击worksheet&#xff0c;创建子程序&#xff0c;Private Sub Worksheet_SelectionChange(ByVal Target…

实习日志30

概要 高拍仪硬件通信原理&#xff0c;WebSocket源码解析&#xff08;JavaScript&#xff09; WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据…

关于使用Mxnet GPU版本运行DeepAR报错解决方案

1.引言 我们经常使用GPU来训练和部署神经网络&#xff0c;因为与CPU相比&#xff0c;它提供了更多的计算能力。在本教程中&#xff0c;我们将介绍如何将GPU与MXNet GluonTS一起使用。 首先&#xff0c;确保您的机器中至少有一个Nvidia GPU&#xff0c;并正确安装了CUDA以及CUDN…

【算法分析与设计】1的个数

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位…

Windows系统中定时执行python脚本

背景&#xff1a;本地Windows系统指定目录下会有文件的修改新增&#xff0c;这些变化的文件需要定时的被上传到git仓库中&#xff0c;这样不需要每次变更手动上传了。 首先编写一个检测文件夹下文件变化并且上传git仓库的python脚本(确保你已经在E:\edc_workspace\data_edc_et…

深度学习环境配置常见指令

首先打开anaconda prompt&#xff0c;激活对应虚拟环境。 导入torch并获取对应版本 import torch torch.__version__导入torchvision并获取对应版本 import torchvision torchvision.__version__ 检查cuda是否可用 torch.cuda.is_available() 获取CUDA设备数 torch.cuda.…

【知识整理】Git Commit Message 规范

一. 概述 前面咱们整理过 Code Review 一文&#xff0c;提到了 Review 的重要性&#xff0c;已经同过gitlab进行CodeReview 的方式&#xff0c;那么本文详细说明一下对CodeReivew非常重要的Git Commit Message 规范。 我们在每次提交代码时&#xff0c;都需要编写 Commit Mes…

Rabbitmq入门与应用(一)-rabbitmq安装(docker版)

Rabbitmq入门与应用-rabbitmq安装(docker版) RabbitMQ简介 什么是RabbitMQ&#xff1f; RabbitMQ is a message broker: it accepts and forwards messages. You can think about it as a post office: when you put the mail that you want posting in a post box, you can …