QSingnalMapper-信号翻译和转发器

简介

QSingalMapper类可以看成是信号的翻译和转发器。它可以把一个无参的信号 翻译成带参数(intQStringQObjectQWidget) 的信号类型,然后再转发出去。

使用场景

一个使用场景是多个按钮点击时所要实现的业务是雷同的,此时我们会将其绑定在同一个槽函数中,
虽然我们可以在槽函数中利用sender()函数来获取发送信号的按钮,但为了区分信号具体来源必然会做额外的操作,而QSignalMapper类用于简化信号与槽机制的处理。它可以将一个信号连接到多个槽,同时为每个槽提供一个标识符,以便在槽函数中区分不同的信号来源。

API

设置信号发射者的映射关系和映射的数据,对应的发射信号也有四个

functions:
	void setMapping(QObject *sender, int id)
	void setMapping(QObject *sender, const QString &text)
	void setMapping(QObject *sender, QWidget *widget)
	void setMapping(QObject *sender, QObject *object)

signals:
	void mapped(int i)
	void mapped(const QString &text)
	void mapped(QWidget *widget)
	void mapped(QObject *object)

通过转发参数获取发射信号的原始对象

QObject *mapping(int id) const
QObject *mapping(const QString &id) const
QObject *mapping(QWidget *widget) const
QObject *mapping(QObject *object) const

删除指定的对象的映射关系

void removeMappings(QObject *sender)

接收信号

void map()
void map(QObject *sender)

流程解析

前提: 在页面上拖动三个按钮,分别为btn1、btn2、btn3
在这里插入图片描述

简述是总结,详述是按照代码一步一步进行更为细致的说明。

简述

  1. 首先把原始不带参数的clicked信号连接到signalMapper的map()槽函数,这样signalMapper能在第一时间接收到原始信号;
  2. signalMapper接收到clicked信号以后,通过用户自定义的信号映射规则,将其转换成用户所需要的信号
  3. 最后只需要绑定转换后的带参数的信号,定义对应的槽函数进行处理即可。

详述

我们以下面的代码为例,讲述QSignalMapper的用法,这里省略了代码结构,只保留了关键部分,后面会给出整个代码。

1. 初始化一个QSignalMapper对象

    QSignalMapper *signalMapper= new QSignalMapper(this);

2. 为三个button创建信号映射规则

  • QSignalMapper类的功能核心是要建立一个从原始信号的object到需要的数据的映射。我们通过调用setMapping函数建立这个映射关系。
  • 就像定义路由器的转发规则一样,btn1的clicked信号发过来了,那就从这个带int参数的口发出去一个信号;btn2的clicked信号发过来了,那就从这个带QString参数的口发出去一个信号;参数由自己传进去。
    // btn1传递了一个int
    signalMapper->setMapping(ui->btn1, 10);
    // btn2和btn3分别传递的是自己的文本
    signalMapper->setMapping(ui->btn2, ui->btn2->text()); 
    signalMapper->setMapping(ui->btn3, ui->btn3->text());

4. 将对象的信号连接到QSignalMapper对象的map()槽函数上
就像是在原始信号clicked和signalMapper之间架起了一座桥梁,使signalMapper能在第一时间接收到按钮发出的clicked信号;(对应图示③)

	connect(ui->btn1, SIGNAL(clicked()), signalMapper, SLOT(map()));
    connect(ui->btn2, SIGNAL(clicked()), signalMapper, SLOT(map()));
    connect(ui->btn3, SIGNAL(clicked()), signalMapper, SLOT(map()));

5. 自定义的槽函数连接到mapped(xx参数)信号,接收我们定义规则中的信号

  • signalMapper通过上一步的map得知了发出clicked信号的按钮,然后一查规则表(图示②)得知btn1这小子要映射到int类型参数的信号。所以这里的mapped信号即为映射后的带自定义参数的信号,我们绑定此信号进行处理即可。
	// btn1的
    connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(btnClicked(int)));
    // btn2和btn3的
    connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(btnClicked(QString)));

槽函数的实现

void Form::btnClicked(int idid)
{
    qDebug() << __FILE__ << __LINE__ << "btn1点击了,接收到的int值为:" << idid;
}
void Form::btnClicked(QString name)
{
    qDebug() << __FILE__ << __LINE__  << name << "点击了";
}

代码示例

代码中加入了btn4,主要是为了测试传入QObject的对象。

form.h

#ifndef FORM_H
#define FORM_H

#include <QWidget>
#include <QSignalMapper>
#include <QDebug>
namespace Ui {
class Form;
}

class Form : public QWidget
{
    Q_OBJECT
public:
    explicit Form(QWidget *parent = nullptr);
    ~Form();
    
public slots:
    void btnClicked(int id); 		// btn1的测试槽函数
    void btnClicked(QString name);  // btn2/3的测试槽函数
    void showStuInfo(QObject *obj); // btn4的测试槽函数
    
private:
    Ui::Form *ui;
    QSignalMapper *signalMapper;   // QSignalMapper 对象
};

// 用于测试的对象
class Student : public QObject 
{
public:
    Q_OBJECT

public:
    QString m_name;
    int m_age;

    void printStuInfo() 
    {
        qDebug() << __FILE__ << __LINE__  << m_name << ":" << m_age;
    }
};
#endif // FORM_H

form.cpp

#include "form.h"
#include "ui_form.h"

Form::Form(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Form)
{
    ui->setupUi(this);
    // 1. 初始化SingalMapper对象
    signalMapper = new QSignalMapper(this);
    // 2. 为三个button设置信号映射规则
    signalMapper->setMapping(ui->btn1, 10);
    signalMapper->setMapping(ui->btn2, ui->btn2->text());
    signalMapper->setMapping(ui->btn3, ui->btn3->text());

    Student *stu = new Student; // 注意这里对象一定是指针类型,不能是局部变量传地址
    stu->m_name = "张三";
    stu->m_age = 12;
    signalMapper->setMapping(ui->btn4, stu);
    
    // 将对象的信号连接到QSignalMapper对象的map()槽函数上
    connect(ui->btn1, SIGNAL(clicked()), signalMapper, SLOT(map()));
    connect(ui->btn2, SIGNAL(clicked()), signalMapper, SLOT(map()));
    connect(ui->btn3, SIGNAL(clicked()), signalMapper, SLOT(map()));
    connect(ui->btn4, &QPushButton::clicked, signalMapper, QOverload<>::of(&QSignalMapper::map));
    
    //自定义的槽函数连接到mapped(xx)信号,接收我们定义规则中的信号
    connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(btnClicked(int)));
    connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(btnClicked(QString)));
    connect(signalMapper, QOverload<QObject*>::of(&QSignalMapper::mapped), this, QOverload<QObject*>::of(&Form::showStuInfo));
}



void Form::btnClicked(int idid)
{
    qDebug() << "btn1点击了" <<idid;
    // 通过参数获取规则的对象
    qobject_cast<QPushButton*>(signalMapper->mapping(idid))->text();
}
void Form::btnClicked(QString name)
{
    qDebug() << name;
}

void Form::showStuInfo(QObject *obj)
{
    auto *stu = qobject_cast<Student*>(obj);
    if(stu) {
        stu->printStuInfo();
    }
}


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

注意事项

  • singalMapper处理的是无参数的信号
  • setMapping函数的参数只有四种,并且要严格按照格式写入,第一种const QString&,第二种int,第三种QObject*,第四种QWidget *,对于后两种,需要的是他们的子类,则在信号处理的函数里进行类型转化.

参考

[1]. https://blog.csdn.net/lion_cxq/article/details/130276969
[2]. https://www.cnblogs.com/tudou/p/11586454.html

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值