CTK 事件管理机制(signal/slot)

来源:互联网 发布:来自mac的照片怎么删除 编辑:程序博客网 时间:2024/06/09 16:25

简述

在 CTK 中,插件之间的通信,可以通过 Event Admin 来完成。Event Admin 是一种基于发布/订阅的方式,一个插件订阅某一主题之后,另一个插件发布一个与该主题相关的事件,从而达到通信的目的。

除了 CTK 事件管理机制(sendEvent()/postEvent()) 中介绍的 sendEvent()/postEvent() + ctkEventHandler 方式之外,Event Admin 还提供了另一种方式 - signal/slot,可以达到相同的效果。

  • 简述
  • 使用事件管理机制
    • 工程文件
    • 事件发布者
    • 事件处理程序
    • 主程序
  • 比较

版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820

使用事件管理机制

下面,来演示 signal/slot 方式:

这里写图片描述

工程文件

创建一个 Qt 控制台应用程序,.pro 内容如下:

QT += coreQT -= guiTARGET = PublishSignalCONFIG += consoleTEMPLATE = appLIBS += -L$$PWD/Libs -lCTKCore -lCTKPluginFrameworkINCLUDEPATH += \    $$PWD/../../../CTK-master/Libs/Core \    $$PWD/../../../CTK-master/Libs/PluginFrameworkHEADERS += \    publisher.h \    subscriber.hSOURCES += \    main.cpp \    publisher.cpp \    subscriber.cpp

需要同时包含 CTKCoreCTKPluginFramework

事件发布者

使用 Qt 信号来发布事件需要声明一个 signal,并使用 Event Admin 注册(发布)它。

publisher.h 内容如下:

#ifndef PUBLISHER_H#define PUBLISHER_H#include <QObject>#include <ctkPluginContext.h>#include <service/event/ctkEventAdmin.h>// 事件发布者class Publisher : public QObject{    Q_OBJECTpublic:    Publisher(ctkPluginContext* context);    // 使用一个特定的主题来注册信号    void publishSignal();    // 发布事件    void publish();signals:    void finished(const ctkDictionary&);private:    ctkPluginContext* pc;};#endif // PUBLISHER_H

使用一个特定的主题来注册信号(发射信号将始终发送 ctkEvent 对象,该对象将此主题作为 EVENT_TOPIC 属性)。

publisher.cpp 内容如下:

#include "publisher.h"Publisher::Publisher(ctkPluginContext *context)    : pc(context){}// 使用一个特定的主题来注册信号void Publisher::publishSignal(){    ctkServiceReference ref = pc->getServiceReference<ctkEventAdmin>();    if (ref) {        ctkEventAdmin* eventAdmin = pc->getService<ctkEventAdmin>(ref);        eventAdmin->publishSignal(this, SIGNAL(finished(ctkDictionary)),                                  "org/commontk/login", Qt::DirectConnection);    }}// 发布事件void Publisher::publish(){    ctkDictionary props;    props.insert("name", "Waleon");    props.insert("age", 18);    emit finished(props);}

发射信号将自动创建一个 ctkEvent 对象,同步或异步发送,取决于发射信号时使用的 Qt:ConnectionType

事件处理程序

ctkEvent 对象作为参数的每个 Qt 槽,都可以被订阅来接收事件通知。

subscriber.h 内容如下:

#ifndef SUBSCRIBER_H#define SUBSCRIBER_H#include <QObject>#include <ctkPluginContext.h>#include <service/event/ctkEvent.h>// 事件处理程序(或订阅者)class Subscriber : public QObject{    Q_OBJECTpublic:    Subscriber(ctkPluginContext* context);    // 可以被订阅,来接收事件通知    void subscribeSlot();private slots:    // 处理事件    void onFinished(const ctkEvent& event);private:    ctkPluginContext* pc;};#endif // SUBSCRIBER_H

subscriber.cpp 内容如下:

#include "subscriber.h"#include <QDebug>#include <service/event/ctkEventConstants.h>#include <service/event/ctkEventAdmin.h>Subscriber::Subscriber(ctkPluginContext* context)    : QObject(),      pc(context){}// 可以被订阅,来接收事件通知void Subscriber::subscribeSlot(){    ctkDictionary props;    props[ctkEventConstants::EVENT_TOPIC] = "org/commontk/login";    ctkServiceReference ref = pc->getServiceReference<ctkEventAdmin>();    if (ref) {        ctkEventAdmin* eventAdmin = pc->getService<ctkEventAdmin>(ref);        eventAdmin->subscribeSlot(this, SLOT(onFinished(ctkEvent)), props);    }}// 处理事件void Subscriber::onFinished(const ctkEvent& event){    QString name = event.getProperty("name").toString();    int age = event.getProperty("age").toInt();    qDebug() << QString("name:%1 age:%2").arg(name).arg(age);}

使用 Qt 槽作为事件处理程序,可以很容易地确保事件处理代码在接收者的线程中执行(默认的连接类型是 Qt::AutoConnection)。

主程序

最后,来看看 main.cpp

#include <QCoreApplication>#include <ctkPluginFrameworkLauncher.h>#include <ctkPluginContext.h>#include "publisher.h"#include "subscriber.h"// liborg_commontk_eventadmin.dll 所在路径const QString c_strSearchPath = "E:/CTK-Examples/EventAdmin/PublishSignal/Plugins";int main(int argc, char *argv[]){    QCoreApplication app(argc, argv);    // 在插件的搜索路径列表中添加一条路径    ctkPluginFrameworkLauncher::addSearchPath(c_strSearchPath);    // 设置并启动 CTK 插件框架    ctkPluginFrameworkLauncher::start("org.commontk.eventadmin");    // 获取插件上下文    ctkPluginContext* pluginContext = ctkPluginFrameworkLauncher::getPluginContext();    // 订阅接收事件    Subscriber sub(pluginContext);    sub.subscribeSlot();    Publisher pub(pluginContext);    // 使用一个特定的主题来注册信号    pub.publishSignal();    // 发布事件    pub.publish();    // 停止插件    ctkPluginFrameworkLauncher::stop();    return app.exec();}

好了,此过程在前面已经讲过,这里就不再赘述。

比较

回过头来,比较下这两种方式:

  • sendEvent()/postEvent() + ctkEventHandler
  • signal/slot

使用 Qt 信号,可以简化发送事件的行为。然而,由于信号发射需要经过 Qt 元对象系统,所以其性能较差。此外,信号被绑定到一个特定的事件主题上。

使用 ctkEventHandler 接口或 Qt 槽来注册一个事件处理程序,涉及的代码量大致相同。然而,使用槽会降低性能(可能会被忽略不计),但是代码将自动与接收者线程同步。

此外,订阅槽意味着需要一个已注册的事件管理服务实现。而 ctkEventHandler 方式不需要了解 Event Admin 的任何信息,因为 handler 被注册为框架中的一个服务对象。