CTK插件框架学习-插件注册调用(03)

CTK插件框架学习-新建插件(02)icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/136923735

一、CTK插件组成

  • 接口类:对外暴露的接口,供其他插件调用
  • 实现类:实现接口内的方法
  • 激活类:负责将插件注册到CTK框架中

二、接口、插件、服务三者关系

1、一对一

一个接口类由一个实现类实现,对应一个插件,注册一个服务

参见

CTK插件框架学习-新建插件(02)icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/136923735

2、多对一(多态)

多个接口类由一个实现类实现,对应一个插件,注册多个服务
 

  • 接口类1
    #pragma once
    #include <QObject>class IService1
    {
    public:virtual ~IService1() {}virtual void printf1() = 0;
    };//此宏将当前这个接口类声明为接口,后面的字符串是这个接口的唯一标识。
    Q_DECLARE_INTERFACE(IService1, "zr.IService1")
    

  • 接口类2
    #pragma once
    #pragma once
    #include <QObject>class IService2
    {
    public:virtual ~IService2() {}virtual void printf2() = 0;
    };//此宏将当前这个接口类声明为接口,后面的字符串是这个接口的唯一标识。
    Q_DECLARE_INTERFACE(IService2, "zr.IService2")
    

  • 实现类
    
    ==============================TestPlugin2.ch==================================
    #pragma once#include "IService1.h"
    #include "IService2.h"class ctkPluginContext;
    class TestPlugin2 : public QObject, public IService1, public IService2
    {Q_OBJECT//当一个类继承这个接口类,表明需要实现这个接口类Q_INTERFACES(IService1)Q_INTERFACES(IService2)public:TestPlugin2(ctkPluginContext* contex);virtual void printf1();virtual void printf2();
    };==============================TestPlugin2.cpp=================================#include "TestPlugin2.h"
    #include <qdebug.h>TestPlugin2::TestPlugin2(ctkPluginContext* contex)
    {
    }void TestPlugin2::printf1()
    {qDebug() << "IService1 printf1";
    }void TestPlugin2::printf2()
    {qDebug() << "IService2 printf2";
    }
    

  • 插件测试
#include "CTKPlugin.h"
#include <QtWidgets/QApplication>#include <iostream>
#include <QStyleFactory>
#include <QDir>
#include <QDirIterator>
#include <QDebug>
#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"
#include "../TestPlugin2/IService1.h"
#include "../TestPlugin2/IService2.h"
/*
* 1、注意:Plugin-SymbolicName要满足这里的前缀是:TARGET/META-INF格式。TARGET的名字最好和工程名一致,不然可能出现device not open错误。
* 2、如果CTK初始化、插件安装启动等是在一个类中,则与CTK相关的变量应定义成类的属性,不能是成员变量,否则获取不到服务
* 3、CTK插件组成:
(1)每个插件有自己的注册器Activator,继承自QObject和ctkPluginActivator的一个类,并实现ctkPluginActivator的start、stop函数
(2)每个插件必须有一个资源文件,名称一般与插件名称一致,前缀必须为TARGET/META-INF,例:插件名称/META-INF
(3)每个插件必须添加一个元数据文件,名字必须为MANIFEST.MF,并添加到资源文件中
* 4、QSharedPointer framework这个对象既可以作为对象也可以作为对象指针,但要作为插件框架使用必须要用指针方法调用
* 5、生成的插件名(TARGET)不要有下划线,因为CTK会默认将插件名中的下划线替换成点号,最后导致找不到插件 
*/
int main(int argc, char *argv[])
{QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QApplication a(argc, argv);a.setApplicationName("ctktest");//Linux下没有名称报错QString path = QCoreApplication::applicationDirPath();// 启动插件工厂ctkPluginFrameworkFactory* ctkFrameWorkFactory = new ctkPluginFrameworkFactory;QSharedPointer<ctkPluginFramework> framework = ctkFrameWorkFactory->getFramework();try {framework->init();framework->start();}catch (const ctkPluginException& e){std::cout << "framework init fail" << std::endl;}QSharedPointer<ctkPlugin> plugin;QDirIterator iter(path + "/plugins/", { "*.dll" }, QDir::NoFilter, QDirIterator::Subdirectories);while (iter.hasNext()) {//qDebug() << iter.next();QString dllPath = iter.next();QUrl url = QUrl::fromLocalFile(dllPath);try{plugin = framework->getPluginContext()->installPlugin(url);//获取MANIFEST.MF中的数据QHash<QString, QString> headers = plugin->getHeaders();ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));QString name = headers.value(ctkPluginConstants::PLUGIN_NAME);}catch (ctkPluginException e) {std::cout << e.message().toStdString() << e.getType() << std::endl;}try {plugin->start(ctkPlugin::START_TRANSIENT);//表示立即启用插件,不设置参数的话加载后也不会立即打印输出}catch (ctkPluginException e) {std::cout << e.message().toStdString() << e.getType() << std::endl;}}//2、测试插件(多个接口一个实现一个服务一个插件)IService1* service1 = NULL;ctkServiceReference ref2 = framework->getPluginContext()->getServiceReference<IService1>();if (ref2){service1 = framework->getPluginContext()->getService<IService1>(ref2);}if (service1){service1->printf1();}IService2* service2 = NULL;ctkServiceReference ref3 = framework->getPluginContext()->getServiceReference<IService2>();if (ref3){service2 = framework->getPluginContext()->getService<IService2>(ref3);}if (service2){service2->printf2();}//ctkPlugin::State sta = plugin->getState();//ctkPluginFrameworkLauncher::stop();//plugin->stop(); //plugin->uninstall();//sta = plugin->getState();CTKPlugin c;c.show();return a.exec();
}

3、一对多

一个接口类由多个实现类实现,对应多个插件,注册一个服务

/*
* 1、通过ctkPluginConstants::SERVICE_RANKING和ctkPluginConstants::SERVICE_ID来调用不同的插件
* 2、插件不同但是在同一个dll内
* 3、插件获取策略:
*		插件容器中id最小的服务,id为插件注册时的SERVICE_RANKING属性
*		插件容器内id相同的情况,返回pid最小的服务
* 4、插件每次调用其他插件时只会生成一个实例,不会因多次调用产生多个服务实例
*/

  • 接口类
    #pragma once
    #include <QObject>/*
    * 1、通过ctkPluginConstants::SERVICE_RANKING和ctkPluginConstants::SERVICE_ID来调用不同的插件
    * 2、插件不同但是在同一个dll内
    * 3、插件获取策略:
    *		插件容器中id最小的服务,id为插件注册时的SERVICE_RANKING属性
    *		插件容器内id相同的情况,返回pid最小的服务
    * 4、插件每次调用其他插件时只会生成一个实例,不会因多次调用产生多个服务实例
    */
    class IService
    {
    public:virtual ~IService() {}virtual void printf() = 0;
    };//此宏将当前这个接口类声明为接口,后面的字符串是这个接口的唯一标识。
    Q_DECLARE_INTERFACE(IService, "zr.IService")
    

  • 实现类1
    #pragma once#include "IService.h"
    #include <QObject>class ctkPluginContext;
    class ServiceImp1 :public QObject, public IService
    {Q_OBJECT//当一个类继承这个接口类,表明需要实现这个接口类Q_INTERFACES(IService)public:ServiceImp1(ctkPluginContext* contex);void printf();};

  • 实现类2
    #pragma once
    #include "IService.h"
    #include <QObject>class ctkPluginContext;
    class ServiceImp2 :public QObject, public IService
    {Q_OBJECT//当一个类继承这个接口类,表明需要实现这个接口类Q_INTERFACES(IService)public:ServiceImp2(ctkPluginContext* contex);void printf();
    };

  • 服务类
    =========================PluginActivator.h=============================
    #pragma once
    #include <qobject.h>
    #include "ctkPluginActivator.h"
    #include "ctkPluginContext.h"
    #include "ServiceImp1.h"
    #include "ServiceImp2.h"class PluginActivator :public QObject, ctkPluginActivator
    {Q_OBJECTQ_INTERFACES(ctkPluginActivator)//向Qt的插件框架声明,希望将xxx插件放入到框架中。Q_PLUGIN_METADATA(IID "TestPlugin3")//向qt框架申明插件(qt5版本)public:PluginActivator();void start(ctkPluginContext *context);void stop(ctkPluginContext *context);
    private:QScopedPointer<ServiceImp1> m_serviceImp1;//智能指针,自动析构回收QScopedPointer<ServiceImp2> m_serviceImp2;//智能指针,自动析构回收
    };=========================PluginActivator.cpp=============================#include "PluginActivator.h"
    #include <QDebug>
    #include "ctkPluginContext.h"
    #include "ctkPluginFrameworkLauncher.h"PluginActivator::PluginActivator()
    {}
    void PluginActivator::start(ctkPluginContext *context)
    {qDebug() << "my plugin3 start";m_serviceImp1.reset(new ServiceImp1(context));m_serviceImp2.reset(new ServiceImp2(context));ctkDictionary dic1;dic1.insert(ctkPluginConstants::SERVICE_RANKING, 1);dic1.insert("name", "ServiceImp1");context->registerService<IService>(m_serviceImp1.get(), dic1);ctkDictionary dic2;dic2.insert(ctkPluginConstants::SERVICE_RANKING, 2);dic2.insert("name", "ServiceImp2");context->registerService<IService>(m_serviceImp2.get(), dic2);}void PluginActivator::stop(ctkPluginContext *context)
    {qDebug() << "my plugin3 stop";Q_UNUSED(context)// Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用ctkServiceReference  ref1 = context->getServiceReference<IService>();context->ungetService(ref1);m_serviceImp1.reset(NULL);m_serviceImp2.reset(NULL);ctkPlugin::State sta = context->getPlugin()->getState();}

  • 插件测试
    #include "CTKPlugin.h"
    #include <QtWidgets/QApplication>#include <iostream>
    #include <QStyleFactory>
    #include <QDir>
    #include <QDirIterator>
    #include <QDebug>
    #include "ctkPluginFrameworkFactory.h"
    #include "ctkPluginFramework.h"
    #include "ctkPluginException.h"
    #include "ctkPluginContext.h"
    #include "ctkPluginFrameworkLauncher.h"
    #include "../TestPlugin3/IService.h"
    /*
    * 1、注意:Plugin-SymbolicName要满足这里的前缀是:TARGET/META-INF格式。TARGET的名字最好和工程名一致,不然可能出现device not open错误。
    * 2、如果CTK初始化、插件安装启动等是在一个类中,则与CTK相关的变量应定义成类的属性,不能是成员变量,否则获取不到服务
    * 53、CTK插件组成:
    (1)每个插件有自己的注册器Activator,继承自QObject和ctkPluginActivator的一个类,并实现ctkPluginActivator的start、stop函数
    (2)每个插件必须有一个资源文件,名称一般与插件名称一致,前缀必须为TARGET/META-INF,例:插件名称/META-INF
    (3)每个插件必须添加一个元数据文件,名字必须为MANIFEST.MF,并添加到资源文件中
    * 4、QSharedPointer framework这个对象既可以作为对象也可以作为对象指针,但要作为插件框架使用必须要用指针方法调用
    * 5、生成的插件名(TARGET)不要有下划线,因为CTK会默认将插件名中的下划线替换成点号,最后导致找不到插件 
    */
    int main(int argc, char *argv[])
    {QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QApplication a(argc, argv);a.setApplicationName("ctktest");//Linux下没有名称报错QString path = QCoreApplication::applicationDirPath();// 启动插件工厂ctkPluginFrameworkFactory* ctkFrameWorkFactory = new ctkPluginFrameworkFactory;QSharedPointer<ctkPluginFramework> framework = ctkFrameWorkFactory->getFramework();try {framework->init();framework->start();}catch (const ctkPluginException& e){std::cout << "framework init fail" << std::endl;}//QString dir = QCoreApplication::applicationDirPath();//dir += "/plugins/TestPlugin.dll";//QUrl url = QUrl::fromLocalFile(dir);QSharedPointer<ctkPlugin> plugin;QDirIterator iter(path + "/plugins/", { "*.dll" }, QDir::NoFilter, QDirIterator::Subdirectories);while (iter.hasNext()) {//qDebug() << iter.next();QString dllPath = iter.next();QUrl url = QUrl::fromLocalFile(dllPath);try{plugin = framework->getPluginContext()->installPlugin(url);//获取MANIFEST.MF中的数据QHash<QString, QString> headers = plugin->getHeaders();ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));QString name = headers.value(ctkPluginConstants::PLUGIN_NAME);}catch (ctkPluginException e) {std::cout << e.message().toStdString() << e.getType() << std::endl;}try {plugin->start(ctkPlugin::START_TRANSIENT);//表示立即启用插件,不设置参数的话加载后也不会立即打印输出}catch (ctkPluginException e) {std::cout << e.message().toStdString() << e.getType() << std::endl;}}//3、测试插件(一个接口多个实现一个服务多个插件<一个dll内>)//3.1获取所有服务QList<ctkServiceReference> ref3List = framework->getPluginContext()->getServiceReferences<IService>();foreach (ctkServiceReference var, ref3List){if (var){qDebug() << "service name:" << var.getProperty("name").toString();qDebug() << "service ranking:" << var.getProperty(ctkPluginConstants::SERVICE_RANKING).toLongLong();qDebug() << "service id:" << var.getProperty(ctkPluginConstants::SERVICE_ID).toLongLong();IService* service3 = qobject_cast<IService*>(framework->getPluginContext()->getService(var));if (service3){service3->printf();}}}//3.2获取某些服务IService* service3 = NULL;ref3List = framework->getPluginContext()->getServiceReferences<IService>("(&(name=ServiceImp1))");foreach(ctkServiceReference var, ref3List){if (var){qDebug() << "service name:" << var.getProperty("name").toString();qDebug() << "service ranking:" << var.getProperty(ctkPluginConstants::SERVICE_RANKING).toLongLong();qDebug() << "service id:" << var.getProperty(ctkPluginConstants::SERVICE_ID).toLongLong();IService* service3 = qobject_cast<IService*>(framework->getPluginContext()->getService(var));if (service3){service3->printf();}}}//3.3获取一个服务,由service ranking 和service id决定ctkServiceReference ref = framework->getPluginContext()->getServiceReference<IService>();if (ref) {IService* service3 = qobject_cast<IService*>(framework->getPluginContext()->getService(ref));if (service3){service3->printf();}}//ctkPlugin::State sta = plugin->getState();//ctkPluginFrameworkLauncher::stop();//plugin->stop(); //plugin->uninstall();//sta = plugin->getState();CTKPlugin c;c.show();return a.exec();
    }
    

    CTK插件框架学习-事件监听(04)icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/137171155

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/296495.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ABC318 F - Octopus

解题思路 对于每个宝藏维护个区间&#xff0c;答案一定在这些区间中对于每个区间的端点由小到大排序对于每个点进行判断&#xff0c;若当前位置合法&#xff0c;则该点一定为一个右端点则该点到前一个端点之间均为合法点若前一个点不合法&#xff0c;则一定是某一个区间限制的…

C++万物起源:类与对象(三)拷贝构造、赋值重载

目录 一、拷贝构造函数 1.1拷贝构造函数的概念与特征 1.2拷贝构造的实现 1.3默认构造函数 1.4拷贝构造函数典型调用场景 二、赋值运算符重载 2.1赋值运算符重载的格式 一、拷贝构造函数 1.1拷贝构造函数的概念与特征 在c语言语法中&#xff0c;我们可以将一个变量赋值给…

SSTI模板注入(jinja2)

前面学习了SSTI中的smarty类型&#xff0c;今天学习了Jinja2&#xff0c;两种类型都是flask框架的&#xff0c;但是在注入的语法上还是有不同 SSTI&#xff1a;服务器端模板注入&#xff0c;也属于一种注入类型。与sql注入类似&#xff0c;也是通过凭借进行命令的执行&#xff…

【JavaWeb】Day32.MySQL概述

什么是数据库 数据库&#xff1a;英文为 DataBase&#xff0c;简称DB&#xff0c;它是存储和管理数据的仓库。 像我们日常访问的电商网站京东&#xff0c;企业内部的管理系统OA、ERP、CRM这类的系统&#xff0c;以及大家每天都会刷的头条、抖音类的app&#xff0c;那这些大家所…

项目5-验证码案例

选择使用Google的开源项目Kaptcha来实现. 1.Kaptcha 插件介绍 Kaptcha 是Google的⼀个高度可配置的实⽤验证码⽣成⼯具. 代码: http://code.google.com/p/kaptcha/ ⽹上有很多⼈甚⾄公司基于Google的kaptcha进⾏了⼆次开发. 我们选择⼀个直接适配SpringBoot的 开源项目 htt…

Vue 大文件切片上传实现指南包会,含【并发上传切片,断点续传,服务器合并切片,计算文件MD5,上传进度显示,秒传】等功能

Vue 大文件切片上传实现指南 背景 在Web开发中&#xff0c;文件上传是一个常见的功能需求&#xff0c;尤其是当涉及到大文件上传时&#xff0c;为了提高上传的稳定性和效率&#xff0c;文件切片上传技术便显得尤为重要。通过将大文件切分成多个小块&#xff08;切片&#xff0…

(免费分享)基于微信小程序自助停取车收费系统

本项目的开发和制作主要采用Java语言编写&#xff0c;SpringBoot作为项目的后端开发框架&#xff0c;vue作为前端的快速开发框架&#xff0c;主要基于ES5的语法&#xff0c;客户端采用微信小程序作为开发。Mysql8.0作为数据库的持久化存储。 获取完整源码&#xff1a; 大家点赞…

上位机图像处理和嵌入式模块部署(qmacvisual并发执行)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 类似于qmacvisual这样的软件&#xff0c;其实价格并不便宜。比如大家熟知的halcon、vision pro、vision master这样的软件&#xff0c;最便宜的版本…

AlexNet网络模型

AlexNet 是一个深度卷积神经网络&#xff0c;由 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton 在 2012 年的 ImageNet 大规模视觉识别挑战赛&#xff08;ILSVRC&#xff09;中首次提出并获得了显著的成功。它是深度学习历史上一个里程碑式的模型&#xff0c;对后来的深…

【漏洞复现】通天星CMSV6车载主动安全监控云平台inspect_file接口处存在任意文件上传漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

【opencv】教程代码 —features2D(4)利用两张摄像机拍摄的图片计算单应性矩阵...

homography_from_camera_displacement.cpp Chessboard poses 棋盘姿态 使用根据相机位移计算的单应性扭曲图像 使用根据绝对相机姿势计算的单应性扭曲图像 Warped images comparison 扭曲图像比较 左侧-nfindHomography 右侧-使用根据相机位移计算的单应性扭曲图像 终端输出&a…

Electron 打包自定义NSIS脚本为安装向导增加自定义页面增加输入框

Electron 打包工具有很多&#xff0c;如Electron-build、 Electron Forge 等&#xff0c;这里使用Electron-build&#xff0c;而Electron-build使用了nsis组件来创建安装向导&#xff0c;默认情况nsis安装向导不能自定义安装向导界面&#xff0c;但是nsis提供了nsis脚本可以扩展…

Express框架搭建项目 node.js

文章目录 引言Express框架介绍express安装环境准备写一个简单的项目展示 文章总结 引言 Express是一个基于Node.js平台的轻量级Web应用框架&#xff0c;它提供了简洁的API和丰富的功能&#xff0c;使得开发者能够快速地构建Web服务器和API。本文将带领大家从零开始&#xff0c…

企业管理新思考:利润率与质量在创业路上的重要性

一、引言 在当下这个充满变革与挑战的商业环境中&#xff0c;创业者和企业家们时常面临着规模扩张与利润增长之间的权衡。著名天使投资人吴世春先生的一席话&#xff0c;为我们指明了方向&#xff1a;“做企业利润率优先于规模&#xff0c;质量优先于数量。”这一深刻见解&…

unity 使用Base64编码工具对xml json 或者其他文本进行加密 解密

Base64编码加密解密工具 这是一个加密解密的网页工具&#xff0c;别人可以把他加密后的字符串给你&#xff0c;然后你可以用代码解密出来&#xff0c; 或者自己对内容进行加密&#xff0c;解密处理。 /// <summary>/// Base64 解码/// </summary>string DecodeBase…

【WEEK6】 【DAY3】MySQL函数【中文版】

2024.4.3 Wednesday 目录 5.MySQL函数5.1.常用函数5.1.1.数据函数5.1.2.字符串函数5.1.2.1.CHAR_LENGTH(str)计算字符串str长度5.1.2.2.CONCAT(str1,str2,...)拼接字符串str1 str2 ...5.1.2.3.INSERT(str,pos,len,newstr)把原文str第pos位开始长度为len的字符串替换成newstr5.…

WPF上使用MaterialDesign框架---下载与配置

一、介绍&#xff1a; Material Design语言的一些重要功能包括 系统字体Roboto的升级版本 &#xff0c;同时颜色更鲜艳&#xff0c;动画效果更突出。杜拉特还简要谈到了新框架的一些变化。谷歌的想法是让谷歌平台上的开发者掌握这个新框架&#xff0c;从而让所有应用就有统一的…

DETR【Transformer+目标检测】

End-to-End Object Detection with Transformers 2024 NVIDIA GTC&#xff0c;发布了地表最强的GPU B200&#xff0c;同时&#xff0c;黄仁勋对谈《Attention is All You Need》论文其中的7位作者&#xff0c;座谈的目的无非就是诉说&#xff0c;Transformer才是今天人工智能成…

技术揭秘:如何打造完美互动的充电桩硬件与服务平台?

充电桩平台全套源码地址 https://gitee.com/chouleng/cdzkjjh.git 这张图像是一个系统或服务的架构图。以下是对图中各个部分的描述&#xff1a; 前端&#xff1a; 位于图像的顶部&#xff0c;颜色为浅绿色。用户服务端&#xff1a; 紧邻前端&#xff0c;颜色为淡黄色。设备服…

基于深度学习的肿瘤图像检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;在本博客中&#xff0c;我们深入探讨了基于YOLOv8/v7/v6/v5的肿瘤图像检测系统。核心上&#xff0c;我们采用了最新的YOLOv8技术&#xff0c;并将其与YOLOv7、YOLOv6、YOLOv5算法进行了综合整合和性能指标对比分析。我们详细阐述了当前国内外在此领域的研究现状…