Qt实现简单事件总线
Qt实现简单事件总线
事件总线(Event Bus)是一种解耦组件通信的设计模式,它允许不同对象之间通过事件进行通信而无需直接引用对方。
事件通常是自定义类型,需要在main.cpp中注册自定义元类型
//注册自定义元类型
qRegisterMetaType<KeyPressedEvent>("KeyPressedEvent");
1 事件总线头文件 (EventBusService.h)
#ifndef EVENTBUSSERVICE_H
#define EVENTBUSSERVICE_H
#include <functional>
#include <type_traits>
#include <QObject>
#include <QMap>
#include <QList>
#include <QMutex>
#include <QDebug>
#include <QSharedPointer>
#include <QThread>
class EventBusService : public QObject
{
Q_OBJECT
public:
explicit EventBusService();
~EventBusService();
//订阅事件
template <typename EventType>
void subscribe(QObject* subscriber, void (QObject::*handler)(const EventType&))
{
if (!subscriber || !handler)
{
return;
}
QMutexLocker locker(&m_mutex);
QByteArray eventType = typeid(EventType).name();
//创建处理函数包装器
std::function<void(const EventType&)> func = [subscriber, handler](const EventType& event)
{
(subscriber->*handler)(event);
};
//创建事件处理器
HandlerBase* handlerBase = new Handler<EventType>(subscriber, eventType, func);
//添加到事件映射
m_subscriptionsByEvent[eventType].append(handlerBase);
//添加到订阅者映射
m_subscriptionsBySubscriber[subscriber].append(handlerBase);
//连接销毁信号
connect(subscriber, &QObject::destroyed, this, &EventBusService::onSubscriberDestroyed);
}
//取消订阅
template <typename EventType>
void unsubscribe(QObject* subscriber)
{
QMutexLocker locker(&m_mutex);
QByteArray eventType = typeid(EventType).name();
if (!m_subscriptionsBySubscriber.contains(subscriber))
{
return;
}
auto& handlers = m_subscriptionsBySubscriber[subscriber];
QList<HandlerBase*> toRemove;
//查找匹配的事件处理器
for (HandlerBase* handler : handlers)
{
if (handler->eventType == eventType)
{
toRemove.append(handler);
}
}
//移除事件处理器
for (HandlerBase* handler : toRemove)
{
handlers.removeAll(handler);
m_subscriptionsByEvent[eventType].removeAll(handler);
delete handler;
}
//如果订阅者没有其他订阅,则完全移除
if (handlers.isEmpty())
{
m_subscriptionsBySubscriber.remove(subscriber);
disconnect(subscriber, &QObject::destroyed, this, &EventBusService::onSubscriberDestroyed);
}
}
//发布事件
template <typename EventType>
void publish(const EventType& event)
{
QMutexLocker locker(&m_mutex);
QByteArray eventType = typeid(EventType).name();
if (!m_subscriptionsByEvent.contains(eventType))
{
return;
}
//使用共享指针确保事件在跨线程传递时的安全性
auto eventPtr = QSharedPointer<EventType>::create(event);
auto handlers = m_subscriptionsByEvent[eventType]; //复制一份避免迭代时修改
locker.unlock(); //提前释放锁,避免处理事件时死锁
for (HandlerBase* base : handlers)
{
Handler<EventType>* handler = dynamic_cast<Handler<EventType>*>(base);
if (handler)
{
QObject* subscriber = handler->subscriber;
//跨线程调用处理
if (subscriber->thread() != QThread::currentThread())
{
QMetaObject::invokeMethod(subscriber, [handler, eventPtr]()
{
handler->func(*eventPtr);
}, Qt::QueuedConnection);
}
//同线程直接调用
else
{
handler->func(*eventPtr);
}
}
}
}
//检查是否有订阅者
template <typename EventType>
bool hasSubscribers()
{
QMutexLocker locker(&m_mutex);
QByteArray eventType = typeid(EventType).name();
return m_subscriptionsByEvent.contains(eventType) &&
!m_subscriptionsByEvent[eventType].isEmpty();
}
signals:
private slots:
void onSubscriberDestroyed(QObject* subscriber);
private:
//清理订阅者
void cleanupSubscriber(QObject* subscriber);
private:
//事件处理基类
struct HandlerBase
{
QObject* subscriber;
QByteArray eventType;
virtual ~HandlerBase() = default;
HandlerBase(QObject* sub, const QByteArray& type)
: subscriber(sub), eventType(type) {}
};
//具体事件处理模板类
template <typename EventType>
struct Handler : public HandlerBase
{
std::function<void(const EventType&)> func;
Handler(QObject* sub, const QByteArray& type, const std::function<void(const EventType&)>& f)
: HandlerBase(sub, type), func(f) {}
};
private:
QMap<QByteArray, QList<HandlerBase*>> m_subscriptionsByEvent; //事件类型映射
QMap<QObject*, QList<HandlerBase*>> m_subscriptionsBySubscriber; //订阅者映射
QMutex m_mutex; //线程安全锁
};
#endif // EVENTBUSSERVICE_H
2 事件总线实现 (EventBusService.cpp)
#include "EventBusService.h"
#include <QThread>
EventBusService::EventBusService() : QObject()
{
}
//析构函数
EventBusService::~EventBusService()
{
QMutexLocker locker(&m_mutex);
//清理所有订阅者
for (auto subscriber : m_subscriptionsBySubscriber.keys())
{
disconnect(subscriber, &QObject::destroyed, this, &EventBusService::onSubscriberDestroyed);
}
//清理所有处理器
for (auto handlerList : m_subscriptionsByEvent.values())
{
for (auto handler : handlerList)
{
delete handler;
}
}
m_subscriptionsByEvent.clear();
m_subscriptionsBySubscriber.clear();
}
//订阅者销毁槽函数
void EventBusService::onSubscriberDestroyed(QObject* subscriber)
{
cleanupSubscriber(subscriber);
}
//清理订阅者
void EventBusService::cleanupSubscriber(QObject* subscriber)
{
QMutexLocker locker(&m_mutex);
if (!m_subscriptionsBySubscriber.contains(subscriber))
{
return;
}
auto handlers = m_subscriptionsBySubscriber[subscriber];
//从事件映射中移除
for (HandlerBase* handler : handlers)
{
auto& eventHandlers = m_subscriptionsByEvent[handler->eventType];
eventHandlers.removeAll(handler);
//如果事件类型没有订阅者了,移除该事件类型
if (eventHandlers.isEmpty())
{
m_subscriptionsByEvent.remove(handler->eventType);
}
delete handler;
}
m_subscriptionsBySubscriber.remove(subscriber);
disconnect(subscriber, &QObject::destroyed, this, &EventBusService::onSubscriberDestroyed);
}
3 事件总线用法示例
3.1 定义事件 (KeyPressedEvent.h)
#ifndef KEYPRESSEDEVENT_H
#define KEYPRESSEDEVENT_H
struct KeyPressedEvent
{
int key;
};
#endif // KEYPRESSEDEVENT_H
3.2 主窗口头文件 (mainwindow.h)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "EventBusService.h"
#include "KeyPressedEvent.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void handleKeyPressed(const KeyPressedEvent &event);
private:
EventBusService *m_eventBusService;
};
#endif // MAINWINDOW_H
3.3 主窗口实现 (mainwindow.cpp)
#include <QDebug>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
m_eventBusService = new EventBusService();
//订阅事件
auto handler = static_cast<void (QObject::*)(const KeyPressedEvent&)>(&MainWindow::handleKeyPressed);
m_eventBusService->subscribe<KeyPressedEvent>(this, handler);
//测试事件
KeyPressedEvent event { 10 };
m_eventBusService->publish(event);
}
MainWindow::~MainWindow()
{
}
void MainWindow::handleKeyPressed(const KeyPressedEvent &event)
{
qDebug() << "===== KeyPressed: " << event.key;
}

浙公网安备 33010602011771号