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

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_OBJECTQ_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_OBJECTQ_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 _DEBUGctkPluginFrameworkLauncher::addSearchPath(path + "/CTKPlugins");//ctkPluginFrameworkLauncher::addSearchPath("E:/Demo(Qt5)/08_CTKPlugin/CTKPlugin/CTK/lib/ctk-0.1/plugins");
#elsectkPluginFrameworkLauncher::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 1QDirIterator 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.mzph.cn/news/800888.shtml

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

相关文章

Day5-Hive的结构和优化、数据文件存储格式

Hive 窗口函数 案例 需求&#xff1a;连续三天登陆的用户数据 步骤&#xff1a; -- 建表 create table logins (username string,log_date string ) row format delimited fields terminated by ; -- 加载数据 load data local inpath /opt/hive_data/login into table log…

开源免费的多功能PDF工具箱

它支持修改PDF、编辑PDF书签、导出PDF书签、导入书签、生成、合并、拆分、提取页面内容、提取图片、OCR 功能介绍: 修改PDF信息&#xff1a;修改文档属性、页码编号、页面链接、页面尺寸&#xff1b;删除自动打开网页等动作&#xff0c;去除复制及打印限制&#xff1b;设置阅读…

SQLite数据库的性能问题并不是单纯地由数据量的大小决定的,而是受到多种因素的综合影响。以下是一些可能导致SQLite性能问题的因素

SQLite数据库的性能问题并不是单纯地由数据量的大小决定的&#xff0c;而是受到多种因素的综合影响。以下是一些可能导致SQLite性能问题的因素&#xff1a; 数据量&#xff1a;当SQLite数据库中的数据量增长到一定程度时&#xff0c;查询、插入和更新等操作可能会变得缓慢。这…

进程替换exec系列介绍

ececl,execlp,execle,execv,execvp //库函数 execve //系统调用 1.execl which ps #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() {printf("main pid%d\n",getpid());execl("/usr/bin/ps","ps&qu…

.Net HttpClient应用

.NET HttpClient 是一个类型&#xff0c;在 System.Net.Http 命名空间中&#xff0c;用于发送 HTTP 请求和接收 HTTP 响应。它是 .NET 框架和 .NET Core 中用于处理 HTTP 通信的主要工具。HttpClient 提供了一个高级别的 API&#xff0c;用于向 Web 服务发送请求并接收响应&…

数据仓库作业四:第7章 数据的属性与相似性

目录 第7章 数据的属性与相似性作业题 第7章 数据的属性与相似性 作业题 1、设有10个二元属性&#xff0c;3个数据对象的数据集&#xff08;表1&#xff09;。 id A 1 A_1 A1​ A 2 A_2 A2​ A 3 A_3 A3​ A 4 A_4 A4​ A 5 A_5 A5​ A 6 A_6 A6​ A 7 A_7 A7​ A 8 A_8 A8​…

工业通信原理——Modbus-TCP通信C语言程序代码

工业通信原理——Modbus-TCP通信C语言程序代码 前言 简单的Modbus-TCP通信的C语言程序代码示例,包括底层驱动层和应用层。 C语言程序代码详解 底层驱动层(modbus_driver.c): #include <stdio.h> #include <stdint.h> #include <stdbool.h>// 定义Mo…

蓝桥杯 试题 基础练习 十六进制转八进制

资源限制 内存限制&#xff1a;512.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述   给定n个十六进制正整数&#xff0c;输出它们对应的八进制数。输入格式   输入的第一行为一个正整数n &#xff08;1&…

别再抱怨学鸿蒙没方向了! 这鸿蒙全栈(南北双向)开发学习路线收藏好!

在互联网技术不断发展的现在&#xff0c;鸿蒙操作系统的出现标志着是能技术领域的一次重大突破&#xff0c;鸿蒙作为华为推出的一代操作系统&#xff0c;鸿蒙不仅达代表了自主创新的力量&#xff0c;还因为独特的分布式架构和全场景适配能力而备受关注。随着鸿蒙生态的不断完善…

2024.4.7周报

摘要 在本周阅读的文献中&#xff0c;提出了基于Transformer的GAN模型&#xff0c;GAN的生成器和鉴别器&#xff0c;都是基于Transformer的编码器架构构建的&#xff0c;通过处理图像的方式处理时间序列数据作为该模型的输入。该模型能够生成各种长度的多维时间序列数据&#…

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

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

Mysql服务器主从相关

一主一从 准备两台服务器(以53为主,54为从)启动主服务器binlog日志 vim /etc/my.cnf.d/mysql-server.cnf [mysqld] server-id53 //指定主服务器的server-id为53 log-binmysql53 //修改binlog日志命名 :wqsystemctl restart mysqld //重载mysqld服务,使得以上配置生效 创…

11-新热文章-实时计算

热点文章-实时计算 1 今日内容 1.1 定时计算与实时计算 1.2 今日内容 kafkaStream 什么是流式计算 kafkaStream概述 kafkaStream入门案例 Springboot集成kafkaStream 实时计算 用户行为发送消息 kafkaStream聚合处理消息 更新文章行为数量 替换热点文章数据 2 实时…

备战蓝桥杯---最长公共子序列(LCS)模板

题目链接&#xff1a;最长公共子序列 import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner;public class Main {public static void main(String[] args){Scanner scannernew Scanner(System.in);int nscanner.nextInt();i…

C++ sleep相关延时函数

目录 秒相关单位进制转换 sleep() 函数&#xff1a; usleep() 函数&#xff1a; nanosleep() 函数&#xff1a; C11及以后版本的std::this_thread::sleep_for()&#xff1a; 秒相关单位进制转换 秒&#xff08;second, s&#xff09;是国际单位制&#xff08;SI&#xff…

vue watch监听的多种使用

简述&#xff1a;vue 的watch的监听使用的几种写法。常用第4中写法。 一、$route监听路由跳转 前提&#xff1a;当需要前端监听路由跳转的时候&#xff0c;一般写在App.vue入口 //App.vue //vue2、uniapp写法 watch: {$route(to, from) {if (hasPermission(to.path)) {this…

能源照明运作机制与智能调控技术实现途径

随着城市化进程的加速&#xff0c;智慧城市已成为现代城市发展的重要方向。能源照明作为城市基础设施的重要组成部分&#xff0c;其运作机制与智能调控技术的实现对于提高城市能源利用效率、促进可持续发展具有重要意义。 能源照明是一个涵盖广泛、错综复杂的领域&#xff0c;它…

Redis中的集群(一)

集群 概述 Redis集群是Redis提供的分布式数据库方案&#xff0c;集群通过分片(sharding)来进行数据共享&#xff0c;并提供复制和故障转移功能 节点 一个Redis集群通常由多个节点(node)组成&#xff0c;在刚开始的时候&#xff0c;每个节点都是相互独立的&#xff0c;它们都…

【优选算法专栏】专题十六:BFS解决最短路问题(二)

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

奇函数+(-)偶函数一定是非奇非偶函数?

今天遇到个有意思的题&#xff0c;跟大家分享一下&#xff0c;可能有的人不太了解&#xff1a; 首先说下结论&#xff1a;这题选D选项&#xff0c;以上均有可能&#xff1b; 开始证明&#xff1a; 非奇非偶函数的充要条件&#xff1a; 定义域是(一a,a)(a>0)或(一 oo,oo)的…