Qt的信号槽很好用,可以轻松的对代码解耦,现在我不想在类里面声明信号槽,也不想写Q_OBJECT,因此有了以下的方式模拟一个全局广播,通过一个全局的实例(单例)发送接收数据
//CGlobalBroadcast.h
#pragma once
#include
#include
#include
//添加消息Id
namespace BroadcastEvent {
enum Event_Void {
CUSTOM_EVENT_VOID = 0,
};
enum Event_Variant {
CUSTOM_EVENT_VARIANT = 0,
};
enum Event_Variant_List {
CUSTOM_EVENT_VARIANT_LIST = 0,
};
};
class CGlobalBroadcast : public QObject {
Q_OBJECT
private:
CGlobalBroadcast(QObject* parent);
public:
static void Install(QObject* parent);
//connect direct
template<typename F>
static void RegisterEvent(BroadcastEvent::Event_Void id, F f);
template<typename F>
static void RegisterEvent(BroadcastEvent::Event_Variant id, F f);
template<typename F>
static void RegisterEvent(BroadcastEvent::Event_Variant_List id, F f);
//connect auto
template<typename F>
static void RegisterEvent(BroadcastEvent::Event_Void id, const QObject* context, F f);
template<typename F>
static void RegisterEvent(BroadcastEvent::Event_Variant id, const QObject* context, F f);
template<typename F>
static void RegisterEvent(BroadcastEvent::Event_Variant_List id, const QObject* context, F f);
static void PostEvent(BroadcastEvent::Event_Void id);
static void PostEvent(BroadcastEvent::Event_Variant id, QVariant data);
static void PostEvent(BroadcastEvent::Event_Variant_List id, QVariantList data);
private:
typedef void (CGlobalBroadcast::*func_void)();
typedef void (CGlobalBroadcast::*func_variant)(QVariant);
typedef void (CGlobalBroadcast::*func_variant_list)(QVariantList);
private:
static CGlobalBroadcast* globalBroadcast;
//function map
QHash<BroadcastEvent::Event_Void, func_void> funcMap_void;
QHash<BroadcastEvent::Event_Variant, func_variant> funcMap_variant;
QHash<BroadcastEvent::Event_Variant_List, func_variant_list> funcMap_variant_list;
//注册信号
private:
inline void installFuncVoid() {
funcMap_void.insert(BroadcastEvent::CUSTOM_EVENT_VOID, &CGlobalBroadcast::custom_event_void);
}
inline void installFuncVariant() {
funcMap_variant.insert(BroadcastEvent::CUSTOM_EVENT_VARIANT, &CGlobalBroadcast::custom_event_variant);
}
inline void installFuncVariantList() {
funcMap_variant_list.insert(BroadcastEvent::CUSTOM_EVENT_VARIANT_LIST, &CGlobalBroadcast::custom_event_variant_list);
}
#define F_VOID(f_n) void f_n()
#define F_VARIANT(f_n) void f_n(QVariant data)
#define F_VARIANT_LIST(f_n) void f_n(QVariantList data)
//定义消息信号
signals:
//function void
F_VOID(custom_event_void);
//function variant
F_VARIANT(custom_event_variant);
//function variant list
F_VARIANT_LIST(custom_event_variant_list);
};
template<typename F>
inline void CGlobalBroadcast::RegisterEvent(BroadcastEvent::Event_Void id, F f) {
connect(globalBroadcast, globalBroadcast->funcMap_void.value(id), f);
}
template<typename F>
inline void CGlobalBroadcast::RegisterEvent(BroadcastEvent::Event_Variant id, F f) {
connect(globalBroadcast, globalBroadcast->funcMap_variant.value(id), f);
}
template<typename F>
inline void CGlobalBroadcast::RegisterEvent(BroadcastEvent::Event_Variant_List id, F f) {
connect(globalBroadcast, globalBroadcast->funcMap_variant_list.value(id), f);
}
template<typename F>
inline void CGlobalBroadcast::RegisterEvent(BroadcastEvent::Event_Void id, const QObject * context, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_void.value(id), context, f);
}
template<typename F>
inline void CGlobalBroadcast::RegisterEvent(BroadcastEvent::Event_Variant id, const QObject * context, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_variant.value(id), context, f);
}
template<typename F>
inline void CGlobalBroadcast::RegisterEvent(BroadcastEvent::Event_Variant_List id, const QObject * context, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_variant_list.value(id), context, f);
}
//CGlobalBroadcast.cpp
#include "CGlobalBroadcast.h"
CGlobalBroadcast* CGlobalBroadcast::globalBroadcast = nullptr;
CGlobalBroadcast::CGlobalBroadcast(QObject* parent)
: QObject(parent)
{
installFuncVoid();
installFuncVariant();
installFuncVariantList();
}
void CGlobalBroadcast::Install(QObject * parent) {
if (globalBroadcast == nullptr) {
globalBroadcast = new CGlobalBroadcast(parent);
}
}
void CGlobalBroadcast::PostEvent(BroadcastEvent::Event_Void id) {
emit (globalBroadcast->*(globalBroadcast->funcMap_void.value(id)))();
}
void CGlobalBroadcast::PostEvent(BroadcastEvent::Event_Variant id, QVariant data) {
emit (globalBroadcast->*(globalBroadcast->funcMap_variant.value(id)))(data);
}
void CGlobalBroadcast::PostEvent(BroadcastEvent::Event_Variant_List id, QVariantList data) {
emit (globalBroadcast->*(globalBroadcast->funcMap_variant_list.value(id)))(data);
}
注册全局广播实例
CGlobalBroadcast::Install(parent);
在A类中发送广播
struct StructA {
int a;
QString b;
};
Q_DECLARE_METATYPE(StructA);
void A::sendEvent(){
//没有参数的通知
CGlobalBroadcast::PostEvent(BroadcastEvent::CUSTOM_EVENT_VOID);
//发送1个QString
CGlobalBroadcast::PostEvent(BroadcastEvent::CUSTOM_EVENT_VARIANT, "hello B!");
//发送1个StructA
StructA structA;
CGlobalBroadcast::PostEvent(BroadcastEvent::CUSTOM_EVENT_VARIANT, QVariant::fromValue(structA));
//发送一堆数据
QVariantList data;
data << 1;
data << "abc";
CGlobalBroadcast::PostEvent(BroadcastEvent::CUSTOM_EVENT_VARIANT_LIST, data);
}
在B类中接收广播
void B::receiverEvent(){
//接收没有参数的通知
CGlobalBroadcast::RegisterEvent(BroadcastEvent::CUSTOM_EVENT_VOID, [&]() {
//do something...
});
//接收A发送的QString
CGlobalBroadcast::RegisterEvent(BroadcastEvent::CUSTOM_EVENT_VARIANT, [&](QVariant data) {
auto str = data.toString();
//do something...
});
//接收A发送的结构体
CGlobalBroadcast::RegisterEvent(BroadcastEvent::CUSTOM_EVENT_VARIANT, [&](QVariant data) {
auto structA = data.value<StructA>();
//do something...
});
//接收A发送的一堆数据
CGlobalBroadcast::RegisterEvent(BroadcastEvent::CUSTOM_EVENT_VARIANT_LIST, [&](QVariantList data) {
auto dataInt = data.at(0).toInt();
auto dataStr = data.at(1).toString();
//do something...
});
}
用起来很爽,发送和接收都不用connect了,甚至不用继承QObject,A类和B类相隔十万八千里,只要都包含CGlobalBroadcast.h就可以传递数据,不同的消息可以通过消息ID区分,而且B看心情接收不接收消息,B和另一个C也可以接收相同的消息,但是…由于添加消息写在头文件里,每添加1个消息ID后,所有用到CGlobalBroadcast的cpp得全部重新编译一次。
主要解决上述1个问题:由于消息的传递是通过1个实例进行的,在同一个线程下的接收函数发送频率太高会发生阻塞。由此将CGlobalBroadcast做成模板基类,可以实现多个消息发送类,让定义消息分开
定义模板基类CGlobalBroadcastImpl.h
#pragma once
#include
#include
#include
template<typename T, typename B>
class CGlobalBroadcastImpl : public QObject {
public:
CGlobalBroadcastImpl<T, B>(QObject* parent) : QObject(parent) {}
public:
static void Install(QObject* parent) {
if (globalBroadcast == nullptr) {
globalBroadcast = new T(parent);
}
}
template<typename F>
static void RegisterEvent(typename B::Event_Void id, F f);
template<typename F>
static void RegisterEvent(typename B::Event_Variant id, F f);
template<typename F>
static void RegisterEvent(typename B::Event_Variant_List id, F f);
//connect auto
template<typename F>
static void RegisterEvent(typename B::Event_Void id, const QObject* context, F f);
template<typename F>
static void RegisterEvent(typename B::Event_Variant id, const QObject* context, F f);
template<typename F>
static void RegisterEvent(typename B::Event_Variant_List id, const QObject* context, F f);
static void PostEvent(typename B::Event_Void id) {
emit (globalBroadcast->*(globalBroadcast->funcMap_void.value(id)))();
}
static void PostEvent(typename B::Event_Variant id, QVariant data) {
emit (globalBroadcast->*(globalBroadcast->funcMap_variant.value(id)))(data);
}
static void PostEvent(typename B::Event_Variant_List id, QVariantList data) {
emit (globalBroadcast->*(globalBroadcast->funcMap_variant_list.value(id)))(data);
}
private:
typedef void (T::*func_void)();
typedef void (T::*func_variant)(QVariant);
typedef void (T::*func_variant_list)(QVariantList);
protected:
static T* globalBroadcast;
//function map
QHash<typename B::Event_Void, func_void> funcMap_void;
QHash<typename B::Event_Variant, func_variant> funcMap_variant;
QHash<typename B::Event_Variant_List, func_variant_list> funcMap_variant_list;
//注册信号
private:
virtual void installFuncVoid() = 0;
virtual void installFuncVariant() = 0;
virtual void installFuncVariantList() = 0;
#define F_VOID(f_n) void f_n()
#define F_VARIANT(f_n) void f_n(QVariant data)
#define F_VARIANT_LIST(f_n) void f_n(QVariantList data)
};
template<typename T, typename B>
template<typename F>
inline void CGlobalBroadcastImpl<T, B>::RegisterEvent(typename B::Event_Void id, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_void.value(id), f);
}
template<typename T, typename B>
template<typename F>
inline void CGlobalBroadcastImpl<T, B>::RegisterEvent(typename B::Event_Variant id, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_variant.value(id), f);
}
template<typename T, typename B>
template<typename F>
inline void CGlobalBroadcastImpl<T, B>::RegisterEvent(typename B::Event_Variant_List id, F f) {
connect(globalBroadcast, globalBroadcast->funcMap_variant_list.value(id), f);
}
template<typename T, typename B>
template<typename F>
inline void CGlobalBroadcastImpl<T, B>::RegisterEvent(typename B::Event_Void id, const QObject * context, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_void.value(id), context, f);
}
template<typename T, typename B>
template<typename F>
inline void CGlobalBroadcastImpl<T, B>::RegisterEvent(typename B::Event_Variant id, const QObject * context, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_variant.value(id), context, f);
}
template<typename T, typename B>
template<typename F>
inline void CGlobalBroadcastImpl<T, B>::RegisterEvent(typename B::Event_Variant_List id, const QObject * context, F f)
{
connect(globalBroadcast, globalBroadcast->funcMap_variant_list.value(id), context, f);
}
重新定义CGlobalBroadcast,使用方法跟原来一样
//CGlobalBroadcast.h
#pragma once
#include "CGlobalBroadcastImpl.h"
//添加消息Id
struct BroadcastEvent {
enum Event_Void {
CUSTOM_EVENT_VOID = 0,
};
enum Event_Variant {
CUSTOM_EVENT_VARIANT = 0,
};
enum Event_Variant_List {
CUSTOM_EVENT_VARIANT_LIST = 0,
};
};
class CGlobalBroadcast : public CGlobalBroadcastImpl<CGlobalBroadcast, BroadcastEvent> {
Q_OBJECT
public:
CGlobalBroadcast(QObject* parent) : CGlobalBroadcastImpl(parent) {
installFuncVoid();
installFuncVariant();
installFuncVariantList();
}
private:
void installFuncVoid() override;
void installFuncVariant() override;
void installFuncVariantList() override;
//定义消息信号
signals:
//function void
F_VOID(custom_event_void);
//function variant
F_VARIANT(custom_event_variant);
//function variant list
F_VARIANT_LIST(custom_event_variant_list);
};
//CGlobalBroadcast.cpp
#include "CGlobalBroadcast.h"
CGlobalBroadcast* CGlobalBroadcast::globalBroadcast = nullptr;
void CGlobalBroadcast::installFuncVoid() {
funcMap_void.insert(BroadcastEvent::CUSTOM_EVENT_VOID, &CGlobalBroadcast::custom_event_void);
}
void CGlobalBroadcast::installFuncVariant() {
funcMap_variant.insert(BroadcastEvent::CUSTOM_EVENT_VARIANT, &CGlobalBroadcast::custom_event_variant);
}
void CGlobalBroadcast::installFuncVariantList() {
funcMap_variant_list.insert(BroadcastEvent::CUSTOM_EVENT_VARIANT_LIST, &CGlobalBroadcast::custom_event_variant_list);
}
demo工程下载