简介
QSingalMapper类可以看成是信号的翻译和转发器。它可以把一个无参的信号
翻译成带参数(int、QString、QObject、QWidget) 的信号类型,然后再转发出去。
使用场景
一个使用场景是多个按钮点击时所要实现的业务是雷同的,此时我们会将其绑定在同一个槽函数中,
虽然我们可以在槽函数中利用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
简述是总结,详述是按照代码一步一步进行更为细致的说明。
简述
- 首先把原始不带参数的clicked信号连接到signalMapper的map()槽函数,这样signalMapper能在第一时间接收到原始信号;
- signalMapper接收到clicked信号以后,通过用户自定义的信号映射规则,将其转换成用户所需要的信号
- 最后只需要绑定转换后的带参数的信号,定义对应的槽函数进行处理即可。
详述
我们以下面的代码为例,讲述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