首页 > 其他分享 >CTK框架(九):插件间通信

CTK框架(九):插件间通信

时间:2024-09-12 12:21:11浏览次数:14  
标签:发送 插件 通信 间通信 事件 context include CTK

目录

1.概述

2.主要接口和方法

3.通信方式

4.实现步骤

5.实现示例

5.1.类通信

5.2.信号槽通信

6.类通信和信号槽通信的区别

7.注意事项


1.概述

        在CTK Plugin Framework中,插件间的通信主要通过EventAdmin服务来完成。EventAdmin是一种基于发布/订阅的通信方式,一个插件可以订阅某一主题的事件,而另一个插件则可以发布与该主题相关的事件,从而实现通信。
        CTK框架中的事件监听,其实就是观察者模式,流程大概如下:
                1)接收者注册监听事件(接收方想监听xxx信息)
                2)发送者发送事件(发送方发送xxx信息)
                3)接收者接收到事件并响应(接收方收到xxx事件后的动作)
        相比调用插件接口,监听事件插件间依赖关系更弱,不用指定事件的接收方和发送方是谁。

2.主要接口和方法

1.通信主要用到了​​ctkEventAdmin​​结构体,主要定义了如下接口:

  • postEvent:以异步方式发送事件。
  • sendEvent:以同步方式发送事件。
  • publishSignal:通过信号与槽的方式发送事件。
  • unpublishSignal:取消发送事件。
  • subscribeSlot:通过信号与槽的方式订阅事件,并返回订阅的ID。
  • unsubscribeSlot:取消订阅事件。
  • updateProperties:更新某个订阅ID的主题。

2.通信是数据:​​ctkDictionary​

CTK插件间通信的数据主要通过ctkDictionary传递,它实际上是一个hash表(在Qt中通常使用QHash<QString, QVariant>实现),用于存储事件的属性。

3.通信方式

1. 类通信

        类通信的原理是直接将信息使用CTK的eventAdmin接口sendpost出去。发送插件需要创建事件对象,并设置事件的属性(如主题、数据等),然后通过EventAdmin服务发送事件。接收插件则通过订阅相应主题的事件来接收信息,并在接收到事件时执行相应的处理函数。

2. 信号与槽通信

        除了类通信外,CTK还支持通过Qt的信号与槽机制进行插件间通信。发送插件可以发射一个信号,该信号携带需要传递的信息;接收插件则连接该信号到一个槽函数上,当信号被发射时,槽函数会被调用,从而实现信息的传递和处理。

4.实现步骤

以发布博客为例,实现CTK插件间通信的大致步骤如下:

  1. 编译EventAdmin库:确保eventadmin.dll(或其他平台对应的库文件)已经编译成功。
  2. 创建发送插件
    • 新建一个插件项目,编写发送类(如BlogManager),在该类中实现发布事件的方法(如publishBlog)。
    • 在发送类的构造函数中,通过ctkPluginContext获取EventAdmin服务的引用,并保存为成员变量。
    • 在发布事件的方法中,创建ctkEvent对象,设置事件的属性和数据,然后通过EventAdmin服务的sendEventpostEvent方法发送事件。
  3. 创建接收插件
    • 新建一个插件项目,编写接收类(如BlogEventHandler),实现ctkEventHandler接口中的handleEvent方法。
    • 在接收类的激活类中,通过ctkPluginContext注册服务,并订阅相应主题的事件。
    • handleEvent方法中编写处理事件的逻辑。
  4. 启用插件
    • 在主程序中加载并启动发送插件和接收插件。
    • 发送插件发布事件后,接收插件将接收到该事件,并执行相应的处理逻辑。

5.实现示例

5.1.类通信

代码结构:

插件结构说明:

cn.qtio.publisher:发送【发布者】
cn.qtio.subscriber:接收【订阅类】

发送【发布者】

publisheractivator.h

#ifndef TESTPLUGINACTIVATOR_H
#define TESTPLUGINACTIVATOR_H

#include <QObject>
#include <ctkPluginActivator.h>

class PublisherActivator : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_INTERFACES(ctkPluginActivator)
    Q_PLUGIN_METADATA(IID "Publisher")

public:
    void start(ctkPluginContext* context) Q_DECL_OVERRIDE;
    void stop(ctkPluginContext* context) Q_DECL_OVERRIDE;
};

#endif // TESTPLUGINACTIVATOR_H

publisheractivator.cpp

#include "publisheractivator.h"

#include <QDebug>
#include <QThread>
#include <service/event/ctkEventAdmin.h>

void PublisherActivator::start(ctkPluginContext *context)
{
    ctkServiceReference ref = context->getServiceReference<ctkEventAdmin>();
    ctkEventAdmin *eventAdmin = qobject_cast<ctkEventAdmin*>(context->getService(ref));
    ctkProperties props;
    props.insert("type", "消息类型");
    ctkEvent event("cn/qtio/eventAdmin/subscriber/handleEvent", props);
    if(eventAdmin){
        //sendEvent:同步通信
        eventAdmin->sendEvent(event);
    }
}

void PublisherActivator::stop(ctkPluginContext *context)
{
    Q_UNUSED(context)
}
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
Q_EXPORT_PLUGIN2(Publisher, PublisherActivator)
#endif

接收【订阅类】

subscriberactivator.h

#ifndef SUBSCRIBERACTIVATOR_H
#define SUBSCRIBERACTIVATOR_H

#include <QObject>
#include <ctkPluginActivator.h>
#include <service/event/ctkEventAdmin.h>
#include <service/event/ctkEventHandler.h>

class SubscriberActivator :
        public QObject,
        public ctkPluginActivator,
        public ctkEventHandler
{
    Q_OBJECT
    Q_INTERFACES(ctkPluginActivator)
    Q_INTERFACES(ctkEventHandler)
    Q_PLUGIN_METADATA(IID "Subscriber")

public:
    void start(ctkPluginContext* context) Q_DECL_OVERRIDE;
    void stop(ctkPluginContext* context) Q_DECL_OVERRIDE;

private:
    void handleEvent(const ctkEvent &event) Q_DECL_OVERRIDE;

private:
    ctkEventAdmin *m_eventAdmin;
};

#endif // SUBSCRIBERACTIVATOR_H

subscriberactivator.cpp

#include "subscriberactivator.h"

#include <QDebug>
#include <service/event/ctkEventConstants.h>

void SubscriberActivator::start(ctkPluginContext* context)
{
	//事件管理服务
	ctkServiceReference eventAdminRef = context->getServiceReference<ctkEventAdmin>();
	m_eventAdmin = qobject_cast<ctkEventAdmin*>(context->getService(eventAdminRef));
	if (!m_eventAdmin) {
		qDebug() << "事件管理服务获取失败!";
	}

	//消息订阅
	ctkDictionary props;
	props.insert(ctkEventConstants::EVENT_TOPIC, "cn/qtio/eventAdmin/subscriber/handleEvent");
	context->registerService<ctkEventHandler>(this, props);
}

void SubscriberActivator::stop(ctkPluginContext* context)
{
	Q_UNUSED(context)
}

void SubscriberActivator::handleEvent(const ctkEvent& event)
{
	//查看消息包所有信息
	foreach(QString propertyName, event.getPropertyNames()) {
		qDebug() << "SubscriberActivator key:"
			<< propertyName
			<< "value:"
			<< event.getProperty(propertyName);
	}
}
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
Q_EXPORT_PLUGIN2(Subscriber, SubscriberActivator)
#endif

5.2.信号槽通信

信号槽通信和Qt的信号槽绑定类似,就不在这里赘述了。

6.类通信和信号槽通信的区别

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也有自己的超时机制。如果事件处理程序花费的时间比配置的超时时间长,那么就会被列入黑名单。一旦处理程序被列入黑名单,它就不会再被发送任何事件。

5) handleEvent里是线程池里运行的,可以通过打印线程id测试出。

7.注意事项

  • 在进行插件间通信时,需要确保所有相关的库文件都已经正确编译并链接到项目中。
  • 订阅事件时,可以指定事件过滤器来过滤不需要处理的事件。
  • 发送事件时,需要确保事件的主题和数据已经正确设置,以便接收插件能够正确解析和处理。

标签:发送,插件,通信,间通信,事件,context,include,CTK
From: https://blog.csdn.net/haokan123456789/article/details/142127553

相关文章

  • 强烈推荐PyCharm中常用的插件,增强效率,赶快收藏起来!!!
    一、pycharm插件安装方法和路径在上篇文章中介绍到的汉化pycharm的方法中就是通过汉化插件完成的,具体操作如下:打开设置 > 插件,在右侧的文本框中输入想要查看的插件名称,在下方就会罗列出已经安装的相关的插件。二、好用的几个插件1、汉化插件ChineseLanguagePack直......
  • vite如何打包vue3插件为JSSDK
    安装vitenpmcreatevite@latest你还可以通过附加的命令行选项直接指定项目名称和你想要使用的模板。例如,要构建一个Vite+Vue+ts项目,运行:#npm7+,需要添加额外的--:npmcreatevite@latestmy-vue-app----templatevue-ts查看create-vite以获取每个模板的更多细......
  • 两款插件让浏览器起飞!
    今天给大家分享两款最近在用的实用小插件~1.猫抓一个用来帮我们嗅探下载网络上各种媒体资源的小插件 当我们浏览的网站有媒体文件时,插件就会自动嗅探视频资源。这时我们只需要点开插件页面,直接下载就好了。不单单是普通的媒体文件,遇见M3U8这种分段式格式,插件还会自动为......
  • dotnet 使用 dnlib 检测插件程序集的 API 兼容性
    本文将和大家介绍在开发dotnet的插件时,如何通过dnlib库检测当前的插件是否由于主应用程序的版本差异导致存在API兼容性问题众所周知,在开发插件的过程中,插件与主程序之间的兼容性问题将持续是一个令开发者烦恼的事情。举个例子,我开发的插件是面向1.0版本的主程序开发了,我......
  • verilog vscode 与AI 插件
    Verilog轻量化开发环境背景笔者常用的开发环境VIAVDO,体积巨大,自带编辑器除了linting能用,编辑器几乎不能用,仿真界面很友好,但是速度比较慢。SublimeText,非常好用的编辑器,各种插件使用verilog非常方便,可以自动补全、生成调用、linting等;VSCODE,SublimeText有的插件,VSC......
  • HTB-Oopsie(越权漏洞,suid提权,js接口查询插件)
    前言各位师傅大家好,我是qmx_07,今天给大家讲解Oopsie靶机渗透过程信息搜集服务器开放了22SSH端口和HTTP80端口FindSomething插件介绍:帮助寻找网站的js接口,辅助渗透通过js接口查找,发现目录/cdn-cgi/login登录接口通过游客模式登录越权登录访问uploads文件......
  • 如何在Java中实现应用的动态扩展:基于热插拔与插件机制的实现
    如何在Java中实现应用的动态扩展:基于热插拔与插件机制的实现大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代应用开发中,为了应对不断变化的需求和快速迭代的要求,应用的动态扩展能力变得尤为重要。实现动态扩展的关键技术包括热插拔和插件机制。......
  • Wordpress 知名插件漏洞致百万网站面临接管风险
        流行的 WordPressLiteSpeedCache 插件中存在一个漏洞,可能允许攻击者检索用户cookie并可能接管网站。    该问题被跟踪为CVE-2024-44000,之所以存在,是因为该插件在用户登录请求后会在调试日志文件中包含set-cookie的HTTP响应标头。    ......
  • HtmlWebpackPlugin插件和HtmlWebpackInlineSourcePlugin插件的使用
    一、HtmlWebpackPlugin1.作用自动创建HTML自动创建HTML:在构建过程中自动生成一个HTML5文件,该文件可以包含所有webpack打包过程中生成的bundles。这意味着你不需要手动创建HTML文件,插件会为你处理这一切。自动注入资源:自动将打包生成的JavaScript、CSS等文件注入到生成的HTML文......
  • ob插件-TP模板-配置CMD
    1.简介EnableUserSystemCommandFunctions:打开此功能Shellbinarylocation:输入C:\\Windows\\System32\\cmd.exe添加脚本:脚本名称,脚本代码调用脚本:<%tp.user.脚本名称()%>2.更新3.pyt1"E:/ProgramFiles/Python310/python.exe""E:\Clouds\BaiduSyncdisk......