文章目录
- 一、前言
- 二、事件
- 三、类通信
- 3.1、新建接收插件
- 3.2、新建发送插件
- 3.3、启用插件
- 四、信号槽通信
- 4.1、新建接收插件
- 4.2、新建发送插件
- 4.3、启用插件
- 五、类通信和信号槽通信的区别
- 六、插件依赖
- 七、获取元数据
一、前言
CTK框架中的事件监听,其实就是观察者模式,流程大概如下:
- 接收者注册监听事件(接收方想监听xxx信息)
- 发送者发送事件(发送方发送xxx信息)
- 接收者接收到事件并响应(接收方收到xxx事件后的动作)
相比调用插件接口,监听事件插件间依赖关系更弱,不用指定事件的接收方和发送方是谁
要使用CTK框架的事件服务,在编译CTK库是需要编译出支持事件监听的动态库:liborg_commontk_eventadmin.dll
在编译输出的CTK文件夹中可以找到
加载EventAdmin动态库:main.cpp
中新增如下代码
#include "ctkPluginFrameworkLauncher.h"
// 获取插件所在位置
// 在插件的搜索路径列表中添加一条路径
ctkPluginFrameworkLauncher::addSearchPath("../CTK/lib/ctk-0.1/plugins");
// 设置并启动 CTK 插件框架
ctkPluginFrameworkLauncher::start("org.commontk.eventadmin");
// 停止插件
//ctkPluginFrameworkLauncher::stop();
二、事件
1、通信主要用到了ctkEventAdmin
结构体,主要定义了如下接口:
事件 | 说明 |
---|---|
postEvent | 类通信形式,异步发送事件 |
sendEvent | 类通信形式,同步发送事件 |
publishSignal | 信号与槽通信形式发送事件 |
unpublishSignal | 取消发送事件 |
subscribeSlot | 信号与槽通信形式订阅事件,返回订阅的ID |
unsubscribeSlot | 取消订阅事件 |
updateProperties | 更新某个订阅ID的主题 |
2、通信是数据:ctkDictionary
其实就是个hash表:typedef QHash<QString,QVariant> ctkDictionary
三、类通信
原理:直接将信息使用CTK的eventAdmin接口send/post出去;
3.1、新建接收插件
插件结构说明:
- BlogEventHandler:接收类【订阅者】
- BlogEventHandlerActivator:激活类
工程文件:BlogEventHandler.pro
QT += core
QT -= gui
TEMPLATE = lib
CONFIG += plugin
TARGET = BlogEventHandler
DESTDIR = $$OUT_PWD/bin/plugins
include($$PWD/../CTK/CTK_dependency.pri)
RESOURCES += \
qresource.qrc
HEADERS += \
BlogEventHandler.h \
blog_event_handler_activator.h
SOURCES += \
blog_event_handler_activator.cpp
激活类:BlogEventHandlerActivator
#ifndef BLOGEVENTHANDLERACTIVATOR_H
#define BLOGEVENTHANDLERACTIVATOR_H
#include <ctkPluginActivator.h>
class BlogEventHandler;
class BlogEventHandlerActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "BLOG_EVENT_HANDLER")
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
private:
BlogEventHandler *m_pEventHandler;
};
#endif // BLOGEVENTHANDLERACTIVATOR_H
#include "blog_event_handler.h"
#include "blog_event_handler_activator.h"
#include <service/event/ctkEventConstants.h>
#include <QtDebug>
void BlogEventHandlerActivator::start(ctkPluginContext* context)
{
m_pEventHandler = new BlogEventHandler();
ctkDictionary props;
props[ctkEventConstants::EVENT_TOPIC] = "org/commontk/bloggenerator/published"; //订阅的主题
props[ctkEventConstants::EVENT_FILTER] = "(author=wangjichuan)"; //事件过滤
context->registerService<ctkEventHandler>(m_pEventHandler, props);
}
void BlogEventHandlerActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
delete m_pEventHandler;
}
接收类[订阅者]:BlogEventHandler
#ifndef BLOGEVENTHANDLER_H
#define BLOGEVENTHANDLER_H
#include <QObject>
#include <service/event/ctkEventHandler.h>
// 事件处理程序(或订阅者)
class BlogEventHandler : public QObject, public ctkEventHandler
{
Q_OBJECT
Q_INTERFACES(ctkEventHandler)
public:
BlogEventHandler();
// 处理事件
void handleEvent(const ctkEvent& event) Q_DECL_OVERRIDE;
};
#endif // BLOGEVENTHANDLER_H
#include "blog_event_handler.h"
BlogEventHandler::BlogEventHandler()
{
}
void BlogEventHandler::handleEvent(const ctkEvent& event)
{
QString title = event.getProperty("title").toString();
QString content = event.getProperty("content").toString();
QString author = event.getProperty("author").toString();
qDebug()<<"====================================================";
qDebug()<<"=== EventHandler received the message ===";
qDebug()<<"topic: "<<event.getTopic();
qDebug()<<"----------- properties -----------";
qDebug()<<"title: "<<title;
qDebug()<<"content: "<<content;
qDebug()<<"author: "<<author;
}
3.2、新建发送插件
插件结构说明:
- BlogManager:发送类【发布者】
- BlogManagerActivator:激活类
添加代码
工程文件:BlogManager.pro
QT += core
QT -= gui
TEMPLATE = lib
CONFIG += plugin
TARGET = BlogManager
DESTDIR = $$OUT_PWD/bin/plugins
include($$PWD/../CTK/CTK_dependency.pri)
RESOURCES += \
qresource.qrc
HEADERS += \
blog_manager.h \
blog_manager_activator.h
SOURCES += \
blog_manager.cpp \
blog_manager_activator.cpp
激活类:BlogManagerActivator
#ifndef BLOG_MANAGER_ACTIVATOR_H
#define BLOG_MANAGER_ACTIVATOR_H
#include <ctkPluginActivator.h>
class BlogManager;
class BlogManagerActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "BLOG_MANAGER")
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
private:
BlogManager *m_pBlogManager;
};
#endif // BLOG_MANAGER_ACTIVATOR_H
#include "blog_manager.h"
#include "blog_manager_activator.h"
#include <QtDebug>
void BlogManagerActivator::start(ctkPluginContext* context)
{
m_pBlogManager = new BlogManager(context);
Blog blog;
blog.title = "CTK Event Admin";
blog.content = "This is a simple blog";
blog.author = "wangjichuan";
m_pBlogManager->publishBlog(blog);
}
void BlogManagerActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
delete m_pBlogManager;
}
发送类[发布者]:BlogManager
#ifndef BLOG_MANAGER_H
#define BLOG_MANAGER_H
#include <ctkPluginContext.h>
typedef struct Blog_Info {
QString title;
QString author;
QString content;
} Blog;
// 事件发布者
class BlogManager
{
public:
BlogManager(ctkPluginContext* context);
// 发布事件
void publishBlog(const Blog& blog);
private:
ctkPluginContext* m_pContext;
};
#endif // BLOG_MANAGER_H
#include "blog_manager.h"
#include <service/event/ctkEventAdmin.h>
#include <QtDebug>
BlogManager::BlogManager(ctkPluginContext* context)
: m_pContext(context)
{
}
// 发布事件
void BlogManager::publishBlog(const Blog& blog)
{
ctkServiceReference ref = m_pContext->getServiceReference<ctkEventAdmin>();
if (ref) {
ctkEventAdmin* eventAdmin = m_pContext->getService<ctkEventAdmin>(ref);
ctkDictionary props;
props["title"] = blog.title;
props["content"] = blog.content;
props["author"] = blog.author;
ctkEvent event("org/commontk/bloggenerator/published", props);
qDebug()<<"====================================================";
qDebug()<<"=== Publisher sends a message ===";
qDebug()<<"props: "<<props;
eventAdmin->sendEvent(event);
}
}
3.3、启用插件
注意;
plugin->start(ctkPlugin::START_TRANSIENT)
会立即启动插件,而plugin->start()
不一定会立即启动插件
修改main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"
#include <QDebug>
#include "../HelloCTK/HelloService.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("CTK_PluginFramework");//给框架创建名称,Linux下没有会报错
// 获取插件所在位置
// 在插件的搜索路径列表中添加一条路径
ctkPluginFrameworkLauncher::addSearchPath("../CTK/lib/ctk-0.1/plugins");
ctkPluginFrameworkLauncher::start("org.commontk.eventadmin");
ctkPluginFrameworkFactory frameworkFactory;
QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework();
// 初始化并启动插件框架
try {
framework->init();
framework->start();
qDebug() << "======================================";
qDebug() << "CTK plugin framework start...";
qDebug() << "======================================";
} catch (const ctkPluginException &e) {
qDebug() << "CTK plugin framework init err: " << e.what();
return -1;
}
//---------------------------------------------------------------------------------------------------------------------------------------
// 获取插件服务的contex
ctkPluginContext* pluginContext = framework->getPluginContext();
try {
// 安装插件
QString HelloCTK_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/HelloCTK/bin/plugins/HelloCTK.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(HelloCTK_dir));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
// 获取服务引用
ctkServiceReference reference = pluginContext->getServiceReference<HelloService>();
if (reference) {
// 获取指定 ctkServiceReference 引用的服务对象
//HelloService* service = qobject_cast<HelloService *>(pluginContext->getService(reference));
HelloService* service = pluginContext->getService<HelloService>(reference);
if (service != Q_NULLPTR) {
// 调用服务
service->sayHello();
}
}
//---------------------------------------------------------------------------------------------------------------------------------------
try {
// 安装插件
QString BlogEventHandler_Path = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/BlogEventHandler/bin/plugins/BlogEventHandler.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(BlogEventHandler_Path));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
try {
// 安装插件
QString BlogManager_Path = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/BlogManager/bin/plugins/BlogManager.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(BlogManager_Path));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
// 停止插件
//ctkPluginFrameworkLauncher::stop();
//---------------------------------------------------------------------------------------------------------------------------------------
MainWindow w;
w.show();
return a.exec();
}
四、信号槽通信
原理:将Qt自己的信号与CTK的发送事件绑定、槽与事件订阅绑定;
4.1、新建接收插件
插件结构说明:
- BlogEventHandlerUsingSlot:接收类【订阅者】
- BlogEventHandlerUsingSlotActivator:激活类
工程文件:BlogEventHandlerUsingSlot.pro
QT += core
QT -= gui
TEMPLATE = lib
CONFIG += plugin
TARGET = BlogEventHandlerUsingSlot
DESTDIR = $$OUT_PWD/bin/plugins
include($$PWD/../CTK/CTK_dependency.pri)
HEADERS += \
blog_event_handler_usingSlot.h \
blog_event_handler_usingSlot_activator.h \
SOURCES += \
blog_event_handler_usingSlot.cpp \
blog_event_handler_usingSlot_activator.cpp
RESOURCES += \
qresource.qrc
接收类:BlogEventHandlerUsingSlot
#ifndef BLOGEVENTHANDLERUSINGSLOT_H
#define BLOGEVENTHANDLERUSINGSLOT_H
#include <QObject>
#include <service/event/ctkEvent.h>
// 事件处理程序(或订阅者)
class BlogEventHandlerUsingSlot : public QObject
{
Q_OBJECT
public:
BlogEventHandlerUsingSlot();
public slots:
void slot_BlogPublished(const ctkEvent& event);
};
#endif // BLOGEVENTHANDLERUSINGSLOT_H
#include "blog_event_handler_usingSlot.h"
BlogEventHandlerUsingSlot::BlogEventHandlerUsingSlot()
{
}
void BlogEventHandlerUsingSlot::slot_BlogPublished(const ctkEvent& event)
{
QString title = event.getProperty("title").toString();
QString content = event.getProperty("content").toString();
QString author = event.getProperty("author").toString();
qDebug()<<"====================================================";
qDebug()<<"=== slot received the message ===";
qDebug()<<"topic: "<<event.getTopic();
qDebug()<<"----------- properties -----------";
qDebug()<<"title: "<<title;
qDebug()<<"content: "<<content;
qDebug()<<"author: "<<author;
}
激活类:BlogEventHandlerUsingSlotActivator
#ifndef BLOGEVENTHANDLERACTIVATOR_H
#define BLOGEVENTHANDLERACTIVATOR_H
#include <ctkPluginActivator.h>
class BlogEventHandlerUsingSlot;
class BlogEventHandlerUsingSlotActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "BLOG_EVENT_HANDLER_USING_SLOT")
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
private:
BlogEventHandlerUsingSlot *m_pEventHandler;
};
#endif // BLOGEVENTHANDLERACTIVATOR_H
#include "blog_event_handler_usingSlot.h"
#include "blog_event_handler_usingSlot_activator.h"
#include <service/event/ctkEventConstants.h>
#include <service/event/ctkEventAdmin.h>
#include <QtDebug>
void BlogEventHandlerUsingSlotActivator::start(ctkPluginContext* context)
{
m_pEventHandler = new BlogEventHandlerUsingSlot();
ctkDictionary props;
props[ctkEventConstants::EVENT_TOPIC] = "org/commontk/bloggenerator/published/SignalSlot"; //订阅的主题
ctkServiceReference ref = context->getServiceReference<ctkEventAdmin>();
if (ref) {
ctkEventAdmin* eventAdmin = context->getService<ctkEventAdmin>(ref);
eventAdmin->subscribeSlot(m_pEventHandler, SLOT(slot_BlogPublished(ctkEvent)), props, Qt::DirectConnection);
}
}
void BlogEventHandlerUsingSlotActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
delete m_pEventHandler;
}
4.2、新建发送插件
插件结构说明:
- BlogEventHandlerUsingSignal:接收类【发布者】
- BlogEventHandlerUsingSignalActivator:激活类
工程文件:BlogEventHandlerUsingSignal.pro
QT += core
QT -= gui
TEMPLATE = lib
CONFIG += plugin
TARGET = BlogManagerUsingSignal
DESTDIR = $$OUT_PWD/bin/plugins
include($$PWD/../CTK/CTK_dependency.pri)
HEADERS += \
blog_manager_usingSignal.h \
blog_manager_activator_usingSignal.h
SOURCES += \
blog_manager_usingSignal.cpp \
blog_manager_activator_usingSignal.cpp
RESOURCES += \
qresource.qrc
接收类:BlogEventHandlerUsingSignal
#ifndef BLOG_MANAGER_H
#define BLOG_MANAGER_H
#include <QObject>
#include <ctkPluginContext.h>
#include <service/event/ctkEventAdmin.h>
typedef struct Blog_Info {
QString title;
QString author;
QString content;
} Blog;
// 事件发布者
class BlogManagerUsingSignal : public QObject
{
Q_OBJECT
public:
BlogManagerUsingSignal(ctkPluginContext* context);
// 发布事件
void publishBlog(const Blog& blog);
signals:
void signal_blogPublished(const ctkDictionary&);
private:
ctkPluginContext* m_pContext;
};
#endif // BLOG_MANAGER_H
#include "blog_manager_usingSignal.h"
#include <QtDebug>
BlogManagerUsingSignal::BlogManagerUsingSignal(ctkPluginContext* context)
: m_pContext(context)
{
ctkServiceReference ref = context->getServiceReference<ctkEventAdmin>();
if (ref) {
ctkEventAdmin* eventAdmin = context->getService<ctkEventAdmin>(ref);
// 使用 Qt::DirectConnection 等同于 ctkEventAdmin::sendEvent()
eventAdmin->publishSignal(this, SIGNAL(signal_blogPublished(ctkDictionary)), "org/commontk/bloggenerator/published/SignalSlot", Qt::DirectConnection);
}
}
// 发布事件
void BlogManagerUsingSignal::publishBlog(const Blog& blog)
{
ctkDictionary props;
props["title"] = blog.title;
props["content"] = blog.content;
props["author"] = blog.author;
emit signal_blogPublished(props);
}
激活类:BlogEventHandlerUsingSignalActivator
#ifndef BLOG_MANAGER_ACTIVATOR_H
#define BLOG_MANAGER_ACTIVATOR_H
#include <ctkPluginActivator.h>
class BlogManagerUsingSignal;
class BlogManagerActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "BLOG_MANAGER_USING_SIGNAL")
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
private:
BlogManagerUsingSignal *m_pBlogManager;
};
#endif // BLOG_MANAGER_ACTIVATOR_H
#include "blog_manager_usingSignal.h"
#include "blog_manager_activator_usingSignal.h"
void BlogManagerActivator::start(ctkPluginContext* context)
{
m_pBlogManager = new BlogManagerUsingSignal(context);
Blog blog;
blog.title = "CTK Event Admin";
blog.content = "This is a simple blog";
blog.author = "wangjichuan";
m_pBlogManager->publishBlog(blog);
}
void BlogManagerActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
delete m_pBlogManager;
}
4.3、启用插件
注意;
plugin->start(ctkPlugin::START_TRANSIENT)
会立即启动插件,而plugin->start()
不一定会立即启动插件
修改main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"
#include <QDebug>
#include "../HelloCTK/HelloService.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("CTK_PluginFramework");//给框架创建名称,Linux下没有会报错
// 获取插件所在位置
// 在插件的搜索路径列表中添加一条路径
ctkPluginFrameworkLauncher::addSearchPath("../CTK/lib/ctk-0.1/plugins");
ctkPluginFrameworkLauncher::start("org.commontk.eventadmin");
ctkPluginFrameworkFactory frameworkFactory;
QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework();
// 初始化并启动插件框架
try {
framework->init();
framework->start();
qDebug() << "======================================";
qDebug() << "CTK plugin framework start...";
qDebug() << "======================================";
} catch (const ctkPluginException &e) {
qDebug() << "CTK plugin framework init err: " << e.what();
return -1;
}
//---------------------------------------------------------------------------------------------------------------------------------------
// 获取插件服务的contex
ctkPluginContext* pluginContext = framework->getPluginContext();
try {
// 安装插件
QString HelloCTK_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/HelloCTK/bin/plugins/HelloCTK.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(HelloCTK_dir));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
// 获取服务引用
ctkServiceReference reference = pluginContext->getServiceReference<HelloService>();
if (reference) {
// 获取指定 ctkServiceReference 引用的服务对象
//HelloService* service = qobject_cast<HelloService *>(pluginContext->getService(reference));
HelloService* service = pluginContext->getService<HelloService>(reference);
if (service != Q_NULLPTR) {
// 调用服务
service->sayHello();
}
}
//---------------------------------------------------------------------------------------------------------------------------------------
//注册事件调用-测试插件
try {
// 安装插件
QString BlogEventHandler_Path = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/BlogEventHandler/bin/plugins/BlogEventHandler.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(BlogEventHandler_Path));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
try {
// 安装插件
QString BlogManager_Path = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/BlogManager/bin/plugins/BlogManager.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(BlogManager_Path));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
//---------------------------------------------------------------------------------------------------------------------------------------
//信号槽通信-测试插件
try {
// 安装插件
QString BlogEventHandlerUsingSlot_Path = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/BlogEventHandlerUsingSlot/bin/plugins/BlogEventHandlerUsingSlot.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(BlogEventHandlerUsingSlot_Path));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
try {
// 安装插件
QString BlogManagerUsingSignal_Path = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/BlogManagerUsingSignal/bin/plugins/BlogManagerUsingSignal.dll";
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(BlogManagerUsingSignal_Path));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
// 停止插件
//ctkPluginFrameworkLauncher::stop();
//---------------------------------------------------------------------------------------------------------------------------------------
MainWindow w;
w.show();
return a.exec();
}
五、类通信和信号槽通信的区别
1、通过event事件通信,是直接调用CTK的接口,把数据发送到CTK框架;通过信号槽方式,会先在Qt的信号槽机制中转一次,再发送到CTK框架。故效率上来讲,event方式性能高于信号槽方式。
2、两种方式发送数据到CTK框架,这个数据包含:主题+属性。主题就是topic,属性就是ctkDictionary。 一定要注意signal方式的信号定义,参数不能是自定义的,一定要是ctkDictionary,不然会报信号槽参数异常错误。
3、两种方式可以混用,如发送event事件,再通过槽去接收;发送signal事件,再通过event是接收。
4、同步:sendEvent、Qt::DirectConnection;异步:postEvent、Qt::QueuedConnection
这里的同步是指:发送事件之后,订阅了这个主题的数据便会处理数据【handleEvent、slot】,处理的过程是在发送者的线程完成的。可以理解为在发送了某个事件之后,会立即执行所有订阅此事件的回调函数。
异步:发送事件之后,发送者便会返回不管,订阅了此事件的所有插件会根据自己的消息循环,轮到了处理事件后才会去处理。不过如果长时间没处理,CTK也有自己的超时机制。如果事件处理程序花费的时间比配置的超时时间长,那么就会被列入黑名单。一旦处理程序被列入黑名单,它就不会再被发送任何事件。
六、插件依赖
插件加载时一般根据首字母大小自动加载,所以在插件启用时,某个插件还没有被调用,所以发送事件没有接收方,这样就要考虑到插件依赖关系,在MANIFEST.MF中添加依赖:
Plugin-SymbolicName:Plugin-xxx-1
Plugin-Version:1.0.0
Require-Plugin:Plugin-xxx-2; plugin-version="[1.0,2.0)"; resolution:="mandatory"
- Plugin-xxx-2:为需要依赖的插件名【就是另一个插件在MANIFEST.MF里的Plugin-SymbolicName】;
- [1.0,2.0):为Plugin-xxx-2的版本,这里是左闭右开区间,默认是1.0;
- resolution:有两个选择,optional、mandatory。前者是弱依赖,就算依赖的插件没有,当前插件也能正常使用,后者是强依赖,如果没有依赖的插件,当前插件就不能被start;
这样就向框架申明了,该插件加载时需要先加载Plugin-xxx-2插件,所有用户插件都应该有这样一份申明。
七、获取元数据
//获取元数据
......
QHash<QString, QString> headers = plugin->getHeaders();
ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));
QString name = headers.value(ctkPluginConstants::PLUGIN_SYMBOLICNAME);
QString number = headers.value("Plugin-Number");
qDebug()<<"version: "<<version;
qDebug()<<"name: "<<name;
qDebug()<<"number: "<<number;