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

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. 插件卸载后没有从框架中移除,热插拔实现待定。。。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序开发技巧:canvas实现电子签名

在微信小程序中实现电子签名功能方式很多,本文采用canvas绘制的方式实现。具体实现步骤如下: 在页面中添加canvas元素 <view class"container"><canvas canvas-id"signCanvas" class"canvas" disable-scrolltrue touchstart"sta…

OSCP靶场--Cockpit--待续

OSCP靶场–Cockpit 考点(sql注入绕过sudo tar提权) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.229.10 -Pn -sV -sC --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-25 01:40 EDT Nmap scan report for 192.168.…

上班几周了,

过年回来后&#xff0c;时间变得飞快&#xff0c;很多事情都是马上要去干&#xff0c;而且又是很着急的事&#xff0c;呵呵&#xff0c;真的要干趴了 然后——经历了第一次年后的周末连续加班出版本保量产&#xff0c;经历了加班到凌晨3点调试问题&#xff0c;经历我们在疯狂的…

【字典树】【字符串】【 前缀】100268. 最长公共后缀查询

作者推荐 视频算法专题 本文涉及知识点 字典树 字符串 前缀 LeetCode 100268. 最长公共后缀查询 给你两个字符串数组 wordsContainer 和 wordsQuery 。 对于每个 wordsQuery[i] &#xff0c;你需要从 wordsContainer 中找到一个与 wordsQuery[i] 有 最长公共后缀 的字符串…

Linux课程_____网络管理

一、查看接口信息 1. ifconfig 查看所有活动网络接口的信息 ifconfig -a 查看所有网络接口信息 ifconfig 直接加网络接口 查看指定网络接口信息 1.1查看指定接口IP [rootlocalhost ~]# ip addr show ens160 1.2设置网络接口的IP地址 # ifconfig eth0 192.168.152.133 …

基于Springboot+Vue的前后端分离的简单Demo案例(二)

前端搭建 Vue router 来动态构建左侧菜单 导航1 页面1页面2导航2 页面3页面4导航3 页面5页面6 在views目录下创建四个页面 PageOne.vue <template><h1>这是页面1</h1> </template> <script> export default {name: "PageOne", }; …

Java String类深入了解JDK各个版本进阶版本

Java String类深入了解JDK各个版本进阶版本 一&#xff0c;底层类型 在jdk11中 String value 存储字符串值 是byte[] 数组 &#xff0c;String中存储字节码的是coder 也是byte类型&#xff0c;因此String的底层数据存储类型成为了byte类型 而在jdk8中String 的String value 存…

shell编程-jq命令详解

文章目录 前言一、jq简介1. 简介2. 语法3. 命令选项 二、用于处理json数据1. 过滤1.1 标识运算符1.2 基本过滤1.3 获取对象属性1.3 迭代数组元素1.4 获取数组元素1.5 使用运算符 2. 类型和值2.1 数组构造2.2 对象构造2.3 递归下降 3. 内置运算符和函数3.1 算术运算符3.2 函数3.…

Makefile的override

今天在编译opengauss extension时遇到一个报错&#xff1a; 简单的理解就是编译时要加 -fPIC&#xff0c;告诉编译器生成Position Independent Code&#xff0c;试过 make CPPFLAGS-fPIC 可以成功编译&#xff0c;不过看到其它的解决方案是在Makefile中加 override CPPFLAG…

代码随想录算法训练营第三十天 | 332.重新安排行程,51. N皇后 ,37. 解数独

这道题是一道欧拉路径/ 欧拉回路的一笔画问题&#xff0c;需要找出开销最小的一笔画方案 这种一笔画的问题&#xff0c;以前学数据结构的时候我们习惯把图放进二维数组中存储&#xff0c;但对于这种无规律的图结构&#xff0c;我们可以使用二维的哈希表来存储&#xff0c;这样…

【4月】CDA Club 第2期数据分析组队打卡学习活动开启!

活动名称 CDA Club 第2期数据分析组队打卡学习活动 活动介绍 本次打卡活动由CDA俱乐部旗下学术部主办。目的是通过数据分析科普内容&#xff0c;为数据分析爱好者提供学习和交流的机会。方便大家利用碎片化时间在线学习&#xff0c;以组队打卡的形式提升学习效果&#xff0c…

水离子雾化壁炉的原理和技术解析

水离子雾化壁炉采用超声波雾化技术将水分子雾化成微细的水离子&#xff0c;然后通过风扇吹出再经过UVC紫外线杀菌产生安全仿真的火焰效果。以下是水离子雾化壁炉的原理和技术解析&#xff1a; 超声波雾化技术&#xff1a; 水离子雾化壁炉利用超声波振动器产生高频振动&#xf…

[Java、Android面试]_13_map、set和list的区别

本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料。 整理成了面试系列&#xff0c;由于时间有限&#xff0c;每天整理一点&#xff0c;后续会陆续分享出来&#xff0c;感兴趣的朋友可关注收…

TSN协议原理!看完这一篇就够了(1)——时钟同步IEEE802.1AS-2020

▎前言 在许多应用场景中&#xff0c;一个本地局域网中互联的设备集群需要共享同一个时间&#xff0c;以支持各设备的协同工作。例如&#xff1a;音频设备与视频设备的配合播放&#xff0c;雷达与摄像头的数据融合等&#xff1b;这样一个看似简单的域功能&#xff0c;细化成为…

好书推荐 :《 提问的艺术:让 ChatGPT 给出高质量答案 》

AGI 时代降临&#xff01;还不知如何向 ChatGPT 提问&#xff1f; 恰当的提示至关重要&#xff01;《提问的艺术—让 ChatGPT 给出高质量答案》一书&#xff0c;共 24 章&#xff0c;系统介绍了如何向 ChatGPT 提问以获取优质答案&#xff0c;是 ChatGPT 时代的入门指南&#x…

【 Mysql8.0 忘记登录密码 可以试试 】

** Mysql8.0 忘记登录密码 可以试试 ** 2024-3-21 段子手168 1、首先停止 mysql 服务 &#xff0c;WIN R 打开运行&#xff0c;输入 services.msc 回车打开服务&#xff0c;找到 mysql 服务&#xff0c;停止。 然后 WIN R 打开运行&#xff0c;输入 CMD 打开控制台终端输…

‘npm‘ 不是内部或外部命令,也不是可运行的程序

npm认识三年了&#xff0c;今天才知道这是node.js的命令 也就是说&#xff0c;想要在cmd里面运行 npm 命令&#xff0c;但就的安装node.js 1. node.js安装 没有安装包的先下载安装包&#xff1a;下载 | Node.js 中文网 (nodejs.cn) 下载之后双击打开&#xff0c;一路安装确…

如何为企业策划一场XR虚拟直播?

活动年年办&#xff0c;都是老一套&#xff0c;想玩点新花样&#xff1f; 预算有限&#xff0c;但还是想把活动办的逼格高一点&#xff1f; 想通过活动&#xff0c;让更多的人知道自己企业的品牌&#xff1f; 随着AIGC技术的不断演变&#xff0c;企业活动的形式和内容也在不…

Node.js之沙盒专题

​ Node.js一直是薄弱项&#xff0c;今天特意整理一下&#xff0c;基本上是各个大佬写的大杂烩&#xff0c;仅用于学习记录~~~ 1. child_process 首先介绍一下nodejs中用来执行系统命令的模块child_process。Nodejs通过使用child_process模块来生成多个子进程来处理其他事物…

滤波器自动化测试:用网络分析仪、示波器、功率计测量功率

滤波器的功率是电压与电流的乘积&#xff0c;滤波器的功率可以通过测量电压与电流计算得出。滤波器的功率对滤波器的稳定运行是至关重要的&#xff0c;如果功率过小可能会导致滤波器无法正常工作;功率越大则有可能会造成滤波器的损坏。因此滤波器的功率测量是非常重要的步骤。 …