QSignalMapper类可以看成是信号的翻译和转发器。
它可以把一个无参的信号翻译成带以下4种参数的信号再转发:int、QString、 QObject以及QWidget 。
应用场景一般是:有一些信号,发送的参数都是一样的情况下,常用的方法是给每一个信号都连接一个槽函数。但这样做,会让代码多一些不必要的复杂,这种情况下,你就可以使用QSignalMapper
下面是 3 个按钮连接 到 对应的 映射数据
setMapping 设置 发射对象 接受的数据
意思:m_signalMapper 作为一个中转站 点击按钮 给到 m_signalMapper,用map来翻译 这个 数据,然后m_signalMapper 发射mapped信号 将刚才翻译的数据发送给 this,这个this 就是我们最终的 接受者
目的:这时候我们就将3个按钮的点击信号 都交给 m_signalMapper 去处理,它发射一个信号mapped 就 节省了 3个按钮 都需要写connect 非必要操作,因为他们的 目的 都是 去 触发showName 这个槽函数,现在我们只需要一个 conenct 就可以解决
m_signalMapper = new QSignalMapper(this);
m_signalMapper->setMapping(ui.btn1, "Button 1 clicked");
m_signalMapper->setMapping(ui.btn2, "Button 2 clicked");
m_signalMapper->setMapping(ui.btn3, "Button 3 clicked");
connect(ui.btn1, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(ui.btn2, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(ui.btn3, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(m_signalMapper, SIGNAL(mapped(const QString&)), this, SLOT(showName(const QString&)));
connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(showStrName(QString)));
结果:
来看一下如果参数为 QObejct是怎么回事
这里有一个StudentInfo 类型 是继承于QObject的,然后分别设置了它的参数,此时我们就知道,点击按钮,然后将 这个学生的信息 交给我们的 m_signalMapper,然后它 在转发给我们的 showStudentInfo 函数,这里函数展示了我们学生的信息情况,也同样不需要写 3个 connect 来操作
m_s1.SetName("lion");
m_s1.SetAge(20);
StudentInfo* s2 = new StudentInfo("cxq", 18);
StudentInfo* s3 = new StudentInfo("lion_cxq", 22);
m_signalMapper->setMapping(ui.btn1, &m_s1);
m_signalMapper->setMapping(ui.btn2, s2);
m_signalMapper->setMapping(ui.btn3, s3);
connect(ui.btn1, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(ui.btn2, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(ui.btn3, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(m_signalMapper, QOverload<QObject*>::of(&QSignalMapper::mapped), this, &QSignalMapperTest::showStudentInfo);
关键的一点是:
我们可以在槽函数中 将QObject 转化为我们 自定义的指针
void QSignalMapperTest::showStudentInfo(QObject* object)
{
StudentInfo* s = qobject_cast<StudentInfo*>(object);
if (s)
{
qDebug() << s->GetAge() << s->GetName();
}
}
还有一个就是我们遇到同名的 槽函数时,我们必须要同时两边重载,使用一个即可,否则会报错
//第一个
connect(m_signalMapper, QOverload<const QString&>::of(&QSignalMapper::mapped), this, QOverload<const QString&>::of(&QSignalMapperTest::showName));
//第二个
connect(m_signalMapper, static_cast<void (QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped), this, static_cast<void (QSignalMapperTest::*)(const QString&)>
(&QSignalMapperTest::showName));
结果:
完整代码:
ui图
.h
#pragma once
#include <QtWidgets/QWidget>
#include "ui_QSignalMapperTest.h"
#include <QSignalMapper>
#include <QDebug>
#include <QVariant>
#define QT5
typedef struct Student
{
QString name;
int age;
}Student;
Q_DECLARE_METATYPE(Student)
class StudentInfo :public QObject
{
Q_OBJECT
public:
StudentInfo(QObject* parent = nullptr);
StudentInfo(QString name, int age, QObject* parent = nullptr);
void SetName(const QString&);
QString GetName() const;
void SetAge(const int&);
int GetAge() const;
private:
QString m_name;
int m_age;
};
class QSignalMapperTest : public QWidget
{
Q_OBJECT
public:
QSignalMapperTest(QWidget *parent = Q_NULLPTR);
public Q_SLOTS:
void showName(const QString&);
void showName(QString, int);
void showStrName(QString);
void showStudentInfo(QObject* object);
private:
Ui::QSignalMapperTestClass ui;
StudentInfo m_s1;
QSignalMapper* m_signalMapper;
};
.cpp
#include "QSignalMapperTest.h"
QSignalMapperTest::QSignalMapperTest(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
m_signalMapper = new QSignalMapper(this);
#if 1
#ifdef QT5
m_s1.SetName("lion");
m_s1.SetAge(20);
StudentInfo* s2 = new StudentInfo("cxq", 18);
StudentInfo* s3 = new StudentInfo("lion_cxq", 22);
m_signalMapper->setMapping(ui.btn1, &m_s1);
m_signalMapper->setMapping(ui.btn2, s2);
m_signalMapper->setMapping(ui.btn3, s3);
connect(ui.btn1, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(ui.btn2, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(ui.btn3, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(m_signalMapper, QOverload<QObject*>::of(&QSignalMapper::mapped), this, &QSignalMapperTest::showStudentInfo);
#else
StudentInfo* s = new StudentInfo("cxq", 18);
m_signalMapper->setMapping(ui.btn1, s);
m_signalMapper->setMapping(ui.btn2, s);
m_signalMapper->setMapping(ui.btn3, s);
connect(ui.btn1, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(ui.btn2, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(ui.btn3, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(m_signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(showStudentInfo(QObject*)));
#endif
#endif
#if 0
#ifdef QT5
m_signalMapper->setMapping(ui.btn1, "Button 1 clicked");
m_signalMapper->setMapping(ui.btn2, "Button 2 clicked");
m_signalMapper->setMapping(ui.btn3, "Button 3 clicked");
connect(ui.btn1, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(ui.btn2, &QPushButton::clicked, m_signalMapper, QOverload<>::of(&QSignalMapper::map));
connect(ui.btn3, &QPushButton::clicked, m_signalMapper, static_cast<void(QSignalMapper::*)()>(&QSignalMapper::map));
//使用这个报错 必须使用下面第一种或者第二种 因为 槽函数也是重载的
//connect(m_signalMapper, QOverload<const QString&>::of(&QSignalMapper::mapped), this, &QSignalMapperTest::showName);
//第一个
//connect(m_signalMapper, QOverload<const QString&>::of(&QSignalMapper::mapped), this, QOverload<const QString&>::of(&QSignalMapperTest::showName));
//第二个
connect(m_signalMapper, static_cast<void (QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped), this, static_cast<void (QSignalMapperTest::*)(const QString&)>(&QSignalMapperTest::showName));
#else
m_signalMapper->setMapping(ui.btn1, "Button 1 clicked");
m_signalMapper->setMapping(ui.btn2, "Button 2 clicked");
m_signalMapper->setMapping(ui.btn3, "Button 3 clicked");
connect(ui.btn1, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(ui.btn2, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
connect(ui.btn3, SIGNAL(clicked()), m_signalMapper, SLOT(map()));
//可以
connect(m_signalMapper, SIGNAL(mapped(const QString&)), this, SLOT(showName(const QString&)));
connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(showStrName(QString)));
//不可以 多个参数不可以
//connect(m_signalMapper, SIGNAL(mapped(QString,int)), this, SLOT(showName(QString,int)));
#endif
#endif
}
void QSignalMapperTest::showName(const QString& str)
{
qDebug() << str;
}
void QSignalMapperTest::showName(QString name, int age)
{
qDebug() << QStringLiteral("姓名:");
}
void QSignalMapperTest::showStrName(QString str)
{
qDebug() << str;
}
void QSignalMapperTest::showStudentInfo(QObject* object)
{
StudentInfo* s = qobject_cast<StudentInfo*>(object);
if (s)
{
qDebug() << s->GetAge() << s->GetName();
}
}
StudentInfo::StudentInfo(QObject* parent)
{
}
StudentInfo::StudentInfo(QString name, int age, QObject* parent )
{
m_name = name;
m_age = age;
}
void StudentInfo::SetName(const QString& name )
{
m_name = name;
}
QString StudentInfo::GetName() const
{
return m_name;
}
void StudentInfo::SetAge(const int& age)
{
m_age = age;
}
int StudentInfo::GetAge() const
{
return m_age;
}
参考博客:
QSignalMapper介绍
QSignalMapper使用