CTK插件框架学习-服务工厂(06)

news2024/11/26 16:36:57

CTK插件框架学习-信号槽(05)icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/137240105

一、服务工厂定义

  1. 注册插件时使用服务工厂注册,使用getService根据调用者插件资源文件内容获取在服务工厂内的对应实现
  2. 在服务工厂中可以知道是哪个插件正在调用服务工厂
  3. 懒汉模式,在需要时(通过服务工厂获取时)才创建出对象实例
  4. 可以根据需要在服务工厂内创建出多个其他插件对应需要的功能

二、服务工厂插件

IPrintfService.h

#pragma once
#include <QObject>

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

//此宏将当前这个接口类声明为接口,后面的字符串是这个接口的唯一标识。
Q_DECLARE_INTERFACE(IPrintfService, "zr.TestServiceFactory.IPrintfService")

PrintfServiceImp1类

========================PrintfServiceImp1.h===========================
#pragma once

#include "IPrintfService.h"
#include <QObject>

class ctkPluginContext;
class PrintfServiceImp1 :
	public QObject, public IPrintfService
{
	Q_OBJECT
	//当一个类继承这个接口类,表明需要实现这个接口类
	Q_INTERFACES(IPrintfService)
	
public:
	PrintfServiceImp1();
	void printf();

};

========================PrintfServiceImp1.cpp=========================

#include "PrintfServiceImp1.h"

#include <qdebug.h>

PrintfServiceImp1::PrintfServiceImp1()
{
}

void PrintfServiceImp1::printf()
{
	qDebug() << "ServiceImp1 printf zr.A";
}

PrintfServiceImp2类

=============================PrintfServiceImp2.h================================
#pragma once
#include "IPrintfService.h"
#include <QObject>


class ctkPluginContext;
class PrintfServiceImp2 :
	public QObject, public IPrintfService
{
	Q_OBJECT
	//当一个类继承这个接口类,表明需要实现这个接口类
	Q_INTERFACES(IPrintfService)

public:
	PrintfServiceImp2();
	void printf();
};

=============================PrintfServiceImp2.cpp=============================

#include "PrintfServiceImp2.h"

#include <qdebug.h>

PrintfServiceImp2::PrintfServiceImp2()
{
}

void PrintfServiceImp2::printf()
{
	qDebug() << "ServiceImp2 printf zr.B";
}

ServiceFactory类

============================ServiceFactory.h=============================
#pragma once
#include <qobject.h>

#include <ctkServiceFactory.h>
#include <ctkPluginConstants.h>
#include <ctkVersion.h>
#include "IPrintfService.h"

class ServiceFactory :
	public QObject, public ctkServiceFactory
{
	Q_OBJECT
	Q_INTERFACES(ctkServiceFactory)

public:
	ServiceFactory();

	QObject* getService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration);
	void ungetService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration, QObject* service);

private:
	QObject* getServiceByName(QString name);

private:
	int m_count;
};

============================ServiceFactory.cpp===========================

#include "ServiceFactory.h"

#include <qdebug.h>

#include "PrintfServiceImp1.h"
#include "PrintfServiceImp2.h"

ServiceFactory::ServiceFactory()
{
	m_count = 0;
}

QObject * ServiceFactory::getService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration)
{
	Q_UNUSED(registration)

	qDebug() << "getSymbolicName: " << plugin->getSymbolicName();
	qDebug() << "plugin count: " << m_count++;
	QHash<QString, QString> headers = plugin->getHeaders();
	//ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));
	//QString name = headers.value(ctkPluginConstants::PLUGIN_NAME);
	//qDebug() << "PLUGIN_NAME: " << name;

	QString pluginName = headers.value(ctkPluginConstants::PLUGIN_NAME);
	QObject* obj = getServiceByName(pluginName);
	return obj;

}

void ServiceFactory::ungetService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration, QObject * service)
{
	Q_UNUSED(plugin)
	Q_UNUSED(registration)
	Q_UNUSED(service)

	qDebug() << "getSymbolicName: " << plugin->getSymbolicName();
	QHash<QString, QString> headers = plugin->getHeaders();
}

QObject * ServiceFactory::getServiceByName(QString name)
{
	if (name.contains("zr.A"))
	{
		return new PrintfServiceImp1();
	}
	else
	{
		return new PrintfServiceImp2();
	}
}

PluginActivator类

=============================PluginActivator.h================================
#pragma once
#include <qobject.h>
#include "ctkPluginActivator.h"
#include "ctkPluginContext.h"
#include "PrintfServiceImp1.h"
#include "PrintfServiceImp2.h"

class PluginActivator :
	public QObject, ctkPluginActivator
{
	Q_OBJECT
	Q_INTERFACES(ctkPluginActivator)//向Qt的插件框架声明,希望将xxx插件放入到框架中。
	Q_PLUGIN_METADATA(IID "TestServiceFactory")//向qt框架申明插件(qt5版本)

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

=============================PluginActivator.cpp==============================

#include "PluginActivator.h"
#include <QDebug>
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"

#include "ServiceFactory.h"
#include "IPrintfService.h"

PluginActivator::PluginActivator()
{

}
void PluginActivator::start(ctkPluginContext *context)
{
	ServiceFactory* serviceFactory = new ServiceFactory();
	context->registerService<IPrintfService>(serviceFactory);

}

void PluginActivator::stop(ctkPluginContext *context)
{
	Q_UNUSED(context);

}

三、测试插件

新建插件可以参考CTK插件框架学习-新建插件(02)

1、在新插件中调用服务工厂

	//使用服务工厂
	ctkServiceReference ref = context->getServiceReference<IPrintfService>();
	if (ref)
	{
		IPrintfService* service = qobject_cast<IPrintfService*>(context->getService(ref));
		if (service != nullptr)
		{
			service->printf();
		}
	}

 2、新插件MANIFEST.MF文件内容如下:

Plugin-SymbolicName:TestUseServiceFactoryPluginA
Plugin-Version: 1.0.0//版本号添加多级或带字母会导致插件加载失败
Plugin-Name: zr.A


键值对类型可以参考ctkPluginConstants.h文件,根据服务工厂内使用的字段类型进行修改,
如在服务工厂内以获取插件名称的方式区分不同插件,则定义(Plugin-Name: zr.A),
然后通过以下方式获取属性值进行区分
QHash<QString, QString> headers = plugin->getHeaders();
QString pluginName = headers.value(ctkPluginConstants::PLUGIN_NAME);

四、加载插件

#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 "../TestServiceFactory/IPrintfService.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 + "/CTKPlugins");
	//ctkPluginFrameworkLauncher::addSearchPath("E:/Demo(Qt5)/08_CTKPlugin/CTKPlugin/CTK/lib/ctk-0.1/plugins");
#else
	ctkPluginFrameworkLauncher::addSearchPath(path + "/CTKPlugins");
#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;
#if 1
	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);
			qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
			
			//获取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);//表示立即启用插件,不设置参数的话加载后也不会立即打印输出
			qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
		}
		catch (ctkPluginException e) {
			std::cout << e.message().toStdString() << e.getType() << std::endl;
		}
	}
#else

#endif

    //在main函数中调用服务工厂获取到的getSymbolicName为"system.plugin"
	ctkServiceReference ref = framework->getPluginContext()->getServiceReference<IPrintfService>();
	if (ref)
	{
		IPrintfService* service = qobject_cast<IPrintfService*>(framework->getPluginContext()->getService(ref));
		if (service != nullptr)
		{
			service->printf();
		}
	}

	//ctkPlugin::State sta = plugin->getState();
	//ctkPluginFrameworkLauncher::stop();
	//plugin->stop(); 
	//plugin->uninstall();
	//sta = plugin->getState();

	

	CTKPlugin c;
	c.show();
    return a.exec();
}

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

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

相关文章

Java数组详解

​TOC 第一章、数组的概念介绍 1.1&#xff09;数组的概念 ①数组就是用来储存数据的容器,可以存储同一种类型的数据&#xff0c;是同一种数据类型的集合。实现对这些数据的统一管理。如果数组中存储的是基本类型数据&#xff0c;我就不能往里面存引用类型数据。数组中存储的…

Java-Tomcat

一、web补充技术 ①&#xff1a;B/S架构 主流的方式&#xff0c;只要有浏览器即可。编程方式直接基于socket即可 ②&#xff1a;javascript 简称js&#xff0c;早期只是实现在客户端的浏览器的动态效果&#xff0c;但服务端不会解释运行&#xff0c;所以本质上是静态资源。 …

峥嵘九载,逐云而上:青果乔迁新址,乘风破浪再起新篇

4月1日&#xff0c;近百名员工和诸多合作伙伴齐聚&#xff0c;共同见证了青果九周年庆典暨乔迁仪式这一里程碑式的时刻。 新起点&#xff0c;新征程&#xff0c;再启航&#xff01; 以新为序&#xff0c;共赴新征程 在典礼上&#xff0c;青果创始人和高管分别发表了致辞&#…

python实现OCR:pytesseract和pyddleocr(附代码)

文章目录 背景pytesseractpaddleocr百度apipaddleocr 背景 OCR是光学字符识别&#xff08;Optical Character Recognition&#xff09;的缩写&#xff0c;通过扫描等光学输入方式和文字识别将图片中的文字提取出来&#xff0c;非常适用于提取网络截图或扫描pdf等文件里的文本。…

2014最新AI智能系统ChatGPT网站源码+Midjourney绘画网站源码+搭建部署教程文档

一、文章前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持…

关于OpenFeign的返回类型包装问题

在一天夜里。我在使用feign的调用时&#xff0c;突然出现了一点点问题。 就是对于feign类型的包装问题。产生了疑问。 在后来&#xff0c;也就是今天。在网上取取经。看到了一个答案。说&#xff1a;feign的调用会有一个编码器和解码器。 使用feign的解码器。他的原理也很简…

c++有趣代码(游戏)(续集)

19.忍者三(参考:c++高级游戏集游戏_c++游戏库-CSDN博客) #include<bits/stdc++.h> #include<windows.h> #include<stdio.h> #include<conio.h> #include<time.h> #define Nor if(B[b].x<5) B[b].x=5; #define Out1 Bx1-

【JavaEE框架技术】spring-1

目录 一、使用maven管理spring项目 1.1搭建开发环境 1.1.1修改settings.xml文件 1.1.2把该文件拷入.m2目录 1.1.3打开ecplise&#xff0c;建立maven项目 1.1.4向pom.xml文件中添加spring的坐标&#xff1a; 1.4.1.1代码含义 1.4.1.2代码说明 1.2创建spring配置文件 二…

7.1.4 Selenium 爬取京东商品信息实战

目录 1、实战内容 2、思路 3、分析 url 4、开始操作 1、得到 Cookies 2、访问页面&#xff0c;得到 response 3、解析页面 4、存入 MySQL 5、1-3步总代码 1、实战内容 爬取京东笔记本电脑商品的信息(如&#xff1a;价格、商品名、评论数量)&#xff0c;存入 MySQL 中…

RAG基础知识及应用

简单介绍下RAG的基础知识和RAG开源应用 “茴香豆" 一. RAG 基础知识 1. RAG工作原理 RAG是将向量数据库和大模型问答能力的有效结合&#xff0c;从而达到让大模型的知识能力增加的目的。首先将知识源存储在向量数据库中&#xff0c;当提出问题时&#xff0c;去向量数据库…

ENVI实战-影像的下载和矢量边界裁剪

实验1&#xff1a;学会使用不同的遥感数据检索和下载平台 目的&#xff1a;学会使用不同的数据平台&#xff0c;检索和下载所需的遥感数据。 过程&#xff1a; ①基于地理空间数据云的数据检索和下载方法&#xff1a; A.网站进入&#xff1a;网络搜索&#xff1a;https://w…

Notepad++软件安装及配置说明

Notepad是 Windows操作系统下的一套文本编辑器&#xff0c;有完整的中文化接口及支持多国语言编写的功能。 Notepad功能比 Windows自带记事本强大&#xff0c;除了可以用来制作一般的纯文字说明文件&#xff0c;也十分适合编写计算机程序代码。Notepad不但可以显示行号&#xf…

ABC库存分类管理法

ABC库存分类管理法&#xff1f; ABC分类法是根据物品在技术或经济方面的主要特征&#xff0c;进行分类排队&#xff0c;将分析对象划分成A、B、C三类&#xff0c;从而有区别地确定管理方式的分析方法。 ABC分类法来源与定义 1951年美国通用公司经理戴克将“关键的少数和次要的…

day76 jquery

知识点: 1 在HTML中引入jQuery 2 jQuery中就绪函数 3 jQuery中选择器 4 使用jQuery获取表单元素的值 及标签中间的内容 5 jQuery中获取标签属性 6 jQuery设置和获取标签样式 ----------------------------------- 一 在HTML中引入jQuery 1 1) 把jQue…

3.C++ Make

1.Makefile 1.1 什么是 Makefile 一个工程中有很多文件&#xff0c;文件之间都是相辅相成有着编译的先后顺序&#xff0c;但是如果自己手动根据编译顺序编译文件造成速度非常慢。Makefile 是”自动化编译“&#xff0c;只需一个 make 指令系统就会根据编译顺序帮自己编译文件…

excel散点图怎么每个点添加名称

最终效果图&#xff1a; 添加图标元素->数据标签->其他数据标签选项 选择单元格中的值 手动拖动数据标签&#xff0c;调整到合适的位置。

Spring学习笔记:IOC控制反转、AOP面向切面

挺快的&#xff0c;框架这一部分 文章目录 一、Spring概述入门案例导入依赖包在src下写配置文件创建普通类和测试类 二、IOC&#xff08;控制反转&#xff09;2.1 IOC bean 的XML操作&#xff08;创建对象&#xff0c;注入属性2.2 IOC bean 的 注解 操作 三、AOP&#xff08;面…

《UE5_C++多人TPS完整教程》学习笔记31 ——《P32 角色移动(Character Movement)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P32 角色移动&#xff08;Character Movement&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译者&…

用国内版Devin:DevOpsGPT开发一个简易官网

前言&#xff1a; 世界上第一个AI程序员Devin想必已经给大家带来了不小的震撼&#xff0c;这种L4级的技术也许已经昭示着AGI离我们或许真的不远了。 这里先给大家普及一个概念&#xff1a; L4是谷歌对AGI划分的第四个等级&#xff0c;把代码丢给 AI 改这个是 L1 或者 L2 级别的…

CentOS7安装Docker及禅道

https://blog.csdn.net/weixin_46453070/article/details/136183615?ops_request_misc%257B%2522request%255Fid%2522%253A%2522171246925816800222886233%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id171246925816800222886233&biz_i…