文章目录

  • Qt 之 开源事件总线模块
    • libgitlevtbus
    • 模型
    • 模块
      • Event
      • EventBus
      • Module
      • ModuleDelegate
    • TestCase

Qt 之 开源事件总线模块

libgitlevtbus

用到了libgitlevtbus
(libgitlevtbus)[https://github.com/lheric/libgitlevtbus]

  • 介绍
    libgitlevtbus 是一个基于Qt的开源的事件总线(消息总线 ) , BSD lisence.
  • 特征
1. Easy to use (c++11 feature supported: lambda expression, member function callback, ...) //C++11新特性,lambda表达式, 成员函数回调
2. Custom event support (carry custom parameters)                                          //用户事件支持(可携带用户自定义的参数)
3. Events can be deliverd across threads                                                   //事件可以跨线程
  • Demo
#include "gitlmodule.h"
#include <QDebug>int main(int argc, char *argv[])
{GitlModule cModule;/// subscribe to an eventcModule.subscribeToEvtByName("I am a test event",[](GitlEvent& rcEvt)->bool{qDebug() << "Hello GitlEvtBus!";return true;});GitlEvent cEvent("I am a test event");              ///< create an eventcEvent.dispatch();                                  ///< dispatch/// output: "Hello GitlEvtBus!"*/return 0;
}

模型

模块

该事件总线模型主要有以下几个类构成:

  • Event
  • EventBus
  • Module
  • ModuleDelegate

Event

该类是事件类,主要内容有:

  1. 事件名称
  2. 事件是否带有参数
  3. 事件参数的设置和获取
  4. 事件的发布(dispatch):调用Bus的Post接口,将事件派发到总线上,所有订阅该事件的module都会收到消息
  • gitlevent.h
#ifndef GITLEVENT_H
#define GITLEVENT_H
#include <QString>
#include <QMap>
#include <QVariant>
#include "gitldef.h"
#include "gitleventparam.h"class GitlModule;
class GitlEventBus;/*!* \brief The GitlEvent class represents an event.*  If you want to create an custom event by inherit GitlEvent, you ***MUST****  reimplement the 'clone' method in this class. This can be done by adding*  VIRTUAL_COPY_PATTERN(subclassname) in the subclass. Otherwise the application*  may crash*/
class GitlEvent
{/// virtual copy pattern, please add this macro to all the subclassCLONABLE(GitlEvent)public:GitlEvent( const QString& strEvtName );GitlEvent();virtual ~GitlEvent() {}/*!* \brief hasParameter if this event carries a specific parameter* \param strParam parameter name* \return*/bool hasParameter(QString strParam) const;/*!* \brief getParameter get the value of a specific parameter* \param strParam parameter name* \return parameter value, if it does not exist, return a default-constructed QVariant*/QVariant getParameter(const QString& strParam ) const;/*!* \brief setParameter set the value of a  specific parameter* \param strParam parameter name* \param rvValue parameter value* \return*/bool setParameter(const QString& strParam, const QVariant& rvValue);/*!* \brief dispatch dispatch this event to event bus, all module subscribed to this event name will be notified.* \param pcEventBus If pcEventBus is NULL, it will find a global (default) event bus and post the event onto the bus.*                   Or you can specify another event bus.*/void dispatch(GitlEventBus *pcEventBus = NULL) const;protected:    ADD_CLASS_FIELD(QString, strEvtName, getEvtName, setEvtName)            ///< event nameADD_CLASS_FIELD_NOSETTER(GitlEventParam, cParameters, getParameters)    ///< event parameters-value pair};
  • gitlevent.cpp
#include "gitlevent.h"
#include "gitlmodule.h"
#include <QDebug>
#include "gitleventbus.h"
#include <QSharedPointer>
GitlEvent::GitlEvent( const QString& strEvtName )
{this->m_strEvtName = strEvtName;
}GitlEvent::GitlEvent()
{this->m_strEvtName = "UNKNOWN";
}bool GitlEvent::hasParameter(QString strParam) const
{return m_cParameters.hasParameter(strParam);
}QVariant GitlEvent::getParameter(const QString& strParam ) const
{return m_cParameters.getParameter(strParam);
}bool GitlEvent::setParameter(const QString& strParam, const QVariant& rvValue)
{m_cParameters.setParameter(strParam, rvValue);return true;
}void GitlEvent::dispatch(GitlEventBus* pcEventBus) const
{if(pcEventBus == NULL)GitlEventBus::getInstance()->post(*this);elsepcEventBus->post(*this);
}

EventBus

事件总线,在实际应用中,可以有多条事件总线,每条总线挂接不同的Module.

  • 单例模式,在该类中,存在该类型的单例模式,当module未指定某个Bus时, 默认情况都使用该单例
  • register: 将ModuleDelegate 的denotate关联至该总线的post接口发出的eventTriggered信号
  • post: 将Event传递至总线。上述的Event中的dispatch接口,最终调用的某个Bus对象的post接口。

EventBus的核心: 注册ModuleDelegate, 发布Event 消息

  • gitleventbus.h
#ifndef GITLEVENTBUS_H
#define GITLEVENTBUS_H#include <QList>
#include <QObject>
#include <QMutex>
#include <QMutexLocker>
#include <QSharedPointer>
#include "gitldef.h"
#include "gitlevent.h"
#include "gitlmodule.h"class GitlModuleDelegate;
/*!* \brief The GitlEventBus class represents the event bus*/
class GitlEventBus : public QObject
{Q_OBJECT
private:GitlEventBus();public:/*!* \brief create The safe way to explictly create a new event bus* \return*/static GitlEventBus *create();/*!* \brief registerModule connect a module to the event bus* \param pcModule* \return*/bool registerModule(GitlModuleDelegate *pcModule);/*!* \brief unregisterModule disconncet a module from the event bus* \param pcModule* \return*/bool unregisterModule(GitlModuleDelegate *pcModule);public slots:/*! send event to event bus*/void post(const GitlEvent &rcEvt) const;signals:/*! message to send*/void eventTriggered( QSharedPointer<GitlEvent> pcEvt ) const;///SINGLETON design patternSINGLETON_PATTERN_DECLARE(GitlEventBus)};#endif // GITLEVTBUS_H
  • gitleventbus.cpp
#include "gitleventbus.h"
#include <QDebug>SINGLETON_PATTERN_IMPLIMENT(GitlEventBus)GitlEventBus::GitlEventBus()
{}GitlEventBus *GitlEventBus::create()
{return new GitlEventBus();
}/*! connect a module to the event bus*/
Q_DECLARE_METATYPE( QSharedPointer<GitlEvent> )
bool GitlEventBus::registerModule(GitlModuleDelegate* pcModule)
{    qRegisterMetaType< QSharedPointer<GitlEvent> >("QSharedPointer<GitlEvent>");connect(this,     SIGNAL(eventTriggered(QSharedPointer<GitlEvent>) ),pcModule, SLOT  (detonate      (QSharedPointer<GitlEvent>) ),Qt::AutoConnection );return true;
}bool GitlEventBus::unregisterModule(GitlModuleDelegate *pcModule)
{return disconnect(this, NULL, pcModule, NULL);
}/*! send event to event bus*/
void GitlEventBus::post(const GitlEvent& rcEvt) const
{    QSharedPointer<GitlEvent> pcEvtCopy( rcEvt.clone() );/// notify modulesemit eventTriggered(pcEvtCopy);}

Module

Module 和 ModuleDelegate 使用了委托模式, 将实际的工作都交给了ModuleDelegate处理了。

委托模式:
一个对象接收到了请求,但是自己不处理,交给另外的对象处理,就是委托模式,例如 老板接到了活,
然后把活转手给了工人去做。

这里的Module有一个私有成员: ModuleDelegate, Event其实并不知道这一层关系的存在,在它眼里,只有BusEvent。
Module的行为(动作), 最后都转化成ModuleDelegate去执行了, 仿佛只是套了个壳。

  • gitlmodule.h
#include <QSharedPointer>#include "gitldef.h"
#include "gitlevent.h"#include "gitlmoduledelegate.h"class GitlEventBus;/*!* \brief The GitlModule class represents a module*/class GitlModule
{public:/*** @brief GitlModule Represents a module in the event bus. It will keep listening to events*                   in the event bus and catch those it is interested in.* @param pcEventBus If pcEventBus it will find a gloabl event bus using singleton pattern.*                   Or you can specify an exsiting event bus.*/GitlModule(GitlEventBus* pcEventBus = NULL);/*!* \brief subscribeToEvtByName Subscribe to an event* \param strEvtName event name* \param pfListener listener callback function*/void subscribeToEvtByName(const QString& strEvtName,const GitlCallBack& pfListener  );/*!* \brief unsubscribeToEvtByName Unsubscribe to an event* \param strEvtName event name*/void unsubscribeToEvtByName( const QString& strEvtName );/*!* \brief dispatchEvt Dispatch an event* \param rcEvt event*/void dispatchEvt(GitlEvent &rcEvt );/*!* \brief setModuleName Set the name of this module. That's ok if you do not* give a name to this module. But for better debugging, we recommend you name it.* \param strModuleName name for this module*/void setModuleName(QString strModuleName );/*** @brief getEventBus Get the event bus that this module is attached to* @return*/GitlEventBus* getEventBus();/*!* \brief detach Detach the module*/void detach();/*!* \brief attach Attach the module to a new event bus* \param pcEventBus*/void attach(GitlEventBus *pcEventBus);/// Delegate pattern/// Avoiding this class becoming a subclass of QObject/// (GUI class is based on QOBject, but QObject doesn't support virtual inheritance).ADD_CLASS_FIELD_PRIVATE( GitlModuleDelegate, cDelegate )
};#endif // GITLMODULE_H
  • gitlmodule.cpp
#include "gitlmodule.h"
#include "gitleventbus.h"
#include <QDebug>GitlModule::GitlModule(GitlEventBus *pcEventBus) :m_cDelegate(this, pcEventBus)
{
}void GitlModule::subscribeToEvtByName( const QString& strEvtName,const GitlCallBack& pfListener )
{return m_cDelegate.subscribeToEvtByName(strEvtName, pfListener);
}void GitlModule::unsubscribeToEvtByName( const QString& strEvtName )
{return m_cDelegate.unsubscribeToEvtByName(strEvtName);
}void GitlModule::dispatchEvt( GitlEvent& rcEvt )
{m_cDelegate.dispatchEvt(rcEvt);
}void GitlModule::setModuleName( QString strModuleName )
{m_cDelegate.setModuleName(strModuleName);
}GitlEventBus *GitlModule::getEventBus()
{return m_cDelegate.getGitlEvtBus();
}void GitlModule::detach()
{m_cDelegate.detach();
}void GitlModule::attach(GitlEventBus *pcEventBus)
{m_cDelegate.attach(pcEventBus);
}

ModuleDelegate

由于真正干活的是这位老兄,所以,它除了和Module具有类似的接口,还需要额外维护一些私有成员,比如Module的名字,Event事件和回调接口的QMap关系表。

  • gitlmoduledelegate.h
#ifndef GITLMODULEDELEGATE_H
#define GITLMODULEDELEGATE_H#include <QObject>
#include <QMap>
#include <QMutex>
#include <QMutexLocker>
#include <QSharedPointer>
#include <functional>
#include "gitldef.h"
#include "gitlevent.h"class GitlModule;
class GitlEventBus;///
/// \brief GitlCallBack gitl event callback function
///
typedef std::function<bool (GitlEvent&)> GitlCallBack;class GitlModuleDelegate : public QObject
{Q_OBJECTfriend class GitlModule;  //can access the GitlModule
private:explicit GitlModuleDelegate(GitlModule *pcDelegator, GitlEventBus *pcEventBus = NULL);public:/*!* \brief subscribeToEvtByName listening to an event by name* \param strEvtName event name*/void subscribeToEvtByName( const QString& strEvtName,GitlCallBack pfListener );/*!* \brief subscribeToEvtByName not listening to an event by name* \param strEvtName event name*/void unsubscribeToEvtByName( const QString& strEvtName );/*!* \brief dispatchEvt dispatch an event to subscribers* \param pcEvt event*/void dispatchEvt(const GitlEvent &rcEvt  ) const;/*!* \brief detach Detach the module*/void detach();/*!* \brief attach Attach the module to a new event bus* \param pcEventBus*/void attach(GitlEventBus *pcEventBus);public slots:/*!* \brief detonate notifyed by event bus* \param cEvt* \return*/bool detonate( QSharedPointer<GitlEvent> pcEvt );protected:bool xIsListenToEvt(const QString& strEvtName);ADD_CLASS_FIELD( QString, strModuleName, getModuleName, setModuleName )ADD_CLASS_FIELD_PRIVATE( CONCATE(QMap<QString, GitlCallBack>), cListeningEvts )ADD_CLASS_FIELD_NOSETTER( GitlEventBus*, pcGitlEvtBus, getGitlEvtBus )ADD_CLASS_FIELD_PRIVATE(GitlModule*, pcDelegator)};#endif // GITLMODULEDELEGATE_H
  • gitlmoduledelegate.cpp
#include "gitlmoduledelegate.h"
#include "gitleventbus.h"
#include <QDebug>
#include <iostream>
using namespace std;
GitlModuleDelegate::GitlModuleDelegate(GitlModule *pcDelegator, GitlEventBus* pcEventBus)
{m_pcDelegator = pcDelegator;if(pcEventBus == NULL)m_pcGitlEvtBus = GitlEventBus::getInstance();elsem_pcGitlEvtBus = pcEventBus;m_pcGitlEvtBus->registerModule(this);      //调用eventBus注册moduleDelegatem_strModuleName = "undefined_module_name";}void GitlModuleDelegate::subscribeToEvtByName(const QString& strEvtName, GitlCallBack pfListener )
{m_cListeningEvts.insert(strEvtName, pfListener);return;
}void GitlModuleDelegate::unsubscribeToEvtByName( const QString& strEvtName )
{m_cListeningEvts.remove(strEvtName);
}bool GitlModuleDelegate::detonate(QSharedPointer<GitlEvent> pcEvt )
{QMap<QString, std::function<bool (GitlEvent&)>>::iterator p =m_cListeningEvts.find(pcEvt->getEvtName());if( p != m_cListeningEvts.end() ){(p.value())(*pcEvt.data());}return true;
}bool GitlModuleDelegate::xIsListenToEvt( const QString& strEvtName )
{return m_cListeningEvts.contains(strEvtName);
}void GitlModuleDelegate::dispatchEvt( const GitlEvent& rcEvt ) const
{if(m_pcGitlEvtBus != NULL)m_pcGitlEvtBus->post(rcEvt);
}void GitlModuleDelegate::detach()
{if(m_pcGitlEvtBus != NULL)m_pcGitlEvtBus->unregisterModule(this);m_pcGitlEvtBus = NULL;
}void GitlModuleDelegate::attach(GitlEventBus *pcEventBus)
{if(pcEventBus == NULL)return;detach();m_pcGitlEvtBus = pcEventBus;m_pcGitlEvtBus->registerModule(this);
}

TestCase

#include <QCoreApplication>
#include <iostream>
#include <QtTest/QtTest>
#include <QTest>
#include <QSharedPointer>
#include <QString>
#include <functional>
#include "gitldef.h"
#include "gitlmodule.h"
#include "gitleventbus.h"
using namespace std;/// test event bus
class TestModule : public GitlModule    //继承自GitlModule
{public:TestModule(GitlEventBus* pcEventBus = NULL):GitlModule(pcEventBus){this->m_bNotified = false;}void subscribeInsideClass(){subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK(TestModule::callback));  //绑定内部的callback函数}bool callback( GitlEvent& rcEvt){Q_UNUSED(rcEvt)this->m_bNotified = true;return true;}ADD_CLASS_FIELD(bool, bNotified, getNotified, setNotified)
};/// custom event, 用户自定义事件,集成GitlEvent
class CustomEvent : public GitlEvent
{CLONABLE(CustomEvent)
public:CustomEvent( const QString& strEvtName ) : GitlEvent(strEvtName) { m_strCustomVar = "Custom String";  //自定义私有成员}ADD_CLASS_FIELD(QString, strCustomVar, getCustomVar, setCustomVar)
};/// 用户自定义事件监听模块,继承自GitlModule
class CustomEventListener : public GitlModule
{public:CustomEventListener(){this->m_bNotified = false;}bool callback( GitlEvent& rcEvt){CustomEvent& pcCusEvt = static_cast<CustomEvent&>(rcEvt);this->m_bNotified = true;this->m_strCustomVar = pcCusEvt.getCustomVar();return true;}ADD_CLASS_FIELD(bool, bNotified, getNotified, setNotified)ADD_CLASS_FIELD(QString, strCustomVar, getCustomVar, setCustomVar)
};/// test case
class TestCase : public QObject
{Q_OBJECTprivate slots:void lamdaListening(){TestModule cModule;cModule.subscribeToEvtByName("TEST_EVENT_1",[&](GitlEvent& e)->bool{Q_UNUSED(e)cModule.setNotified(true);return true;});QVERIFY(!cModule.getNotified());  //QVERIFY(condition)GitlEvent cEvt("TEST_EVENT_1");cModule.dispatchEvt(cEvt);QVERIFY(cModule.getNotified());}void listenInsideClass(){TestModule cModule;cModule.subscribeInsideClass();QVERIFY(!cModule.getNotified());GitlEvent cEvt("TEST_EVENT_1");cEvt.dispatch();QVERIFY(cModule.getNotified());}void listenOutsideClass(){TestModule cModule;cModule.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule, TestModule::callback));QVERIFY(!cModule.getNotified());GitlEvent cEvt("TEST_EVENT_1");cModule.dispatchEvt(cEvt);QVERIFY(cModule.getNotified());}void unsubscribe(){TestModule cModule;cModule.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule, TestModule::callback));cModule.unsubscribeToEvtByName("TEST_EVENT_1");QVERIFY(!cModule.getNotified());GitlEvent cEvt("TEST_EVENT_1");cModule.dispatchEvt(cEvt);QVERIFY(!cModule.getNotified());}/// 一对多,一个事件,多个Module关注void oneToMany(){TestModule cSender;TestModule cModule1;TestModule cModule2;TestModule cModule3;cModule1.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule1, TestModule::callback));cModule2.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule2, TestModule::callback));cModule3.subscribeToEvtByName("TEST_EVENT_2", MAKE_CALLBACK_OBJ(cModule3, TestModule::callback));GitlEvent cEvt1("TEST_EVENT_1");cSender.dispatchEvt(cEvt1);  //某个Module 派发Event, 而其他Module 关注该Event的后进行处理QVERIFY(cModule1.getNotified());QVERIFY(cModule2.getNotified());QVERIFY(!cModule3.getNotified());GitlEvent cEvt2("TEST_EVENT_2");cSender.dispatchEvt(cEvt2);QVERIFY(cModule3.getNotified());}/// 用户自定义事件测试void customEventTest(){CustomEventListener cModule;cModule.subscribeToEvtByName("TEST_EVENT_1",MAKE_CALLBACK_OBJ(cModule, CustomEventListener::callback));CustomEvent cEvt("TEST_EVENT_1");cEvt.dispatch();qDebug()<<__FUNCTION__<<cModule.getNotified();qDebug()<<__FUNCTION__<<cModule.getCustomVar();QVERIFY(cModule.getNotified());QVERIFY(cModule.getCustomVar() == QString("Custom String"));  //用户自定义的参数,  需要关注CModule的getCustomVar}///多个EventBus和多个Module对象void multiplyEventBus(){GitlEventBus* pcBus1 = GitlEventBus::create(); TestModule cModule1(pcBus1); TestModule cModule2(pcBus1);GitlEventBus* pcBus2 = GitlEventBus::create(); TestModule cModule3(pcBus2); TestModule cModule4(pcBus2);/// all module are listening to the same events, but on different event buses.cModule1.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule1, TestModule::callback));cModule2.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule2, TestModule::callback));cModule3.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule3, TestModule::callback));cModule4.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule4, TestModule::callback));/// eventCustomEvent cEvt("TEST_EVENT_1");/// no one get notified because no module is attached to the default event buscEvt.dispatch();QVERIFY(!cModule1.getNotified());QVERIFY(!cModule2.getNotified());QVERIFY(!cModule3.getNotified());QVERIFY(!cModule4.getNotified());/// this will only notify module 1 & 2cEvt.dispatch(pcBus1);QVERIFY(cModule1.getNotified());QVERIFY(cModule2.getNotified());QVERIFY(!cModule3.getNotified());QVERIFY(!cModule4.getNotified());/// this will notify module 3 & 4cEvt.dispatch(cModule3.getEventBus());QVERIFY(cModule3.getNotified());QVERIFY(cModule4.getNotified());/// make sure everyone is attached to the correct event busQVERIFY(cModule1.getEventBus() == pcBus1);QVERIFY(cModule2.getEventBus() == pcBus1);QVERIFY(cModule3.getEventBus() == pcBus2);QVERIFY(cModule4.getEventBus() == pcBus2);/// create cModule5TestModule cModule5(pcBus1);cModule5.subscribeToEvtByName("TEST_EVENT_1", MAKE_CALLBACK_OBJ(cModule5, TestModule::callback));cEvt.dispatch(pcBus2);QVERIFY(!cModule5.getNotified());cModule5.attach(pcBus2);cEvt.dispatch(pcBus2);QVERIFY(cModule5.getNotified());}
};/// test main
QTEST_MAIN(TestCase)
#include "testcase.moc"
  • 运行测试结果
********* Start testing of TestCase *********
Config: Using QtTest library 5.14.2, Qt 5.14.2 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.1 20160406 (Red Hat 5.3.1-6))
PASS   : TestCase::initTestCase()
PASS   : TestCase::lamdaListening()
PASS   : TestCase::listenInsideClass()
PASS   : TestCase::listenOutsideClass()
PASS   : TestCase::unsubscribe()
PASS   : TestCase::oneToMany()
QDEBUG : TestCase::customEventTest() customEventTest true
QDEBUG : TestCase::customEventTest() customEventTest "Custom String"
PASS   : TestCase::customEventTest()
PASS   : TestCase::multiplyEventBus()
PASS   : TestCase::cleanupTestCase()
Totals: 9 passed, 0 failed, 0 skipped, 0 blacklisted, 1ms
********* Finished testing of TestCase *********

Qt 之 事件总线模型相关推荐

  1. EventBridge 事件总线及 EDA 架构解析

    简介:EventBridge 是事件驱动的具体落地产品,也是 EDA 的最佳实践方式. 作者:肯梦 作为 Gartner 定义的 10 大战略技术趋势之一,事件驱动架构(EDA)逐渐成为主流技术架构. ...

  2. Android事件总线还能怎么玩?

    作者简介:何红辉,Android工程师,现任职于友盟. 顾名思义,AndroidEventBus是一个Android平台的事件总线框架,它简化了Activity.Fragment.Service等组件 ...

  3. 8.QT的事件循环与事件发送相关类

    一.QT的事件发送类QCoreApplication QT使用QCoreApplication类为Qt程序提供了事件循环机制.该类继承QObject.QCoreApplication包含主事件循环,来 ...

  4. Android--Otto事件总线 -- 组件之间通讯框架使用 --模式解析

    前言:Otto事件总线 -- 组件之间通讯框架 对于之前的情况activity之间或者fragment之间等跳转传值一般都是用bundle.intent等,从activityA --- activit ...

  5. Qt中的自定义模型类

    文章目录 1 Qt中的通用模型类 1.1 Qt中的通用模型类 1.2 Qt中的变体类型QVariant 2 自定义模型类 2.1 自定义模型类设计分析 2.2 自定义模型类数据层.数据表示层.数据组织 ...

  6. 阿里云 Serverless 事件总线 EventBridge 重磅发布

    简介:近年来,随着云原生和 Serverless 概念的深入人心,事件驱动再一次成为了云应用架构领域的热门词汇.在 2018 年,Gartner 评估报告将 Event-Driven Model 列为 ...

  7. QT的事件分发、事件过滤器详解

    一.事件的流向 QT的各种控件(QObject的子类)都有事件处理成员函数,例如: bool QObject::event(QEvent *e);//所有事件 dragEnterEvent(QDrag ...

  8. 如何通过本地化事件正确实现微服务内部强一致性,事件总线跨微服务间最终一致性...

    目录 设计重点 流程图 伪代码 2.1. PublishEvent 2.2. SubscribeEvent 2.3. Publisher 2.4. Subscriber 微服务 强一致性 3.1 Pu ...

  9. Android之事件总线EventBus详解

    顾名思义,AndroidEventBus是一个Android平台的事件总线框架,它简化了Activity.Fragment.Service等组件之间的交互,很大程度上降低了它们之间的耦合,使我们的代码 ...

最新文章

  1. GeoIP的使用 - PHP版
  2. 通关制单机器人_2020关务节|“数字供应链与智能通关”论坛——如何打造云上跨境贸易生态圈...
  3. NLP任务非Transformer不可?
  4. 【资源】100+本数据科学电子书
  5. oracle发送邮件
  6. 亲和属性和链路管理组的TE隧道路径控制原理
  7. zoj 3791 An Easy Game
  8. 如何理解Bounce Rate和Exit Rate
  9. java设置面板的大小_java – 设置面板的大小
  10. 金立手机用60亿“砸死”了自己
  11. cs python课程 加州大学_最新盘点!全球顶尖大学CS+数据科学的免费在线课程,共81个...
  12. 跑步进入全站 HTTPS ,这些经验值得你看看
  13. 如何应用Matlab plot画点
  14. 六个步骤 教你搭建Ubuntu nfs服务器
  15. php发起预约申请,php版微信公众平台实现预约提交后发送email的方法
  16. 大数据分析的学习感悟
  17. 互联网经济催生了一些新职业,带来新机遇!
  18. 华硕服务器安装系统安装教程,华硕u盘安装系统教程
  19. php主机卫士,Bypass 360主机卫士SQL注入防御(附tamper脚本)
  20. 项目二:python爬取豆瓣电影信息并分析

热门文章

  1. hive_hbase一个综合练习题目总共包括以下部分
  2. 华为Mate系列主要参数
  3. 陈学贤华南理工大学计算机专业,张见威 - 华南理工大学 - 计算机科学与工程学院...
  4. 对Redis数据库的学习!
  5. 做外贸十大不能接的订单!
  6. 使用opencv实现通过摄像头自动输入阿里云身份宝验证码
  7. 抖音直播运营分析:深入解读直播带货运营那些专业术语
  8. 绝对良心提供百度网盘的jdk1.8源码下载包含sun包的
  9. react报错Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
  10. -Cannot use v-for on stateful component root element because it renders multiple elements