CTK框架(十):PluginAdmin插件

news2024/9/21 3:37:22

目录

1.引言

2.实现原理

3.实际应用

3.1.界面控制

3.2.访问服务管理插件

4.总结


1.引言

        在CTK框架(三): 插件的安装讲解了插件的安装、启动、停止和卸载方法,对于一个插件可以这样写;但是如果是在一个大型的应用程序中,里面有很多插件,就需要一个管理这些插件的服务,CTK官方就提供给了一个:PluginAdmin。

        PluginAdmin它本身也是一个插件,它提供服务的接口有:

struct PluginAdmin
{
    virtual ~PluginAdmin() {}

    virtual void installAllPlugin() = 0;
    virtual void startAllPlugin() = 0;
    virtual void stopAllPlugin() = 0;
    virtual void uninstallAllPlugin() = 0;
};
  • installAllPlugin:安装系统所有插件
  • startAllPlugin:启动系统所有插件
  • stopAllPlugin:停止系统所有插件
  • uninstallAllPlugin: 卸载系统所有插件

2.实现原理

        跟其它CTK插件服务的一样,在PluginAdmin插件里面实现了接口PluginAdmin,代码如下:
pluginadminservice.h

#ifndef PLUGINADMINSERVICE_H
#define PLUGINADMINSERVICE_H

#include <QObject>
#include <service/pluginadmin/pluginAdmin.h>
#include <ctkPluginContext.h>
#include <service/event/ctkEventAdmin.h>

class PluginAdminService :public QObject,public PluginAdmin
{
    Q_OBJECT
    Q_INTERFACES(PluginAdmin)

public:
    explicit PluginAdminService(ctkPluginContext* context,QObject *parent = nullptr);
    ~PluginAdminService();

public:
    void installAllPlugin() Q_DECL_OVERRIDE;
    void startAllPlugin() Q_DECL_OVERRIDE;
    void stopAllPlugin() Q_DECL_OVERRIDE;
    void uninstallAllPlugin() Q_DECL_OVERRIDE;

signals:

private slots:

private:
    ctkPluginContext *m_context;
    ctkDictionary m_dictionary;
    ctkProperties m_properties;
    //事件管理服务插件
    ctkEventAdmin *m_eventAdmin;
    QSharedPointer<ctkPluginFramework> m_framework;
    QStringList m_libFilter;
    QString m_path;
};

#endif // PLUGINADMINSERVICE_H

pluginadminservice.cpp

#include "pluginadminservice.h"
#include <service/event/ctkEventConstants.h>
#include <QCoreApplication>
#include <QDirIterator>
#include <QJsonArray>
#include <QThread>
#include <ctkPluginException.h>
#include <ctkPluginFrameworkFactory.h>
#include <ctkPluginFrameworkLauncher.h>

PluginAdminService::PluginAdminService(ctkPluginContext* context, QObject* parent) :
	QObject(parent),
	m_context(context),
	m_eventAdmin(nullptr),
	m_framework(nullptr)
{
	//注册插件管理服务
	context->registerService<PluginAdmin>(this);
	ctkServiceReference eventRef = context->getServiceReference<ctkEventAdmin>();
	m_eventAdmin = qobject_cast<ctkEventAdmin*>(context->getService(eventRef));
	if (eventRef) {
		context->ungetService(eventRef);
	}

	m_path = QCoreApplication::applicationDirPath() + "/plugins";
	ctkPluginFrameworkLauncher::addSearchPath(m_path, true);
#if defined(Q_OS_WIN)
	m_libFilter << "*.dll";
#elif defined(Q_OS_LINUX)
	m_libFilter << "*.so";
#elif defined(Q_OS_MAC)
	m_libFilter << "*.dylib";
#endif
}

PluginAdminService::~PluginAdminService()
{
}

void PluginAdminService::installAllPlugin()
{
	QDirIterator dirIter(m_path, m_libFilter, QDir::Files);
	QString fileLocation;
	while (dirIter.hasNext()) {
		try {
			fileLocation = dirIter.next();
			if (!fileLocation.contains(QString("pluginadmin"))) {
				m_context->installPlugin(QUrl::fromLocalFile(fileLocation));
                qDebug() << QString::fromLocal8Bit("1.1 安装插件:") << fileLocation;
			}
			else {
                qDebug() << QString::fromLocal8Bit("1.2 未重复安装插件:") << fileLocation;
			}
		}
		catch (const ctkPluginException& exc) {
			qCritical() << fileLocation << exc.what();
		}
	}
}

void PluginAdminService::startAllPlugin()
{
	foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {
		try {
			if (QString("system.plugin") != plugin->getSymbolicName()
				&& QString("pluginadmin") != plugin->getSymbolicName()) {
				plugin->start();
                qDebug() << QString::fromLocal8Bit("2.1 启动插件:") << plugin->getSymbolicName();
			}
			else {
                qDebug() << QString::fromLocal8Bit("2.2 未重复启动插件:") << plugin->getSymbolicName();
			}
		}
		catch (const ctkPluginException& exc) {
			qCritical() << exc.what();
		}
	}
}

void PluginAdminService::stopAllPlugin()
{
	foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {
		try {
			if (QString("system.plugin") != plugin->getSymbolicName()
				&& QString("pluginadmin") != plugin->getSymbolicName()) {
                qDebug() << QString::fromLocal8Bit("3.1 停止插件:") << plugin->getSymbolicName();
				plugin->stop();
			}
			else {
                qDebug() << QString::fromLocal8Bit("3.2 未停止运行插件:") << plugin->getSymbolicName();
			}
		}
		catch (const ctkPluginException& exc) {
			qCritical() << exc.what();
		}
	}
}

void PluginAdminService::uninstallAllPlugin()
{
	foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {
		try {
			if (QString("system.plugin") != plugin->getSymbolicName()
				&& QString("pluginadmin") != plugin->getSymbolicName()) {
                qDebug() << QString::fromLocal8Bit("4.1 卸载插件:") << plugin->getSymbolicName();
				plugin->uninstall();
			}
		}
		catch (const ctkPluginException& exc) {
			qCritical() << exc.what();
		}
	}

	foreach(const QSharedPointer<ctkPlugin> &plugin, m_context->getPlugins()) {
        qDebug() << QString::fromLocal8Bit("4.2 未卸载插件:") << plugin->getSymbolicName();
	}
}

其实实现也不难,以安装插件的installAllPlugin函数实现为例,如果是windows,就是在应用程序的插件目录下面循环查找.dll文件,依次调用ctkPluginContext的installPlugin函数,安装插件,所以这个插件目录不能存放不是插件的.dll文件,否则就会出现安装异常。

启动器

pluginadminactivator.h

#ifndef PLUGINADMINACTIVATOR_H
#define PLUGINADMINACTIVATOR_H

#include "pluginadminthread.h"
#include "pluginadmindialog.h"

#include <ctkPluginActivator.h>

#include <QObject>

class PluginAdminActivator : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_INTERFACES(ctkPluginActivator)
    Q_PLUGIN_METADATA(IID "pluginadmin")

public:
    PluginAdminActivator();

    void start(ctkPluginContext* context) Q_DECL_OVERRIDE;
    void stop(ctkPluginContext* context) Q_DECL_OVERRIDE;

private:
    QThread *m_pluginAdminThread;
    PluginAdminDialog* m_pluginAdminDialog;
};

#endif // PLUGINADMINACTIVATOR_H

pluginadminactivator.cpp

#include "pluginadminactivator.h"
#include <QDebug>

PluginAdminActivator::PluginAdminActivator() :
	m_pluginAdminThread(nullptr)
{

}

void PluginAdminActivator::start(ctkPluginContext* context)
{
	qDebug() << "插件启动";
	m_pluginAdminThread = new PluginAdminThread(context);
	m_pluginAdminThread->start();

	m_pluginAdminDialog = new PluginAdminDialog(context);
    m_pluginAdminDialog->setWindowTitle(QString::fromLocal8Bit("插件管理器"));
    m_pluginAdminDialog->show();
}

void PluginAdminActivator::stop(ctkPluginContext* context)
{
	Q_UNUSED(context)
		if (m_pluginAdminThread)
		{
			m_pluginAdminThread->exit();
			m_pluginAdminThread->wait();
			m_pluginAdminThread->deleteLater();
			m_pluginAdminThread = nullptr;
		}
}

#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
Q_EXPORT_PLUGIN2(PluginAdmin, PluginAdminActivator)
#endif

3.实际应用

3.1.界面控制

PluginAdmin提供了一个简单的插件管理界面,加载PluginAdmin插件会弹出如图所示界面:

直接在界面就可以管理系统的所有插件了。

3.2.访问服务管理插件

跟CTK插件访问服务的方式一样,访问PluginAdmin提供的服务,一般在系统退出的时候调用,代码如下:

//系统退出函数
void MainWindow::closeEvent(QCloseEvent* e)
{
    ctkServiceReference reference = context->getServiceReference<PluginAdmin>();
	if (reference ) {
		PluginAdmin* pPluginManager = context->getService<PluginAdmin>(reference);
		assert(pPluginManager );
        pPluginManager->stopAllPlugin();
	}
}

4.总结

        PluginAdmin是CTK插件框架中的一个重要组件,它负责管理插件的生命周期和插件之间的交互。通过PluginAdmin,可以很方便的管理插件。这使得CTK插件框架能够支持高度模块化和可扩展的应用程序开发。

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

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

相关文章

Android SPN/PLMN 显示逻辑简介

功能描述 当设备驻网后(运营商网络),会在状态栏、锁屏界面、下拉控制中心显示运营商的名称。 此名称来源有两种: 1、SPN(Service Provider Name) 2、PLMN (Public Land Mobile Name) 功能AOSP默认逻辑SPN提供SIM卡的运营商名称预置在SIM EF中,SIM卡发行运营商名称…

GESP等级考试C++二级-ASCII码与字符

1 ASCII码介绍 ASCII码是American Standard Code for Information Interchange&#xff0c;即美国标准信息交换码的简称。 ASCII码的主要功能是将键盘上输入的字符&#xff08;如数字、字母、特殊符号等&#xff09;转换为计算机能够识别的二进制数&#xff0c;即每个字符都对…

Java 每日一刊(第5期):变量守护者

前言 这里是分享 Java 相关内容的专刊&#xff0c;每日一更。 本期将为大家带来以下内容&#xff1a; 量子数据宇宙的变量守护者第一章&#xff1a;能源错配与基本数据类型第二章&#xff1a;引用类型与通讯网络的崩溃第三章&#xff1a;作用域冲突与系统崩溃终章&#xff1…

C++的流提取(>>)(输入) 流插入(<<)(输出)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 什么是输入和输出流 流提取&#xff08;<<&#xff09;(输入) 理解&#xff1a;我们可以理解为&#xff0c;输入到io流里面&#xff0c;比如是cin&…

数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值特殊矩阵的压缩存储

文章目录 栈的应用1.栈的括号匹配代码实战:问题分析:2.栈的表达式求值2.1 中缀、后缀、前缀表达式2.2 中缀表达式改写为后缀表达式(手算)2.3 后缀表达式的计算(手算)2.4 中缀表达式转前缀表达式&#xff08;手算)和计算前缀表达式2.5后缀表达式的计算(机算)2.6 中缀表达式转后缀…

win10+eclipse+ESP8266_RTOS_SDK开发环境构建

官网教程 https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/get-started/eclipse-setup.html 1. 导入工程 Build and Flash with Eclipse IDE — ESP8266 RTOS SDK Programming Guide documentation (espressif.com) 导入整个SDK&#xff0c;便于查看所有代…

网络安全 day6 --- 抓包技术HTTPS协议小程序PC应用WEB转发联动

免责声明 本免责声明适用于作者所有文章内容。使用者需明确&#xff0c;网络安全技术仅供学习和合法研究使用&#xff0c;不得用于任何非法活动&#xff0c;如未经授权的入侵、攻击或数据窃取&#xff0c;所有相关法律责任由使用者自行承担。由于网络安全操作可能带来系统崩溃、…

智慧工地数据集-可移动生产要素检测与分割

智慧工地数据集&#xff0c;可移动生产要素检测与分割数据集篇&#xff0c;超高清数据&#xff0c;拍摄于武汉火神山&#xff0c;雷神山医院。包含13种工地中主要移动目标&#xff0c;Bulldozer - 推土机 Concrete mixer - 混凝土搅拌机 Crane - 起重机 Excavator - 挖掘机 Han…

jsp+servlet+mysql机票订票管理系统

jspsevletmysql机票订票管理系统 一、系统介绍二、功能展示1.机票查询2.选择航班3.填写乘客信息4.提交定单 四、其它1.其他系统实现 一、系统介绍 系统主要功能&#xff1a; 机票查询 1.航行类型 2.出发城市 3.到达城市 4.出发日期 5.返回日期 选择航班 1.航班信息 2.起飞时间…

瑞芯微rv1126 Linux 系统,修改系统时区,包有效方法

在 Linux 系统中,修改时区的步骤通常包括创建符号链接到正确的时区文件,并确保相关的配置文件已正确更新。然而,某些系统可能有额外的步骤或需要修改其他配置文件来使更改生效。以下是一些步骤。 1. 创建符号链接 ln -sf /usr/share/zoneinfo/Asia/Hong_Kong /etc/localti…

GitLab邮箱发送邮件:如何实现自动化发信?

gitlab邮箱发送邮件设置教程&#xff1f;Gitlab邮箱配置和使用&#xff1f; GitLab不仅提供了代码版本控制、持续集成/持续部署等功能&#xff0c;还支持通过其内置的邮件功能实现自动化邮件发送。AokSend将深入探讨如何在GitLab中配置和使用邮箱发送邮件功能。 GitLab邮箱发…

如何在 Selenium 中获取网络调用请求?

引言 捕获网络请求对于理解网站的工作方式以及传输的数据至关重要。Selenium 作为一种 Web 自动化工具,可以用于捕获网络请求。本文将讨论如何使用 Selenium 在 Java 中捕获网络请求并从网站检索数据。 我们可以使用浏览器开发者工具轻松捕获网络请求或日志。大多数现代 Web…

react18基础教程系列--安装环境及packagejson文件分析

一个React项目中&#xff0c;默认会安装: react:React框架的核心react-dom:React 视图渲染的核心「基于React构建WebApp(HTML页面)J—>react-native:构建和渲染App的react-scripts: 脚手架为了让项目目录看起来干净一些&#xff0c;把webpack打包的规则及相关的插件/LOADER…

一、链表-算法总结

文章目录 一、链表1.1 提纲1.2 链表删除1.2.1 删除排序链表中的重复元素&#xff08;仅保留一个重复元素&#xff09;1.2.2 删除排序链表中的重复元素 II &#xff08;删除所有重复的元素&#xff09; 1.3 链表反转1.3.1 反转链表1.3.2 反转链表 1.4 合并链表1.4.1 合并两个有序…

图新地球-将地图上大量的地标点批量输出坐标到csv文件【kml转excel】

0.序 有很多用户需要在卫星影像、或者无人机航测影像、倾斜模型上去标记一些地物的位置&#xff08;如电线杆塔、重点单位、下水盖等&#xff09; 标记的位置最终又需要提交坐标文本文件给上级单位或者其他部门使用&#xff0c;甚至需要转为平面直角坐标。 本文的重点是通过of…

第 1 0 章OpenCV

本章概述如何通过 Python 接口使用流行的计算机视觉库 OpenCV。OpenCV 是一个C 库&#xff0c;用于&#xff08;实时&#xff09;处理计算视觉问题。实时处理计算机视觉的 C 库&#xff0c;最初由英特尔公司开发&#xff0c;现由 Willow Garage 维护。OpenCV 是在 BSD 许可下发…

基于深度学习的医学图像分类与诊断系统(开题报告免费领)

深度学习开始大放异彩的工作&#xff0c;莫过于在ImageNet数据集上&#xff0c;对输入图片的分类了。只要输入图片&#xff0c;就能判断图片中主体所属的类别。然而&#xff0c;和分类问题输入图像输出主体的类别不一样&#xff0c;分割问题需要对每个像素点的类别进行识别。下…

Unity实现自己的协程系统(协程有顺序)

你的类可以在不继承Mono的脚本使用协程,但本质仍然需要借助其他Mono对象的Update来调度 实现了一个有执行顺序的协程的调度器&#xff0c;用于在 Unity 中管理多个协程的执行。通过 ICoroutineNodeOrder 和 ICoroutineWaitCondition 两个接口&#xff0c;可以定义每个协程的执行…

labview禁用8080端口

需求背景 最近电脑上安装了labview全家桶,发现idea的8080端口项目启动报错,一直提示8080端口被占用。最简单的办法就是找到8080端口的服务,然后关闭这个服务。但是我不想这么做,我想把labview的web服务器的端口给修改了。 操作教程 1、cmd查看8080端口 2、windows进程 同…

ICM20948 DMP代码详解(17)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;16&#xff09; 前一篇文章讲到了inv_icm20948_set_chip_power_state函数中尚需解析的3个函数中的第1个函数&#xff1a;inv_icm20948_write_single_mems_reg_core。并没有完全讲完&#xff0c;本回继续解析。为了便于…