目的
Qt信号在多对象之间传递非常的不方便,绑定时必须持有对象,这存在很大的局限性。所以我就想能不能用信号ID来做唯一标识,将信号和槽进行解耦。
代码
头文件
#ifndef HGSSIGNALMANAGER_H
#define HGSSIGNALMANAGER_H
#include <QObject>
#include <iostream>
#include <QList>
#include <QMap>
#include <memory>
#include "h_basegui_global.h"
//自定义信号ID
enum HgsSignalID
{
SIGNALS_TEST_VOID = 0,
SIGNALS_TEST_QT = 1,
SIGNALS_TEST_CONSUMER = 2
};
//连接信息结构体
typedef struct HgsLinkInfo
{
HgsSignalID id; //信号ID
QObject* object; //Qt对象
const char* method; //信号或者槽函数
Qt::ConnectionType connectType = Qt::AutoConnection; //连接方式,信号不用关注
}HgsSignalInfo, HgsSlotInfo;
class H_BASEGUI_EXPORT HgsSignalManager : public QObject
{
Q_OBJECT
public:
/*
*申明成单例类方便调用
*/
static HgsSignalManager* getInstall();
/*
* 按信号ID注册信号
* @Parameter: HgsSignalID signalID 信号ID
* @Parameter: QObject * sender 发送者句柄
* @Parameter: const char * method 信号函数
* @Returns: void
*/
void registerSignal(HgsSignalID signalID, QObject* sender, const char* method);
/*
* 按信号ID绑定槽函数
* @Parameter: HgsSignalID signalID 信号ID
* @Parameter: QObject * sender 接收者句柄
* @Parameter: const char * method 槽函数
* @Parameter: Qt::ConnectionType connectType 连接类型
* @Returns: void
*/
void bindSlot(HgsSignalID signalID, QObject* recever, const char* method, Qt::ConnectionType connectType = Qt::AutoConnection);
/*
* 连接信号与槽,一般在main函数最后调用
* 将信号与槽函数全部绑定上
* @Returns: void
*/
void linkSignalSlot();
/*
* 解绑信号,先阶段还没实现
*/
//void unLinkSignalSlot(HgsSignalID signalId);
public:
private:
HgsSignalManager();
private:
typedef QList<HgsLinkInfo> LinkList;
typedef QMap<QObject*, LinkList> SignalLinkMap;
typedef QMap<QObject*, LinkList> SlotLinkMap;
QMap<HgsSignalID, SignalLinkMap> m_signalMap;
QMap<HgsSignalID, SlotLinkMap> m_slotMap;
private:
static HgsSignalManager* m_pInstall;
};
#endif // HGSSIGNALMANAGER_H
实现
#include "precompiler.h"
#include "HgsSignalManager.h"
#include <QDebug>
HgsSignalManager* HgsSignalManager::m_pInstall = nullptr;
HgsSignalManager* HgsSignalManager::getInstall()
{
if (nullptr == m_pInstall)
{
m_pInstall = new HgsSignalManager();
}
return m_pInstall;
}
void HgsSignalManager::registerSignal(HgsSignalID signalId, QObject* sender, const char* method)
{
auto iterSignal = m_signalMap.find(signalId);
if (iterSignal == m_signalMap.end())
{
//新增信号ID
HgsSignalInfo info;
info.id = signalId;
info.object = sender;
info.method = method;
LinkList list;
list.push_back(info);
SignalLinkMap linkMap;
linkMap[sender] = list;
m_signalMap[signalId] = linkMap;
}
else
{
HgsSignalInfo info;
info.id = signalId;
info.object = sender;
info.method = method;
SignalLinkMap linkMap = m_signalMap[signalId];
auto iterLink = linkMap.find(sender);
if (iterLink == linkMap.end())
{
LinkList list;
list.push_back(info);
linkMap[sender] = list;
m_signalMap[signalId] = linkMap;
}
else
{
LinkList list = linkMap[sender];
list.push_back(info);
linkMap[sender] = list;
m_signalMap[signalId] = linkMap;
}
}
}
void HgsSignalManager::bindSlot(HgsSignalID signalId, QObject* recever, const char* method, Qt::ConnectionType connectType)
{
auto iterSignal = m_slotMap.find(signalId);
if (iterSignal == m_slotMap.end())
{
//新增信号ID
HgsSlotInfo info;
info.id = signalId;
info.object = recever;
info.method = method;
info.connectType = connectType;
LinkList list;
list.push_back(info);
SignalLinkMap linkMap;
linkMap[recever] = list;
m_slotMap[signalId] = linkMap;
}
else
{
HgsSignalInfo info;
info.id = signalId;
info.object = recever;
info.method = method;
info.connectType = connectType;
SignalLinkMap linkMap = m_slotMap[signalId];
auto iterLink = linkMap.find(recever);
if (iterLink == linkMap.end())
{
LinkList list;
list.push_back(info);
linkMap[recever] = list;
m_slotMap[signalId] = linkMap;
}
else
{
LinkList list = linkMap[recever];
list.push_back(info);
linkMap[recever] = list;
m_slotMap[signalId] = linkMap;
}
}
}
void HgsSignalManager::linkSignalSlot()
{
auto iter = m_signalMap.begin();
for (iter; iter != m_signalMap.end(); ++iter)
{
HgsSignalID signalId = iter.key();
auto slotLinkMapIter = m_slotMap.find(signalId);
if (slotLinkMapIter == m_slotMap.end())
{
continue;
}
auto signalLinkMap = iter.value();
auto slotLinkMap = slotLinkMapIter.value();
auto iterSignalLink = signalLinkMap.begin();
for (iterSignalLink; iterSignalLink != signalLinkMap.end(); ++iterSignalLink)
{
auto iterSlotLink = slotLinkMap.begin();
for (iterSlotLink; iterSlotLink != slotLinkMap.end(); ++iterSlotLink)
{
auto signalLinkList = iterSignalLink.value();
auto slotLinkList = iterSlotLink.value();
for (int i = 0; i < signalLinkList.count(); ++i)
{
for (int j= 0; j < slotLinkList.count(); ++ j)
{
auto signalLinkInfo = signalLinkList.value(i);
auto slotLinkInfo = slotLinkList.value(j);
connect(signalLinkInfo.object, signalLinkInfo.method, slotLinkInfo.object, slotLinkInfo.method, slotLinkInfo.connectType);
}
}
}
}
}
}
// void HgsSignalManager::unLinkSignalSlot(HgsSignalID signalId)
// {
// auto iterSignalLinkMap = m_signalMap.find(signalId);
// if (iterSignalLinkMap == m_signalMap.end())
// {
// return;
// }
//
// auto iterSlotLinkMap = m_slotMap.find(signalId);
// if (iterSlotLinkMap == m_slotMap.end())
// {
// return;
// }
//
// auto signalLinkMap = iterSignalLinkMap.value();
// auto slotLinkMap = iterSlotLinkMap.value();
//
// auto iterSignalLink = signalLinkMap.begin();
// for (iterSignalLink; iterSignalLink != signalLinkMap.end(); ++iterSignalLink)
// {
// auto iterSlotLink = slotLinkMap.begin();
// for (iterSlotLink; iterSlotLink != slotLinkMap.end(); ++iterSlotLink)
// {
// auto signalLinkList = iterSignalLink.value();
// auto slotLinkList = iterSlotLink.value();
//
// for (int i = 0; i < signalLinkList.count(); ++i)
// {
// for (int j = 0; j < slotLinkList.count(); ++j)
// {
// auto signalLinkInfo = signalLinkList.value(i);
// auto slotLinkInfo = slotLinkList.value(j);
// disconnect(signalLinkInfo.object, signalLinkInfo.method, slotLinkInfo.object, slotLinkInfo.method);
// }
// }
// }
// }
// }
HgsSignalManager::HgsSignalManager()
{
}
特别注意
HgsSignalManager::linkSignalSlot()
1.该函数在当前版本只能调用一次,调用多次存在重复连接问题
2.该函数一般在所有信号注册完毕,所有曹函数绑定完毕后调用。所以我一般在main函数的末尾调用
后续计划
1.细化连接信息的存储,内部自动检测当前信号是否已连接,避免重复连接
2.添加取消绑定函数
- 按信号ID解绑
- 按信号发送者解绑
- 按信号接收者解绑
- …
结尾
谢谢,如有错误请指正