首页 > 其他分享 >CTK Plugin Framework插件框架学习--插件通信【事件监听】

CTK Plugin Framework插件框架学习--插件通信【事件监听】

时间:2023-01-28 17:40:23浏览次数:48  
标签:插件 Plugin -- plugin blog qDebug include CTK


文章目录

  • ​​一、前言​​
  • ​​二、事件​​
  • ​​三、类通信​​
  • ​​3.1、新建接收插件​​
  • ​​3.2、新建发送插件​​
  • ​​3.3、启用插件​​
  • ​​四、信号槽通信​​
  • ​​4.1、新建接收插件​​
  • ​​4.2、新建发送插件​​
  • ​​4.3、启用插件​​
  • ​​五、类通信和信号槽通信的区别​​
  • ​​六、插件依赖​​
  • ​​七、获取元数据​​

一、前言

CTK框架中的事件监听,其实就是观察者模式,流程大概如下:

  • 接收者注册监听事件(接收方想监听xxx信息)
  • 发送者发送事件(发送方发送xxx信息)
  • 接收者接收到事件并响应(接收方收到xxx事件后的动作)

相比调用插件接口监听事件插件间依赖关系更弱,不用指定事件的接收方和发送方是谁


要使用CTK框架的事件服务,在编译CTK库是需要编译出支持事件监听的动态库:​​liborg_commontk_eventadmin.dll​

在编译输出的CTK文件夹中可以找到

CTK Plugin Framework插件框架学习--插件通信【事件监听】_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、新建接收插件

CTK Plugin Framework插件框架学习--插件通信【事件监听】_ctk_02


插件结构说明:

  • 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、新建发送插件

CTK Plugin Framework插件框架学习--插件通信【事件监听】_#define_03


插件结构说明:

  • 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();
}

CTK Plugin Framework插件框架学习--插件通信【事件监听】_#define_04


四、信号槽通信

原理:将Qt自己的信号与CTK的发送事件绑定、槽与事件订阅绑定;

4.1、新建接收插件

CTK Plugin Framework插件框架学习--插件通信【事件监听】_qt_05

插件结构说明:

  • 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、新建发送插件

CTK Plugin Framework插件框架学习--插件通信【事件监听】_ctk_06


插件结构说明:

  • 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();
}

CTK Plugin Framework插件框架学习--插件通信【事件监听】_#define_07


五、类通信和信号槽通信的区别

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;


标签:插件,Plugin,--,plugin,blog,qDebug,include,CTK
From: https://blog.51cto.com/wangjichuan/6025020

相关文章

  • 【openGauss实战3】基本概念及语法
    ......
  • 将IoTDB注册为Windows服务
    昨天写的文章《​​WindowsServer上部署IoTDB集群​​》,Windows下的IoTDB是控制台程序,打开窗口后,很容易被别人给关掉,因此考虑做成Windows服务,nssm正是解决该问题的利器。1.......
  • Huaweicloud for 开发语言
    连续参加过几次华为云第三方满意度调研,我对华为云对开发者最不满意的一点就是对Top10常用语言的支持上很差,特别是对.NET的支持。经过连续多年(至少有3年了)的不断反馈,今天很......
  • Apache IoTDB C# SDK 介绍
    最近今天写了IoTDB的三篇相关文章,完成了安装部署和客户端连接:​​WindowsServer上部署IoTDB集群​​​​DBeaver连接IoTDBDriver​​​​将IoTDB注册为Windows服务​​Ts......
  • Apache IoTDB C# SDK 介绍
    最近今天写了IoTDB的三篇相关文章,完成了安装部署和客户端连接:​​WindowsServer上部署IoTDB集群​​​​DBeaver连接IoTDBDriver​​​​将IoTDB注册为Windows服务​​Ts......
  • 使用labelimg标注数据集
    labelimg安装在cmd命令行中运行如下命令:pipinstalllabelimg-ihttps://pypi.tuna.tsinghua.edu.cn/simple数据准备新建一个名为VOC2007的文件夹(注意路径中不要带有中文),在......
  • unknow or unsupported command install
    错误原因:今天使用pip下载labelimg时,出现了“unknoworunsupportedcommandinstall”的错误,这是由于电脑有多个pip文件路径所导致。如图,在cmd命令行中输入“wherepip”命......
  • 清醒时刻记7
    就跟“胖子”一样,我也比较喜欢网络游戏,不过最初我还是不花钱玩的,随着了解到在各种游戏里花大笔钱的人,我了解到了这么二八定律里靠近“二”的人是对金钱的挥霍是这么无度......
  • 网站如何进行整站优化?
    如果要做优化或者选择性优化,一定要区分关键词优化和全站优化,米贸搜整理如下,希望可以帮助到你:一、全站优化的概念:1.一般认为,全站点优化是指通过SEO技术,使其网站成为搜索引擎......
  • 清醒时刻记6
    “网络红人”的摇滚演唱会在我脑海中继续上演。我曾经也仰慕过某些歌手,直到他们传出了各种绯闻,当时我的一部分“信仰”崩塌了,但实际上追星这件“单相思”的事情,才是当你关......