信号信号槽

三、信号槽

  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() << "对象错误" ;
    }
}

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

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

相关文章

提升App推广效果,从优化落地页开始

在App推广过程中&#xff0c;落地页的转化率一直是推广运营者关注的重点。然而&#xff0c;很多运营者发现&#xff0c;即使使用了相同的工具和模板&#xff0c;别人的效果却远远超出自己。那么&#xff0c;问题到底出在哪里呢&#xff1f;今天&#xff0c;我们就来聊聊如何提升…

便携式气象站的安装注意事项

型号推荐&#xff1a;云境天合TH-BQX9】便携式气象站的安装注意事项包括以下几点&#xff1a; 安装前检查&#xff1a;在安装前&#xff0c;应对便携式气象站进行检查&#xff0c;确保设备的包装完好无损&#xff0c;配件齐全&#xff0c;如气象站传感器、支架、采集器和传输模…

链表和顺序表的优劣分析及其时间、空间复杂度分析

链表和顺序表的优劣分析及其时间、空间复杂度分析 一、链表和顺序表的优劣分析二、算法复杂度<font face "楷体" size 5 color blue>//上面算法的执行次数大致为&#xff1a;F&#xff08;N&#xff09; N^22*N10;   N 10,F(10) 1002010 130次   N 1…

提高学习效率和速度的方法

如下是一些策略和方法来帮助提高学习效率和速度&#xff1a; 1. **主动学习**&#xff1a;主动寻找信息并提出问题&#xff0c;而不是被动接受。这样可以提高您的学习动力和效率。 2. **分块学习**&#xff1a;将复杂的知识点分解成小块&#xff0c;逐一理解和掌握。这种方法可…

unity屏幕受伤特效

//使用用途&#xff1a;同于屏幕掉血的后处理特效 //请结合和脚本&#xff1a;BloodScreen 挂载至摄像机使用本特效 //本特效设计之初未考虑兼容移动设备&#xff0c;请注意//使用说明&#xff1a; //掉血获取此脚本&#xff0c;将showBlood设置为true&#xff0c;如果您需要更…

Js的 Promise的 then catch 笔记240222

Js的 Promise的 then catch 笔记240222 基本用法 new Promise(f>{setTimeout(ev>{f("一秒后输出控制台");},1000); }).then(f的参数>{console.log(f的参数); }); // 控制台输出: 一秒后输出控制台上面代码中, f 的标准名叫做 resolve , 所以应该写成 new …

函数栈帧的创建及销毁(超详解)

目录 1.预备知识 1.1内存区的划分 1.2认识相关寄存器和汇编指令 1.2.1寄存器 1.2.2相关汇编指令 2.测试前 2.1测试代码及环境 2.2 main函数也是被其他函数调用的 3.函数栈帧的创建 4.进入函数内部 5.形参与实参 6.call/jump add函数 7.函数栈帧的销毁 7.1保存…

使用python查看官网是否发布新的内容

目录 前言 第一章、python介绍和使用pip install下载包 1.python介绍 2.使用vscode编写python 3.pip install的使用 第二章、查看官网是否发布新的内容 第三章、代码实现 目录结构 代码实现 check_new_news.py files.py news.py main.py file.txt 运行演示 前言 也…

【已解决】@tableid can‘t more than one

实体里面不能有两个TableId&#xff0c;只留一个就好了

SpringBoot对于SpringMVC的支持

创建项目 版本说明这里使用的 SpringBoot 2.0.0.Release SpringBoot对于SpringMVC的支持 在之前的开发中很多场景下使用的是基于xml配置文件或者是Java配置类的方式来进行SpringMVC的配置。一般来讲&#xff0c;初始的步骤如下所示 1、初始化SpringMVC的DispatcherServlet2、…

[OpenAI]继ChatGPT后发布的Sora模型原理与体验通道

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言OpenAI体验通道Spacetime Latent Patches 潜变量时空碎片, 建构视觉语言系统…

kettle计算增长率

kettle计算增长率 问题描述处理方法 问题描述 读取一段时间内的数据记录&#xff0c;计算相邻记录的比率 iddatevalue12024-01-0110012024-01-0211012024-01-0312012024-01-0490 处理方法 1.使用统计中的分析查询节点能在每一行中添加前后行的数据 2.使用计算器节点计算比…

音视频基础概念笔记

RGB 色彩空间更适合图像采集和显示&#xff0c; YUV 空间用于编码和存储则比较好。 无论是 RGB 还是 YUV &#xff0c;他们都是 表达 色彩信息的一种方式。 &#xff08;Human Visual System&#xff09;人类视觉系统 色度感知 包含两个维度&#xff1a;色调&#xff08;Hue&…

ELK入门(四)-logstash

Logstash Logstash 是开源的服务器端数据处理管道&#xff0c;能够同时从多个来源采集数据&#xff0c;转换数据&#xff0c;然后将数据发送到您最喜欢的存储库中。 Logstash 能够动态地采集、转换和传输数据&#xff0c;不受格式或复杂度的影响。利用 Grok 从非结构化数据中…

WebService学习,wsdl文件详解

目录 第一章、起因1.1&#xff09;学习原因1.2&#xff09;提问的过程&#xff08;逐步提出问题&#xff09;1、&#xff1f;wsdl链接的含义&#xff0c;有什么作用&#xff1f;2、什么是wsdl文档&#xff1f;3、如何阅读wsdl文件&#xff1f;4、wsdl文件有什么作用&#xff1f…

Linux编译器---gcc/g++使用详解

目录 前言 gcc/g介绍 gcc/g的编译指令&#xff08;以gcc为例&#xff09; ​编辑 gcc选项 预处理(进行宏替换) 编译&#xff08;生成汇编&#xff09; 汇编&#xff08;生成机器可识别代码&#xff09; 链接&#xff08;生成可执行文件或库文件&#xff09; 函数库 概念 …

Vue单文件学习项目综合案例Demo,黑马vue教程

文章目录 前言一、小黑记事本二、购物车三、小黑记账清单 前言 bilibili视频地址 一、小黑记事本 效果图 主代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"/><meta http-equiv"X-UA-Compatible&…

C# CAD2016 cass10宗地Xdata数据写入

一、 查看cass10写入信息 C# Cad2016二次开发获取XData信息&#xff08;二&#xff09; 一共有81条数据 XData value: QHDM XData value: 121321 XData value: SOUTH XData value: 300000 XData value: 141121JC10720 XData value: 权利人 XData value: 0702 XData value: YB…

卫星地面站监测系统仿真

当今世界&#xff0c;大国竞争日趋激烈&#xff0c;国际关系愈发紧张&#xff0c;信息与通信已经是当下高度信息化社会的“命脉”&#xff0c;信息只有经过有效且广泛地传播&#xff0c;才能成为一种有利用价值的资源&#xff0c;产生经济效益、推动社会发展。通信技术在发展的…

【必备清单】开学运动好物清单,迎接新学期,打造健康体魄!

随着新学期的开始&#xff0c;校园里的氛围渐渐热络起来。作为一名学生&#xff0c;除了学习之外&#xff0c;参与体育运动也是非常重要的。不仅可以锻炼身体&#xff0c;提高身体素质&#xff0c;还能增加社交机会&#xff0c;丰富学校生活。然而&#xff0c;想要成为一名校园…