CTK插件框架学习-新建插件(02)

news2024/9/22 21:26:23

CTK插件框架学习-源码下载编译(01)icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/136891825

开发环境

window11、vs17、Qt5.14.0、cmake3.27.4

开发流程

  1. 新建ctk框架调用工程(CTKPlugin)
    1. 拷贝CTK源码编译完成后的头文件和库文件到工程目录,并配置工程属性


    2. main.cpp
      #include "CTKPlugin.h"
      #include <QtWidgets/QApplication>
      
      
      #include <iostream>
      #include <QStyleFactory>
      #include <QDir>
      #include <QDirIterator>
      #include "ctkPluginFrameworkFactory.h"
      #include "ctkPluginFramework.h"
      #include "ctkPluginException.h"
      #include "ctkPluginContext.h"
      #include "ctkPluginFrameworkLauncher.h"
      #include "../TestPlugin/iTestPlugin.h"
      #include "../TestPlugin/LogServicesI.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();
      
      	//启动方式一
      #ifdef _DEBUG
      	ctkPluginFrameworkLauncher::addSearchPath(path + "/plugins");
      #else
      	ctkPluginFrameworkLauncher::addSearchPath(path + "/libs/plugins");
      #endif // _DEBUG
      	// 设置并启动 CTK 插件框架
      	try {
      		ctkPluginFrameworkLauncher::start("org.commontk.eventadmin");
      	}
      	catch (ctkException e)
      	{
      		std::cout << e.message().toStdString() << std::endl;
      	}
      	//启动方式二
      	// 启动插件工厂
      	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;
      	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;
      	}
      
      	//测试插件
      	iTestPlugin* it = NULL;
      	ctkServiceReference ref = framework->getPluginContext()->getServiceReference<iTestPlugin>();
      	if (ref)
      	{
      		it = framework->getPluginContext()->getService<iTestPlugin>(ref);
      	}
      	if (it)
      	{
      		it->showWidget();
      	}
      
      	//ctkPlugin::State sta = plugin->getState();
      	//ctkPluginFrameworkLauncher::stop();
      	//plugin->stop(); 
      	//plugin->uninstall();
      	//sta = plugin->getState();
      
      
      	CTKPlugin c;
      	c.show();
          return a.exec();
      }
      

  2. 新建插件工程(TestPlugin)
    1. 拷贝源码编译完成后的头文件和库文件到工程目录,并配置工程属性(同上)
    2. 新建注册器类
      PluginActivator.h
      #pragma once
      #include <qobject.h>
      #include "ctkPluginActivator.h"
      #include "ctkPluginContext.h"
      #include "TestPlugin.h"
      
      class PluginActivator :
      	public QObject, ctkPluginActivator
      {
      	Q_OBJECT
      	Q_INTERFACES(ctkPluginActivator)//向Qt的插件框架声明,希望将xxx插件放入到框架中。
      	Q_PLUGIN_METADATA(IID "TestPlugin")//向qt框架申明插件(qt5版本)
      
      public:
      	PluginActivator();
      	void start(ctkPluginContext *context);
      	void stop(ctkPluginContext *context);
      private:
      	QScopedPointer<TestPlugin> m_testPlugin;//智能指针,自动析构回收
      };
      
      

      PluginActivator.cpp
      #include "PluginActivator.h"
      #include <QDebug>
      #include "ctkPluginContext.h"
      
      PluginActivator::PluginActivator()
      {
      
      }
      void PluginActivator::start(ctkPluginContext *context)
      {
          //实现插件自己的功能
      
      	qDebug() << "my plugin start";
      	m_testPlugin.reset(new TestPlugin(context));
      	
      	ctkDictionary dic;
      	context->registerService<iTestPlugin>(m_testPlugin.get(), dic);
      
      }
      
      void PluginActivator::stop(ctkPluginContext *context)
      {
      	qDebug() << "my plugin stop";
      	Q_UNUSED(context)// Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用
      
      	ctkServiceReference  ref = context->getServiceReference<iTestPlugin>();
      	context->ungetService(ref);
      
      }

    3. 新建插件接口文件
      iTestPlugin.h
      #pragma once
      
      #include <QObject>
      #include <qstring.h>
      class iTestPlugin {
      public:
      	virtual ~iTestPlugin() {}
      	virtual void showWidget() = 0;
      };
      Q_DECLARE_INTERFACE(iTestPlugin, "zr.iTestPlugin")//声明一个接口类,此宏将当前这个接口类向qt系统声明为接口,后面的一长串就是这个接口的唯一标识。

    4. 新建插件实现文件
      iTestPlugin.h
      #pragma once
      
      #include <qobject.h>
      #include "iTestPlugin.h"
      #include "MyWidget.h"
      
      class ctkPluginContext;
      
      class TestPlugin : public QObject, public iTestPlugin
      {
      	Q_OBJECT
      	Q_INTERFACES(iTestPlugin)//此宏与Q_DECLARE_INTERFACE宏配合使用, 表明当前插件类实现这个服务接口
      public:
          TestPlugin(ctkPluginContext* context);
          ~TestPlugin();
      
      	virtual void showWidget();
      
      private:
      	ctkPluginContext *m_context;
      	QScopedPointer<MyWidget> m_myWidget;//空测试窗口
      };
      

      iTestPlugin.cpp
      #include "TestPlugin.h"
      
      #include "ctkPluginContext.h"
      
      TestPlugin::TestPlugin(ctkPluginContext* context)
          : m_context(context)
      {
      	m_myWidget.reset(new MyWidget());
      }
      
      TestPlugin::~TestPlugin()
      {
      	
      }
      
      void TestPlugin::showWidget()
      {
      	m_myWidget.get()->show();
      }
      

    5. 添加资源文件
      1. 每个插件必须有一个资源文件,名称一般与插件名称一致,前缀必须为TARGET/META-INF,例:插件名称/META-INF
      2. 每个插件必须添加一个元数据文件,名字必须为MANIFEST.MF,并添加到资源文件中
    6. 生成插件库文件到框架指定的调用目录
    7. 插件卸载后没有从框架中移除,热插拔实现待定。。。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot 整合Mybatis 实现增删改查(二)

续上篇&#xff1a;Springboot整合Mybatis的详细案例图解分析-CSDN博客 mapper层&#xff08;StudentMapper&#xff09; //通过id查询student方法Student searchStudentById(int id);//通过id删除student方法int deleteStudentById(int id);//通过id增加student方法int inser…

[Java基础揉碎]final关键字

目录 介绍 在某些情况下&#xff0c;程序员可能有以下需求&#xff0c;就会使用到final final注意事项和讨论细节 1) final修饰的属性又叫常量&#xff0c;一般用XX_XX_XX来命名 2) final修饰的属性在定义时&#xff0c;必须赋初值&#xff0c;并且以后不能再修改&#…

[AIGC] SQL中的数据添加和操作:数据类型介绍

SQL&#xff08;结构化查询语言&#xff09;作为一种强大的数据库查询和操作工具&#xff0c;它能够完成从简单查询到复杂数据操作的各种任务。在这篇文章中&#xff0c;我们主要讨论如何在SQL中添加&#xff08;插入&#xff09;数据&#xff0c;以及在数据操作过程中&#xf…

【官方】操作指南,附代码!银河麒麟服务器迁移运维管理平台V2.1中间件及高可用服务部署(4)

1.RocketMQ集群模式 主机配置示例&#xff1a; IP 角色 架构模式 对应配置文件 1.1.1.1 nameserver1 master broker-n0.conf 2.2.2.2 nameserver2 salve1 broker-n1.conf 3.3.3.3 nameserver3 salve2 broker-n2.conf 1.1.安装rocketmq 在服务器上安装rocket…

谷歌seo怎么优化产品推广?

想要在谷歌SEO上优化产品推广&#xff0c;关键在于理解和利用搜索引擎的工作原理来提升你的产品在搜索结果中的可见性&#xff0c;结构化数据就很重要了&#xff0c;它能让谷歌更容易理解你的页面内容&#xff0c;让他知道你这个页面不是文章页&#xff0c;主页&#xff0c;而是…

巧用cpl文件维权和免杀(上)

cpl文件 CPL文件&#xff0c;是Windows控制面板扩展项&#xff0c;CPL全拼为Control Panel Item在system32目录下有一系列的cpl文件,分别对应着各种控制面板的子选项 列入我们winR输入main.cpl 将会打开控制面板中的鼠标属性 cpl文件本质是属于PE文件 但cpl并不像exe,更像是dl…

3月份的倒数第二个周末有感

坐在图书馆的那一刻&#xff0c;忽然感觉时间的节奏开始放缓。今天周末因为我们两都有任务需要完成&#xff0c;所以就选了嘉定图书馆&#xff0c;不得不说嘉定新城远香湖附近的图书馆真的很有感觉。然我不经意回想起学校的时光&#xff0c;那是多么美好且短暂的时光。凝视着窗…

手撕算法-盛最多水的容器

描述 分析 两个板之间能盛下的水的量&#xff0c;取决于短板。想让两个板之间能盛下更多的水&#xff0c;需要改变短板的长度。就像水桶效应&#xff1a;那么用两个指针指向容器的两个板&#xff0c;然后每次移动较短的板即可。移动较短的板&#xff0c;可能会增大容积&#x…

芯片设计工程师必备基本功——《Verilog+HDL应用程序设计实例精讲》

进入芯片行业需要学习哪些基本功呢&#xff1f;其实芯片设计工程师的技能是通过多年的经验学习的。在您开始作为芯片设计工程师工作之前&#xff0c;很难给出一个需要的全面的单一列表&#xff0c;也不可能学习所有内容。话虽如此&#xff0c;但您开始芯片设计师职业生涯时必须…

HDFS的Shell操作及客户端配置方法

HDFS进程启停命令 Hadoop HDFS组件内置了HDFS集群的一键启停脚本。 $HADOOP_HOME/sbin/start-dfs.sh&#xff0c;一键启动HDFS集群$HADOOP_HOME/sbin/stop-dfs.sh&#xff0c;一键关闭HDFS集群 执行原理&#xff1a; 在执行此脚本的机器上&#xff0c;启动&#xff08;关闭&…

Java面试题总结200道(四)

76、ApplicationContext 通常的实现是什么? FileSystemXmlApplicationContext &#xff1a;此容器从一个 XML 文件中加 载 beans 的定义&#xff0c;XML Bean 配置文件的全路径名必须提供给它的构造函数。ClassPathXmlApplicationContext&#xff1a;此容器也从一个 XML 文件…

软件签名不一致会出现的原因和采取的措施

软件签名不一致的问题可能涉及到数字签名、证书、应用程序完整性和安全性等多个方面。这个问题对于软件开发和信息安全都是非常重要的&#xff0c;因此需要进行更加深入的讨论和解释。以下是关于软件签名不一致的可能原因的详细解释&#xff1a; 数字签名的作用和原理&#xff…

权限提升-系统权限提升篇数据库提权PostsqlRedis第三方软件提权密码凭据钓鱼文件

知识点 1、数据库到Linux-数据库提权-Redis 3、数据库到Linux-数据库提权-PostgreSQL 4、计算机用户到系统-第三方软件-各类应用 章节点&#xff1a; 1、Web权限提升及转移 2、系统权限提升及转移 3、宿主权限提升及转移 4、域控权限提升及转移 基础点 0、为什么我们要学习权…

【经验分享】转行如何自学Python并且找到工作,分享自己心得

目前信息化产业发展势头很好&#xff0c;互联网就成为了很多普通人想要涉及的行业&#xff0c;因为相比于传统行业&#xff0c;互联网行业涨薪幅度大&#xff0c;机会也多&#xff0c;所以就会大批的人想要转行来学习Python开发。 首先告诉你的是&#xff0c;应届生零基础开始学…

Redis实战篇-4

实战篇Redis 1.3 、实现发送短信验证码功能 页面流程 具体代码如下 贴心小提示&#xff1a; 具体逻辑上文已经分析&#xff0c;我们仅仅只需要按照提示的逻辑写出代码即可。 发送验证码 Overridepublic Result sendCode(String phone, HttpSession session) {// 1.校验手机…

python类属性和global变量区别

数据成员是指在类中定义的变量&#xff0c;即属性&#xff0c;根据定义位置&#xff0c;又可以分为类属性和实例属性。 类属性定义在方法前面。 定义类属性&#xff0c;非全局变量 class MyClass:#global cc 10 ## 类属性def my_function(self):global qwqw 9print(this …

Linux系统部署Paperless-Ngx文档管理系统结合内网穿透实现公网访问

文章目录 1. 部署Paperless-ngx2. 本地访问Paperless-ngx3. Linux安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 Paperless-ngx是一个开源的文档管理系统&#xff0c;可以将物理文档转换成可搜索的在线档案&#xff0c;从而减少纸张的使用。它内置…

获得淘宝app商品详情原数据

网络电商大数据平台实时监测了100余个主流电商交易平台&#xff0c;并通过所能网络完善的数据清洗体系和数学模型整合各平台数据&#xff0c;可实现全面准确掌握所能网络当地网商&#xff08;含企业个人&#xff09;及当地产品在各电商平台的发展动态。 能在秒级完成从数据采集…

新生儿奶瓶怎么选?2024精选宝宝奶瓶推荐榜单

很多新手妈妈都不知道该选择什么样的奶瓶&#xff0c;问我奶瓶买那种好呢&#xff1f;作为一名母婴产品和家电测评博主&#xff0c;我深知市面上的奶瓶品牌琳琅满目&#xff0c;但真正专业、材质安全性高的并不多见。 那什么品牌的新生儿奶瓶质量比较好呢&#xff1f;所以我特…

《论文阅读》因果情绪蕴含的知识桥因果交互网络 AAAI 2023

《论文阅读》因果情绪蕴含的知识桥因果交互网络 AAAI 2023 前言简介任务定义特征提取并行知识桥接因果互动实验结果前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Knowledge-Bridged Causal Interac…