CTK Plugin Framework插件框架学习--服务追踪

news2025/1/18 3:29:22

文章目录

  • 一、前言
  • 二、新建插件PluginA
  • 三、新建插件PluginB
  • 四、测试

一、前言

服务追踪:如果想在B插件里使用A服务,可以专门写一个类继承ctkServiceTracker,在这个类里完成对A服务的底层操作,然后在B插件里通过这个类提供的接口来使用回收A服务


二、新建插件PluginA

在这里插入图片描述
插件结构

  • PluginAService:接口类
  • PluginAImpl:实现类
  • PluginAActivator:激活类

接口类PluginAService

#ifndef PLUGINA_SERVICE_H
#define PLUGINA_SERVICE_H

#include <QtPlugin>

class PluginAService
{
public:
    virtual ~PluginAService() {}
    virtual void A_Func() = 0;
};

#define PluginAService_iid "org.commontk.service.demos.PluginAService"
Q_DECLARE_INTERFACE(PluginAService, PluginAService_iid)
//此宏将当前这个接口类声明为接口,后面的一长串就是这个接口的唯一标识。
#endif // PLUGINA_SERVICE_H


实现类PluginAImpl

#ifndef PLUGINA_IMPL_H
#define PLUGINA_IMPL_H

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

class ctkPluginContext;

class PluginAImpl : public QObject, public PluginAService
{
    Q_OBJECT
    Q_INTERFACES(PluginAService)
    /*
    此宏与Q_DECLARE_INTERFACE宏配合使用。
    Q_DECLARE_INTERFACE:声明一个接口类
    Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
    */

public:
    PluginAImpl(ctkPluginContext* context);
    void A_Func() Q_DECL_OVERRIDE;
};

#endif // PLUGINA_IMPL_H

#include "plugina_impl.h"
#include <QtDebug>

PluginAImpl::PluginAImpl(ctkPluginContext* context)
{

}

void PluginAImpl::A_Func()
{
    qDebug() << "A_Func()";
}


激活类PluginAActivator

#ifndef PLUGINAACTIVATOR_H
#define PLUGINAACTIVATOR_H

#include <QObject>
#include "ctkPluginActivator.h"
#include "PluginAService.h"

class PluginAActivator : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_INTERFACES(ctkPluginActivator)
    Q_PLUGIN_METADATA(IID "PLUGINA")
    //向Qt的插件框架声明,希望将xxx插件放入到框架中。

public:
    void start(ctkPluginContext* context);
    void stop(ctkPluginContext* context);

private:
    QSharedPointer<PluginAService> m_s;
};

#endif // PLUGINAACTIVATOR_H

#include "plugina_activator.h"
#include "plugina_impl.h"
#include <QDebug>

void PluginAActivator::start(ctkPluginContext* context)
{
    PluginAImpl* pluginAImpl = new PluginAImpl(context);
    context->registerService<PluginAService>(pluginAImpl);
    m_s.reset(pluginAImpl);
}

void PluginAActivator::stop(ctkPluginContext* context)
{
    Q_UNUSED(context)
    //Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用
}


三、新建插件PluginB

因为真正使用到A服务的地方就是B插件的实现类里,所以通过构造函数把tracker给传进去。这里的tracker是在激活类里new的,因为context是从实现类里传进来的,根据这个思路也可把context传到B的实现类里,再在实现类里new出tracker

在这里插入图片描述
插件结构

  • PluginBService:接口类
  • PluginBImpl:实现类
  • PluginBActivator:激活类
  • ServiceTracker:追踪类

接口类PluginAService

#ifndef PLUGINB_SERVICE_H
#define PLUGINB_SERVICE_H

#include <QtPlugin>

class PluginBService
{
public:
    virtual ~PluginBService() {}
    virtual void B_Func() = 0;
};

#define PluginBService_iid "org.commontk.service.demos.PluginBService"
Q_DECLARE_INTERFACE(PluginBService, PluginBService_iid)
//此宏将当前这个接口类声明为接口,后面的一长串就是这个接口的唯一标识。
#endif // PLUGINB_SERVICE_H


实现类PluginAImpl

#ifndef PLUGINB_IMPL_H
#define PLUGINB_IMPL_H

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

class ServiceTracker;

class PluginBImpl : public QObject, public PluginBService
{
    Q_OBJECT
    Q_INTERFACES(PluginBService)
    /*
    此宏与Q_DECLARE_INTERFACE宏配合使用。
    Q_DECLARE_INTERFACE:声明一个接口类
    Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
    */

public:
    PluginBImpl(ServiceTracker *tracker);
    void B_Func() Q_DECL_OVERRIDE;

private:
    ServiceTracker *m_pTracker;
};

#endif // PLUGINB_IMPL_H

#include "pluginb_impl.h"
#include <QtDebug>
#include "../PluginA/PluginAService.h"
#include "ServiceTracker.h"

PluginBImpl::PluginBImpl(ServiceTracker *tracker)
    : m_pTracker(tracker)
{

}

void PluginBImpl::B_Func()
{
    PluginAService* service = static_cast<PluginAService*>(m_pTracker->getService());
    if (service != Q_NULLPTR) {
        service->A_Func();
    }else {
        qDebug()<<"get AbsPrintServer from tracker failed";
    }
}


激活类PluginAActivator

#ifndef PLUGINBACTIVATOR_H
#define PLUGINBACTIVATOR_H

#include <QObject>
#include "ctkPluginActivator.h"
#include "PluginBService.h"

class PluginBImpl;
class ServiceTracker;

class PluginBActivator : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_INTERFACES(ctkPluginActivator)
    Q_PLUGIN_METADATA(IID "PLUGINB")
    //向Qt的插件框架声明,希望将xxx插件放入到框架中。

public:
    void start(ctkPluginContext* context);
    void stop(ctkPluginContext* context);

private:
    PluginBImpl *m_pPlugin;
    ServiceTracker* m_pTracker;
    ctkServiceRegistration m_registration;
};

#endif // PLUGINBACTIVATOR_H

#include "pluginb_activator.h"
#include "pluginb_impl.h"
#include "ServiceTracker.h"
#include "pluginb_impl.h"
#include <QDebug>

void PluginBActivator::start(ctkPluginContext* context)
{
    // 开启服务跟踪器
    m_pTracker = new ServiceTracker(context);
    m_pTracker->open();

    m_pPlugin = new PluginBImpl(m_pTracker);
    m_registration = context->registerService<PluginBService>(m_pPlugin);
}

void PluginBActivator::stop(ctkPluginContext* context)
{
    Q_UNUSED(context)
    //Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用

    // 注销服务
    m_registration.unregister();

    // 关闭服务跟踪器
    m_pTracker->close();

    delete m_pPlugin;
    m_pPlugin = Q_NULLPTR;
}


追踪类ServiceTracker

#ifndef SERVICETRACKER_H
#define SERVICETRACKER_H

#include <ctkPluginContext.h>
#include <ctkServiceTracker.h>
#include "../PluginA/PluginAService.h"

class ServiceTracker : public ctkServiceTracker<PluginAService *>
{
public:
    ServiceTracker(ctkPluginContext* context) : ctkServiceTracker<PluginAService *>(context) {}
    ~ServiceTracker() {}

protected:
    // 在 Service 注册时访问
    PluginAService* addingService(const ctkServiceReference& reference) Q_DECL_OVERRIDE {
        qDebug() << "Adding service:" << reference.getPlugin()->getSymbolicName();
        PluginAService* service = (PluginAService*)(ctkServiceTracker::addingService(reference));
        return service;
    }

    void modifiedService(const ctkServiceReference& reference, PluginAService* service) Q_DECL_OVERRIDE {
        qDebug() << "Modified service:" << reference.getPlugin()->getSymbolicName();
        ctkServiceTracker::modifiedService(reference, service);
    }

    void removedService(const ctkServiceReference& reference, PluginAService* service) Q_DECL_OVERRIDE {
        qDebug() << "Removed service:" << reference.getPlugin()->getSymbolicName();
        ctkServiceTracker::removedService(reference, service);
    }
};


#endif // SERVICETRACKER_H


四、测试

我们在B插件的实现类中的B_Func()接口中,通过服务追踪调用了服务A的接口A_Func(),如下:

在这里插入图片描述

启用插件,然后调用B_Func(),修改main.cpp,添加如下代码段

//启用A插件
try {
	// 安装插件
    QString PluginA_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginA/bin/plugins/PluginA.dll";
    QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginA_dir));
    qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
    // 启动插件
    plugin->start(ctkPlugin::START_TRANSIENT);
    qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
	qDebug() << QString("Failed install or run plugin: ") << e.what();
    return -2;
}

//启用B插件
try {
	// 安装插件
    QString PluginB_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginB/bin/plugins/PluginB.dll";
    QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginB_dir));
    qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
    // 启动插件
    plugin->start(ctkPlugin::START_TRANSIENT);
    qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {
    qDebug() << QString("Failed install or run plugin: ") << e.what();
    return -2;
}

// 获取服务引用
ctkServiceReference reference = pluginContext->getServiceReference<PluginBService>();
if (reference) {
	// 获取指定 ctkServiceReference 引用的服务对象
    PluginBService* service = pluginContext->getService<PluginBService>(reference);
    if (service != Q_NULLPTR) {
    	// 调用服务
        service->B_Func();
    }
}

main.cpp完整代码:

#include "mainwindow.h"

#include <QApplication>

#include "ctkPluginFrameworkFactory.h"
#include "ctkPluginFramework.h"
#include "ctkPluginException.h"
#include "ctkPluginContext.h"
#include "ctkPluginFrameworkLauncher.h"
#include <QDebug>

#include "../HelloCTK/HelloService.h"
#include "event_listener.h"
#include "../PluginA/PluginAService.h"
#include "../PluginB/PluginBService.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    a.setApplicationName("CTK_PluginFramework");//给框架创建名称,Linux下没有会报错

    ctkPluginFrameworkFactory frameworkFactory;
    QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework();

    // 初始化并启动插件框架
    try {
        framework->init();
        framework->start();
        qDebug() << "======================================";
        qDebug() << "CTK plugin framework start...";
        qDebug() << "======================================";
    } catch (const ctkPluginException &e) {
        qDebug() << "CTK plugin framework init err: " << e.what();
        return -1;
    }

    // 获取插件服务的contex
    ctkPluginContext* pluginContext = framework->getPluginContext();

    //---------------------------------------------------------------------------------------------------------------------------------------
    //注册事件调用

    //启用A插件
    try {
        // 安装插件
        QString PluginA_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginA/bin/plugins/PluginA.dll";
        QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginA_dir));
        qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
        // 启动插件
        plugin->start(ctkPlugin::START_TRANSIENT);
        qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
    } catch (const ctkPluginException &e) {
        qDebug() << QString("Failed install or run plugin: ") << e.what();
        return -2;
    }

    //启用B插件
    try {
        // 安装插件
        QString PluginB_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/PluginB/bin/plugins/PluginB.dll";
        QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginB_dir));
        qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
        // 启动插件
        plugin->start(ctkPlugin::START_TRANSIENT);
        qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
    } catch (const ctkPluginException &e) {
        qDebug() << QString("Failed install or run plugin: ") << e.what();
        return -2;
    }

    // 获取服务引用
    ctkServiceReference reference = pluginContext->getServiceReference<PluginBService>();
    if (reference) {
        // 获取指定 ctkServiceReference 引用的服务对象
        PluginBService* service = pluginContext->getService<PluginBService>(reference);
        if (service != Q_NULLPTR) {
            // 调用服务
            service->B_Func();
        }
    }

    // 停止插件
    //ctkPluginFrameworkLauncher::stop();

    //---------------------------------------------------------------------------------------------------------------------------------------

    MainWindow w;
    w.show();

    return a.exec();
}

在这里插入图片描述
可以看到在插件B中成功通过服务追踪,调用了服务A的接口A_Func()

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

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

相关文章

重庆市市长胡衡华会见深兰科技董事长陈海波一行

1月9日&#xff0c;重庆市市长胡衡华会见了赴渝考察调研的深兰科技集团创始人、董事长陈海波一行&#xff0c;双方就开展互利合作进行了深入交流。胡衡华市长会见深兰科技考察团重庆市委常委、副市长陈鸣波&#xff0c;市政府秘书长、办公厅主任欧顺清&#xff0c;市政府副秘书…

ResT: An Efficient Transformer for Visual Recognition

文章地址: https://arxiv.org/pdf/2105.13677.pdf codeResT: An Efficient Transformer for Visual Recognition一、引言二、ResT一、Transformer模块的再思考二、Efficient Transformer Block三、Patch Embedding四、Positional Encoding五、整体架构三、实验一、分类二、目标…

go import package 入门lib1 is not in GOROOT

main.go:4:2: package lib1 is not in GOROOT (/usr/local/go/src/lib1)├── 5-init│ ├── lib1│ │ └── lib1.go│ └── lib2│ └── lib2.go├── const.go├── firstVar.go├── go.mod├── helloGolang.go├── main.go└── test3function.gogo env …

Java学习之单例设计模式

目录 设计模式 单例模式 一、饿汉式 二、懒汉式 三、饿汉式VS懒汉式 总结 设计模式 1.静态方法和属性的经典使用 2.设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。就像是经典的棋谱&#xff0c;不同的棋局&#xff0c;我们用…

连接查询之外连接(左外链接和右外连接)

内连接&#xff1a; 假设A表和B表进行连接查询&#xff0c;使用内连接的话&#xff0c;凡是A表和B表能够匹配上的记录被查询出来&#xff0c;这就是内连接。A、B两张表没有主副之分&#xff0c;两张表是平等的。 外连接&#xff1a; 假设A表和B表进行连接查询&#xff0c;使用…

对于html中div标签height属性的个人理解

对于没有系统学习过css的程序员来说&#xff0c;在编写css样式的时候&#xff0c;div的height属性值确实是个玄学的东西&#xff0c;我也感觉css确实挺玄学的&#xff0c;本文将介绍我对div标签height属性的个人理解&#xff0c;如有问题请指正。 在html中&#xff0c;div标签属…

xilinx srio ip学习笔记之srio example

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 xilinx srio ip学习笔记之srio example前言IP的配置例程前言 前面对SRIO的理论有了初步的理解&#xff0c;现在急需要通过理解例程并且修改例程来建立自信心了。 学东西确实…

Java版本TransH代码的学习

主要讲和TransE代码的区别&#xff0c;TransE文章的链接 Java版本TransE代码的学习 关于范数的概念 什么是0范数、1范数、2范数&#xff1f;区别又是什么 初始化向量 初始化关系平面的向量Wr&#xff0c;初始化向量relation_vec,初始化节点向量entity_vec Wr_vec new doub…

富豪酒店集团全新体验「METAGREEN」上线!边玩边赚,了解可持续发展!

富豪酒店集团推出 MetaGreen 以提高大众对可持续发展的认识&#xff0c;并创造一个多元化的绿色生态系统。 体验将包涵盖数个独特的互动地标&#xff0c;包括环保富豪酒店、大华银行艺术空间、恒生银行元宇宙分行&#xff0c;以及 citysuper、LOG-ON 和 The Mills 等零售商。 …

擎创技术流 | ClickHouse实用工具—ckman教程(9)

哈喽~大家好&#xff0c;时间倏然&#xff0c;上一次ckman分享还是在2022&#xff0c;这一期分享就已经是2023了。由于前段时间小编“成功加入羊群”&#xff0c;导致拖更一周&#xff0c;实在抱歉。希望新的一年大家都可以身体健健康康&#xff0c;事业红红火火&#xff0c;生…

Clarifying Question领域最常见的三个数据集

文章目录Qulacqulac.json:qulac_hist012_dict.tar.gz:MIMICSClariQConvAI3 Data ChallengeStage1: initial datasetStage2: human-in-the-loopClariQ DatasetFile Formattrain.tsv and dev.tsvtest.tsvquestion_bank.tsvdev_synthetic.pkl.tar.gz & train_synthetic.pkl.ta…

【进阶】Spring核心思想及其项目创建

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录一、Spring核心思想1. 容器2. IoC3. SpringIoC4. DI概念说明二、Spring的创建和使用1. 创建Spring项目3. Maven项目导入jar包和设置国内源的方法&#xff1a;2. Spring对象的存储/存储Bean对象3. 从Spring中读取到Be…

Electron自定义协议Protocol对web网站做数据交互,使用SSE实时数据推送到网站

(防盗镇楼)本文地址:https://blog.csdn.net/cbaili/article/details/128651549 前言 最近在撸VUE,想要实现一份代码既能构建Web又能构建Electron应用 并且能够判断环境是浏览器还是Electron,随后在Electron中做一些特定的事情 以往的Electron通信依靠IPC通信完成,但是发布到…

模板(template)包含与继承

Django 模板查找机制&#xff1a; Django 查找模板的过程是在每个 app 的 templates 文件夹中找&#xff08;而不只是当前 app 中的代码只在当前的 app 的 templates 文件夹中找&#xff09;。各个 app 的 templates 形成一个文件夹列表&#xff0c;Django 遍历这个列表&#x…

超详细的Socket通信原理和实例讲解

我们深谙信息交流的价值&#xff0c;那网络中进程之间如何通信&#xff0c;如我们每天打开浏览器浏览网页时&#xff0c;浏览器的进程怎么与web服务器通信的&#xff1f;当你用QQ聊天时&#xff0c;QQ进程怎么与服务器或你好友所在的QQ进程通信&#xff1f;这些都得靠socket&am…

【算法篇-排序】八大排序

十大排序0.常见排序1. 插入排序&#xff08;直接插入排序和希尔排序&#xff09;1.1直接插入排序1.2希尔排序&#xff08;缩小增量排序&#xff09;2.选择排序2.1选择排序2. 2堆排序3.交换排序3.1 冒泡排序3.2快速排序3.2.1hoare版本快排3.2.2挖坑法3.2.3前后指针法3.3.4 快排的…

【Linux】在Linux上写一个进度条小程序

&#x1f451;作者主页&#xff1a;安 度 因 &#x1f3e0;学习社区&#xff1a;安度因的学习社区 &#x1f4d6;专栏链接&#xff1a;Linux 文章目录一、前言二、理解 \r 与 \n三、行缓冲1、提出问题2、认识行缓冲3、解答与拓展4、倒计时四、进度条五、结语如果无聊的话&#…

2023/1/12总结

今天学习了图的割点与桥的算法 图的割点以及桥 图的割点&#xff1a;割点是指在无向连通图中&#xff0c;某点和该点连接的边去掉以后图便不再连通 在上面的图片中&#xff08;上面是一个有向图&#xff0c;我们当作无向图即可&#xff09;我们知道当我们去掉A点之后&#xf…

进阶必看 | 6个让Revit建模起飞的习惯,高效就靠它

大家好&#xff0c;这里是建模助手。 相信各位都知道&#xff0c;建模助手一向以来都追求更高&#xff0c;更快&#xff0c;更强。但是有些问题&#xff0c;不是插件本身能解决的事情&#xff0c;而是项目本身的问题。 一般来说&#xff0c;当Revit项目模型大于150MB时&#…

Linux安装sonarqube(含各种错误处理)

目录 1.下载安装 2.错误处理 2.1.JDK版本不适配 2.2.can not run elasticsearch as root 1.下载安装 下载地址&#xff1a; Download | SonarQube | Sonar &#xff08;下载页面向下拉&#xff09;选择稳定版本下载。 解压后启动脚本在&#xff1a; bin/{对应操作系统}…