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;
}
posted @ 2025-07-09 13:13  xhubobo  阅读(86)  评论(0)    收藏  举报