Qt基于CTK Plugin Framework搭建插件框架--创建插件

news2024/11/27 7:44:10

文章目录

  • 一、前言
  • 二、工程搭建
    • 2.1、新建Qt工程
    • 2.2、CTK环境配置
  • 三、CTK Plugin Framework使用
    • 3.1、主函数启动插件框架
    • 3.2、插件的创建
    • 3.3、插件的使用

一、前言

CTK保姆级编译教程:https://blog.csdn.net/Mr_robot_strange/article/details/128547331?spm=1001.2014.3001.5501


二、工程搭建

2.1、新建Qt工程

Qt 新建【子目录项目】,项目命名为为CTK_PluginFramework

在这里插入图片描述

然后继续新建子项目【Application】,作为主项目,项目结构如下图所示:

在这里插入图片描述


2.2、CTK环境配置

1、将CTK编译生成的CTK文件夹复制到工程目录下,例如:

在这里插入图片描述


2、将源码文件夹下的 CTK-master/Libs/PluginFramework 文件夹复制到刚刚复制的CTK文件夹下,例如:

在这里插入图片描述


3、在CTK文件夹下新建CTK_dependency.pri,并添加如下内容:

# CTK 安装路径
CTK_INSTALL_PATH = $$PWD/../CTK

# CTK 相关库所在路径(例如:CTKCore.CTKPluginFramework.lib)
CTK_LIB_PATH = $$CTK_INSTALL_PATH/lib/ctk-0.1

# CTK 相关头文件所在路径(例如:ctkPluginFramework.h)
CTK_INCLUDE_PATH = $$CTK_INSTALL_PATH/include/ctk-0.1

# CTK 插件相关头文件所在路径(主要因为用掉了service相关东西)
CTK_INCLUDE_FRAMEWORK_PATH = $$PWD/PluginFramework

# 相关库文件(CTKCore.lib、CTKWidgets.lib)
LIBS += -L$$CTK_LIB_PATH -lCTKCore -lCTKPluginFramework

INCLUDEPATH += $$CTK_INCLUDE_PATH \
               $$CTK_INCLUDE_FRAMEWORK_PATH


4、在Application.pro中导入CTK_dependency.pri

在这里插入图片描述


三、CTK Plugin Framework使用

3.1、主函数启动插件框架

main.cpp

#include "mainwindow.h"

#include <QApplication>

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

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() << "CTK Plugin Framework start ...";
    } catch (const ctkPluginException &e) {
        qDebug() << "Failed to initialize the plugin framework: " << e.what();
        qDebug() << e.message() << e.getType();
    }

    MainWindow w;
    w.show();

    return a.exec();
}

  • QSharedPointer<ctkPluginFramework> framework:这个对象既可以作为对象,也可以作为对象指针,但要作为插件框架使用必须要用指针方法调用,所以代码里用“->”

在这里插入图片描述

注意:如果吧CTK初始化、插件安装启动、获取等操作封装成一个类,则需要把CTK相关的变量定义成类属性,不能是局部变量,否则会出现各种问题,例如获取不了服务、服务引用为空等;


3.2、插件的创建


CTK框架由一个一个可分离的插件组成,框架对插件识别有一定要求;

  • ctk插件都有自己的注册器Activator,继承自QObject和ctkPluginActivator的一个类,并实现ctkPluginActivator的start、stop函数;
  • ctk插件必须有一个资源文件(名字无所谓),前缀必须是【TARGET/META-INF】,即插【插件名/META_INF】;
  • ctk插件有一个元数据文件,名字固定为【MANIFEST.MF】,需要将其导入资源文件【TARGET/META-INF】中;

1、创建插件子项目,命名为【HelloCTK】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


2、HelloCTK.pro中添加如下内容

QT += core
QT -= gui

TEMPLATE = lib
CONFIG += plugin
TARGET = HelloCTK
DESTDIR = $$OUT_PWD/bin/plugins

include($$PWD/../CTK/CTK_dependency.pri)

注意:生成的插件名(TARGET)不要有下划线,因为CTK会默认将插件名中的下划线替换为点号,最后就导致找不到插件

在这里插入图片描述


3、新建C++类HelloActivator(注册器)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

修改HelloActivator代码如下:

#ifndef HELLOACTIVATOR_H
#define HELLOACTIVATOR_H

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

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

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

#endif // HELLOACTIVATOR_H

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

void HelloActivator::start(ctkPluginContext* context)
{
    qDebug() << "HelloCTK start";
}

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


4、新建资源文件qrc

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:Plugin-SymbolicName要满足这里的前缀是:TARGET/META-INF格式。TARGET的名字最好和工程名一致,不然可能出现device not open错误。

在HelloCTK文件夹中新建MANIFEST.MF文件,并加入如下内容:

插件加载后会寻找【同名前缀/META-INF】,所以前缀格式固定,可直接在MF文件里添加自己特有的元数据

Plugin-SymbolicName:HelloCTK
Plugin-Version:1.0.0
Plugin-Number:100 #元数据

在这里插入图片描述

MANIFEST.MF文件加入资源文件中

在这里插入图片描述

MANIFEST.MF文件包含ctk插件的基本信息,只要ctk框架正常识别到文件中Plugin-SymbolicName等信息,则判定它是一个ctk插件,能够正常调用activator中的start、stop函数。

MANIFEST.MF拷贝到插件生成路径下:

在这里插入图片描述

在HelloCTK.pro中添加代码:

file.path = $$DESTDIR
file.files = MANIFEST.MF
INSTALLS += file

在这里插入图片描述


3.3、插件的使用

右键HelloCTK–>【执行qmake】–>【构建“HelloCTK”】
在这里插入图片描述
在这里插入图片描述

检查生成了HelloCTK.dll

在这里插入图片描述

修改main.cpp

#include "mainwindow.h"

#include <QApplication>

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

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() << "CTK plugin framework start...";
    } catch (const ctkPluginException &e) {
        qDebug() << "CTK plugin framework init err: " << e.what();
        return -1;
    }

    // 获取插件服务的contex
    ctkPluginContext* pluginContext = framework->getPluginContext();
    try {
        // 安装插件
        QString HelloCTK_dir = "C:/Qt_Pro/build-CTK_PluginFramework-CMake-Debug/HelloCTK/bin/plugins/HelloCTK.dll";
        QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(HelloCTK_dir));
        qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
        // 启动插件
        plugin->start(ctkPlugin::START_TRANSIENT);
        qDebug() << "Plugin start...";
    } catch (const ctkPluginException &e) {
        qDebug() << QString("Failed install or run plugin: ") << e.what();
        return -2;
    }

    MainWindow w;
    w.show();

    return a.exec();
}

运行,成功调用HelloCTK中start内打印输出,则表明ctk插件接口正常定义并能成功加载。

其中start(ctkPlugin::START_TRANSIENT)表示立即启用插件,不设置参数的话加载后也不会立即打印输出。

在这里插入图片描述

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

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

相关文章

JavaGUI:多功能计算器(五)--Swing实现双语数据包+菜单切换(完整源码)

JavaGUI&#xff1a;多功能计算器&#xff08;五&#xff09;–Swing实现双语数据包菜单切换&#xff08;完整源码&#xff09; 【背景提示】 “软件国际化”就是实现多种语言显示切换。 1.在前端网页上&#xff0c;可通过探测本地化语言环境实现自动切换&#xff1b; 2.在操…

C++ 20 原子引用 (一)

C 20 原子引用 &#xff08;一&#xff09; std::atomic_ref{} std::atomic_ref类型对其引用的对象进行原子操作。 使用std::atomic_ref 进行多线程读写时不会造成数据争用。被引用对象的生命周期必须超过std::atomic_ref 。操作std::atomic_ref 的子对象是未定义行为。 错…

Docker版RabbitMQ安装延迟队列插件及延迟队列项目应用实战

前言 在项目中经常有延迟业务处理的背景&#xff0c;此时可以借助于Rabbitmq的延迟队列进行实现&#xff0c;但Rabbitmq本身并不支持延迟队列&#xff0c;但可以通过安装插件的方式实现延迟队列 环境准备 首先确认目前项目使用的Rabbitmq的版本&#xff0c;这里博主的版本是3.…

STM32系列(HAL库)——使用ESP8266-01S物联网模块连接Onenet云平台上报DHT11温湿度

前言 本篇主要讲解如何使用ESP8266-01S物联网模块连接Onenet云平台&#xff0c;并上报DHT11模块的温湿度数据。本文单片机主控采用STM32F405RGT6&#xff0c;使用其他主控的话基本要求有2个串口&#xff0c;一个串口用于调试使用&#xff0c;另一个用于ESP模块通讯。 一、前…

SOLIDWORKS 2023工程图和出详图新功能 创建更智能化 更高精度的工程详图

工程图是传达您设计意图的重要文档&#xff0c;您设计的产品越复杂&#xff0c;越需要详细注释说明。SOLIDWORKS 2023增强的工程图和出详图功能将帮助您创建更智能化、更高精度的工程详图&#xff0c;并且扩展新功能使您的设计工作延伸到更多的业务领域。您现在可以从更高层级的…

C 程序设计教程(15)—— 选择结构程序设计练习题

C 程序设计教程&#xff08;15&#xff09;—— 选择结构程序设计练习题 该专栏主要介绍 C 语言的基本语法&#xff0c;作为《程序设计语言》课程的课件与参考资料&#xff0c;用于《程序设计语言》课程的教学&#xff0c;供入门级用户阅读。 目录C 程序设计教程&#xff08;1…

20230110配置ubuntu18.04为开机自动登录

20230110配置ubuntu18.04为开机自动登录 百度搜索&#xff1a;ubuntu 18.04 开机自动登录 https://blog.csdn.net/yang1994/article/details/124446319 通过配置文件启用/禁用Ubuntu 18.04自动登录 超级用户可以通过编辑custom.conf配置文件的方式&#xff0c;来为自己或任何其…

计算机如何存储浮点数和定点数?

1 浮点数的不精确性 能不能用二进制表示所有实数&#xff0c;然后在二进制下计算它的加减乘除呢&#xff1f; 打开Chrome Console&#xff0c;输入0.3 0.6&#xff1a; 简单加法在js算出结果居然不是准确的0.9&#xff0c;而是0.8999999999999999&#xff0c;why&#xff1…

火山语音丨AI创作惊艳四方 诸多挑战仍在路上

2022年8月&#xff0c;一幅名为《太空歌剧院》的数字画作获得冠军同时引发了巨大争议&#xff0c;AIGC&#xff08;AI产生内容&#xff1a;AI-Generated Content&#xff09;出圈的事件便频频出现在大众视野。同年11月30日OpenAI发布的聊天机器人模型ChatGPT免费开放&#xff0…

从0到1完成一个Vue后台管理项目(二十、地图涟漪、线图)

往期 从0到1完成一个Vue后台管理项目&#xff08;一、创建项目&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;二、使用element-ui&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;三、使用SCSS/LESS&#xff0c;安装图标库&#xff09; 从0到1完成一个Vu…

缓存穿透、布隆过滤器、布谷鸟过滤器

1.概述 缓存穿透&#xff1a; 当查询的数据在缓存&#xff08;redis&#xff09;中没有时&#xff0c;一般业务上就会去查询数据存储&#xff08;数据库&#xff09;&#xff0c;这种情况称为缓存穿透。穿透的数量太大会造成数据存储撑不住&#xff08;数据库&#xff09;而宕…

基于控制器软件需求事项进行单元测试和单元测试规范

基于需求事项的单元测试是什么&#xff1f; ​ 大多数汽车行业都遵循 ISO 26262 中定义的标准&#xff0c;这是 ISO 制定的汽车功能安全国际标准。 根据 ISO 26262 标准软件单元测试 (ISO 26262-6-9)&#xff0c;单元验证是验证要验证的单元&#xff08;功能或功能&#xff09…

智能优化算法应用:基于蜣螂优化算法的工程优化案例

智能优化算法应用&#xff1a;基于蜣螂算法的工程优化案例 文章目录智能优化算法应用&#xff1a;基于蜣螂算法的工程优化案例1.蜣螂算法2.压力容器设计问题3.三杆桁架设计问题4.拉压弹簧设计问题5.Matlab代码6.Python代码摘要&#xff1a;本文介绍利用蜣螂搜索算法&#xff0c…

MyBatis框架知识点总结

一、引言1.1 什么是框架&#xff1f;框架&#xff1a;框架使用你的&#xff0c;而不是你在使用框架的。框架让我们提供什么信息&#xff0c;配置信息&#xff0c;数据库连接用户名密码等&#xff0c;你必须提供&#xff0c;还得按照框架要要求的方式提供&#xff0c;否则你就别…

《图机器学习》-Node Embeddings

Node Embeddings一、Graph Representation Learning二、Node Embeddings&#xff1a;Encoder and Decoder三、Random Walk Approaches for Node Embeddings一、Graph Representation Learning 在传统的图机器学习中&#xff0c;依赖于手工特征工程(即由特征工程师去设计节点、…

每日一题:Leetcode54. 螺旋矩阵

文章目录 系列&#xff1a;数组专练 语言&#xff1a;java & go 题目来源&#xff1a;Leetcode54. 螺旋矩阵 难度&#xff1a;中等 考点&#xff1a;边界问题处理 思路和参考答案文章目录题目描述思路java参考代码go参考代码&#xff1a;题目描述 给你一个 m 行 n 列的矩…

力扣sql基础篇(三)

力扣sql基础篇(三) 1 查询结果的质量和占比 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 把该列置为null的话,它就不会统计了 SELECT query_name,ROUND(sum(rating/position)/count(*),2) quality, ROUND(count(IF(rating<3,rating,null))/c…

【数据结构】—— Java实现双向链表

Java实现双向链表一、链表的概念及结构二、头指针与头结点的异同三、代码实现一、链表的概念及结构 我们在单链表中&#xff0c;有了next指针。这就使得我们查找下一个结点的时间复杂度为O(1)。可是我们要查找的是上一个结点的话&#xff0c;那最坏的时间复杂度就是O(n)了&…

用图记忆C语言中的运算符优先级

运算符优先级以及结合方向的统计表&#xff0c;网上到处可见。本文画了一张图&#xff0c;以便记忆&#xff01; 1. 总体来说优先级 初级运算 > 单目运算 > 双目运算 > 三目运算 > 赋值运算 > 逗号运算 2. 双目细分 算术运算 > 位移运算 > 关系运算 &g…

今年十八,基础过关

目录 前言 第一关&#xff1a;KEY在哪里 再加密一次你就得到key啦~ 猜猜这是经过了多少次加密&#xff1f; 据说MD5加密很安全&#xff0c;真的是么&#xff1f; 种族歧视 HAHA浏览器 key究竟在哪里呢&#xff1f; key又找不到了 冒充登陆用户​编辑 比较数字大小 就不让你…