CTK框架使用

2022-09-06 11:25:01 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

基于Qt的CTK框架的使用

QT的plugin插件的创建方式

在介绍CTK框架的使用方法之前我们首先介绍一下QT的plugin插件的创建方式。

QT提供两种API来创建插件:

  1. 扩展Qt库本身的高级API。例如:定制database drivers, image formats, text codecs, custom styles, etc.
  2. 扩展应用程序的低级API 如果你像创建一个可以在Qt Designer 下使用的插件,请查看Qt Designer module documentation 。

扩展应用程序的低级API:

不是只用Qt自己可以加载插件,Qt Application 也可以扩展插件。 qt加载插件使用QPluginLoader类来实现。

要扩展Qt Application 使用插件需要完成如下的步骤: 1. 定义一系列和插件调用的纯虚类来作为调用的接口 2. 使用 Q_DECLARE_INTERFACE() 注册接口到 元对象系统 3. 使用QpluginLoader 加载插件 4. 使用 qobject_cast() 测试该插件是否实现了该接口

要创建插件需要如下步骤: 1. 首先声明一个继承QObject和 插件接口类 2. 使用Q_INTERFACES() 注册接口到元对象系统 3. 使用Q_PLUGIN_METADATA()导出数据到元对象系统 4. 对。pro文件编译

示例代码:

代码语言:javascript复制
class FilterInterface
{
public:
    virtual ~FilterInterface() {}

    virtual QStringList filters() const = 0;
    virtual QImage filterImage(const QString &filter, const QImage &image,
                               QWidget *parent) = 0;
};

#include <QObject>
#include <QtPlugin>
#include <QStringList>
#include <QImage>

#include <plugandpaint/interfaces.h>

class ExtraFiltersPlugin : public QObject, public FilterInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface" FILE "extrafilters.json")
    Q_INTERFACES(FilterInterface)

public:
    QStringList filters() const;
    QImage filterImage(const QString &filter, const QImage &image,
                       QWidget *parent);
};

技术原理

插件就是动态库, 插件技术是使用c 中的多态,定义抽象类接口, 然后再PLugin中实现抽象类接口。 plugin可以动态加载, 动态更新。 可以实现应用的热插拔技术。 对内存的使用效率比较高。 当要使用的时候用interface 类指针指向 Plugin 就可以使用插件中的函数了。 CTK系统可以管理这些插件, 当需要的时候就可以直接从系统中获取相应的插件。 然后用想用的抽象接口指向这个插件就可以使用了。

技术框架

插件框架采用分层, 模块化管理。CTK系统可以管理插件的生命周期, 在运行时动态加载和卸载插件从而实现软件用的热插拔。 ctk框架就像是一个仓库来存储所有的插件, 要使用的时候只需要从仓库里拿出相应的插件实例就可以。而不用关系怎么找到这个实例, 怎么管理这个实例

技术使用

项目架构分析

每一个中型或大型的项目,在实际开发之前,其代码组织架构一定会经过仔细的规划,比如:目录架构(头文件放在哪个目录; lib库放在哪个目录;开发源代码放在哪个目录;生成的项目插件放在哪个目录;最终发布程序放在哪个目录)。 现在,假设我们要为图书馆开发一个图书管理程序,称之为:LibraryProject,然后在该文件夹下有:includes,libs,plugins,bin,application等文件夹。


其基本用途如下:applications用于放置项目加载程序的源码;bin下包含conf、plugins目录,bin下存放项目入口exe程序以及独立运行时依赖的dll文件, bin/conf下存放项目配置文件,bin/plugins下放置项目中所有使用到自己开发的插件;includes目录用于放置头文件,包括第三方头文件以及项目中自己定义的接口文件等; libs用于放置项目中使用的第三方开源库的lib文件;plugins用于放置项目中所有的插件开发源码;而base.pri是用来定义或加载项目中通用的内容, 比如:INCLUDEPATH在该文件中定义则在其它插件子项目中只要include一下这个文件,就可以使用includes中包含的所有头文件。

基于CTK框架的插件的编写规则
1 interface接口定义

首先是interface接口我们以后称之为service(服务) 该类是抽象类, 在c 里叫做纯虚类(如果不知到自己搜索 这里不做过多的介绍) 服务类的定义示例代码如下:

代码语言:javascript复制
#ifndef CONTROLPLUGIN_SERVICE_H
#define CONTROLPLUGIN_SERVICE_H
#include <qobject.h>
struct ControlPlugin_Service
{
public:
    virtual ~ControlPlugin_Service(){}
    virtual void init()=0;
};
Q_DECLARE_INTERFACE(ControlPlugin_Service, "org.commontk.pluginControl")

#endif // CONTROLPLUGIN_SERVICE_H  

代码语言:javascript复制
virtual ~ControlPlugin_Service(){}

析构函数我们定义成虚函数, 原因: 由于提供的接口只有服务类, 要使用插件的内容必须要服务类指针指向我们的实现类。
由于调用者没有我们的实现类的定义和声明所有不可能直接析构我们的实现类这样就可能造成内存泄漏, 
但是使用虚析构函数这样当析构这个服务类是就会自动析构对应的实现类的实例。

Q_DECLARE_INTERFACE(ControlPlugin_Service, "org.commontk.pluginControl")
//声明使用服务的接口和唯一id, 系统会定义一些宏函数
2服务类的实现

接下来就是我们服务类的实现了, 在这里我们必须继承QObject, 和服务类 并且声明接口Q_INTERFACE() //h

代码语言:javascript复制
class ControlPlugin_Plugin : public QObject, public ControlPlugin_Service
{
    Q_OBJECT
    Q_INTERFACES(ControlPlugin_Service)

public:
    ControlPlugin_Plugin(ctkPluginContext *pc);
    virtual void init();
};

#endif // CONTROLPLUGIN_PLUGIN_H

//cpp

代码语言:javascript复制
#include "controlplugin_plugin.h"
#include <ctkPluginContext.h>

#include <QDebug>
ControlPlugin_Plugin::ControlPlugin_Plugin(ctkPluginContext *pc)
{
    pc->registerService<ControlPlugin_Service>(this);
    //把服务类注册到我们的ctk系统供我们获取该类的实现类实例
}


void ControlPlugin_Plugin::init()
{
    qDebug()<<"hello";
}
3 ctkPluginActivator (ctk的生命周期类)

接下来是最重要的类 该类必须继承ctkPluginActivator (ctk的生命周期类), 里面函数得有start(), stop(), s是一个指向服务类的指针,该类析构后自动析构服务类。 //h

代码语言:javascript复制
#ifndef CONTROLSHARELIB_H
#define CONTROLSHARELIB_H

#include <ctkPluginActivator.h>
#include "controlplugin_service.h"

class  ControlShareLib : public QObject, public ctkPluginActivator
{
    Q_OBJECT
    Q_INTERFACES(ctkPluginActivator)

#if (QT_VERSION_MAJOR>4)
    Q_PLUGIN_METADATA(IID "ControlShareLibd")

#endif

public:
    void start(ctkPluginContext *contex);
    void stop(ctkPluginContext *context);
private:
    QScopedPointer<ControlPlugin_Service> s;
};
#endif // CONTROLSHARELIB_H

//cpp

代码语言:javascript复制
void ControlShareLib::start(ctkPluginContext *contex)
{
    s.reset(new ControlPlugin_Plugin(contex));
}
void ControlShareLib::stop(ctkPluginContext *context)
{
    Q_UNUSED(context)
}
4内部资源文件MANIFEST.MF 对插件的描述

资源路径名必须是 $TARGET/META-INF/MANIFEST.MF

例如生成库是 libplugin.so.0.0 TARGET是plugin

MANIFEST.MF 内容示例如下:

代码语言:javascript复制
Plugin-SymbolicName: ControlShareLib
Plugin-ActivationPolicy: eager
Plugin-Category: test
Plugin-ContactAddress: http://www.commontk.org
Plugin-Description: Test plugin for framework, ControlShareLib
Plugin-Name: ControlShareLib
Plugin-Vendor: CommonTK
Plugin-Version: 1.0.1

详细内容可以书写如下:

代码语言:javascript复制
const QString ctkPluginConstants::SYSTEM_PLUGIN_LOCATION = "System Plugin";
const QString ctkPluginConstants::SYSTEM_PLUGIN_SYMBOLICNAME = "system.plugin";

const QString ctkPluginConstants::FRAMEWORK_VERSION = "org.commontk.pluginfw.version";
const QString ctkPluginConstants::FRAMEWORK_VENDOR = "org.commontk.pluginfw.vendor";
const QString ctkPluginConstants::FRAMEWORK_STORAGE = "org.commontk.pluginfw.storage";
const QString ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN = "org.commontk.pluginfw.storage.clean";
const QString ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT = "onFirstInit";
const QString ctkPluginConstants::FRAMEWORK_PLUGIN_LOAD_HINTS = "org.commontk.pluginfw.loadhints";
const QString ctkPluginConstants::FRAMEWORK_PRELOAD_LIBRARIES = "org.commontk.pluginfw.preloadlibs";

const QString ctkPluginConstants::PLUGIN_SYMBOLICNAME = "Plugin-SymbolicName";
const QString ctkPluginConstants::PLUGIN_COPYRIGHT = "Plugin-Copyright";
const QString ctkPluginConstants::PLUGIN_DESCRIPTION = "Plugin-Description";
const QString ctkPluginConstants::PLUGIN_NAME = "Plugin-Name";
const QString ctkPluginConstants::PLUGIN_VENDOR = "Plugin-Vendor";
const QString ctkPluginConstants::PLUGIN_LOCALIZATION = "Plugin-Localization";
const QString ctkPluginConstants::PLUGIN_LOCALIZATION_DEFAULT_BASENAME = "CTK-INF/l10n/plugin";
const QString ctkPluginConstants::REQUIRE_PLUGIN = "Require-Plugin";
const QString ctkPluginConstants::PLUGIN_VERSION_ATTRIBUTE = "plugin-version";
const QString ctkPluginConstants::PLUGIN_VERSION = "Plugin-Version";
const QString ctkPluginConstants::PLUGIN_ACTIVATIONPOLICY = "Plugin-ActivationPolicy";
const QString ctkPluginConstants::PLUGIN_UPDATELOCATION = "Plugin-UpdateLocation";

const QString ctkPluginConstants::ACTIVATION_EAGER = "eager";
const QString ctkPluginConstants::ACTIVATION_LAZY = "lazy";

const QString ctkPluginConstants::RESOLUTION_DIRECTIVE = "resolution";
const QString ctkPluginConstants::RESOLUTION_MANDATORY = "mandatory";
const QString ctkPluginConstants::RESOLUTION_OPTIONAL = "optional";


const QString ctkPluginConstants::OBJECTCLASS = "objectclass";

// ATTENTION!!! If the value is changed, change also ctkEventConstants::SERVICE_ID
const QString ctkPluginConstants::SERVICE_ID = "service.id";

// ATTENTION!!! If the value is changed, change also ctkEventConstants::SERVICE_PID
const QString ctkPluginConstants::SERVICE_PID = "service.pid";

const QString ctkPluginConstants::SERVICE_RANKING = "service.ranking";
const QString ctkPluginConstants::SERVICE_VENDOR = "service.vendor";
const QString ctkPluginConstants::SERVICE_DESCRIPTION = "service.description";
5最后附上Qt的工程文件。
代码语言:javascript复制
#-------------------------------------------------
#
# Project created by QtCreator 2016-12-27T16:04:46
#
#-------------------------------------------------

QT       -= gui

TEMPLATE = lib                          //生成目标为库
CONFIG  = c  11                         //支持c  11
DEFINES  = CONTROLSHARELIB_LIBRARY
DESTDIR = $$PWD/../../bin/plugins     //生成插件的存放路径
SOURCES  = controlsharelib.cpp 
    controlplugin_plugin.cpp

HEADERS  = controlsharelib.h
    controlplugin_plugin.h 
    controlplugin_service.h

unix {
    target.path = /usr/lib
    INSTALLS  = target
}

INCLUDEPATH  = $$PWD/../../include/ctkH 	//需要用到的头文件路径
	LIBS  = -L$$PWD/../../bin  -lCTKCore  -lCTKPluginFramework  //需要用到库文件路径

RESOURCES  = 
    controlsharelib.qrc

ctkPluginContext 详解

类作用:ctkPluginContext 是一个在框架内部的插件执行上下文。 该上下文可以存取其它插件的方法, 实现插件间的通信。

内部方法作用如下:

  1. 通过框架发送事件。
  2. 用框架服务注册服务类。
  3. 从框架注册服务中检索服务引用 (ServiceReferences)
  4. 获取和释放一个参考的引用
  5. 安装插件到服务
  6. 获取框架中更新的插件列表
  7. 获取一个插件 ctkPlugin 类
  8. 通过框架为plugin创建一个flile存储在数据库里

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/134936.html原文链接:https://javaforall.cn

0 人点赞