Qt使用信号槽模拟全局广播

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工程下载

你可能感兴趣的:(Qt,c++模板编程应用,Qt,信号槽)