当前位置: 首页 > news >正文

【QT】Qt Plugin开发

目录

    • 插件是什么
      • QT插件是什么
    • 为什么要有插件开发
      • 插件开发优势
      • 插件和动态库区别
    • Qt Plugin
      • QT插件类型
      • QT插件开发流程
      • QT插件应用
      • QT插件JSON文件
    • 参考文章

插件是什么

  1. 插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。
  2. 其只能运行在程序规定的系统平台下(可能同时支持多个平台),而不能脱离指定的平台单独运行
  3. 因为插件需要调用原纯净系统提供的函数库或者数据。

QT插件是什么

  1. QT插件是重载了虚函数的dll,跟抽象工厂类类似,qt的插件可以说是一种动态库。

为什么要有插件开发

插件开发存在的原因主要是为了提高软件的可扩展性和可维护性。通过插件化开发,开发者可以将功能模块以插件的形式动态加载到应用程序中,使得开发者能够更加方便地对软件进行扩展和定制

插件开发优势

  1. 在函数中,我们导入Interface接口文件,也就是插件接口文件,不需要依赖静态库生成代码,类似C/C++关键字extern。而在最后我们通过系统的API加载dll或者so(通过动态库加载的两种方式)

  2. 定义开发范式,面向Interface编程,内部封装,模块和整体流程开发分离,提高开发效率。应用场景QtCreator-IDE、WPS、visual studio、Nodepad++等等,都是采用这种开发方式。

动态库的加载主要有两种方式(源自GPT)
隐式加载:也叫载入时加载,是在编译的时候,指明所依赖的动态链接库,这样在程序启动的时候,loader会将所有的动态链接库映射到内存中。这种方式需要.h文件,.dll文件,.lib文件。在vs的项目属性->链接器的附加库目录设置为存放.lib文件的路径,附加依赖项加入用到的.lib文件名字。将.dll文件和项目生成的.exe文件放在一起就可以使用.dll文件中的函数了。

显式加载:也叫运行时加载,是在程序运行过程中,通过调用系统函数,把动态库加载到程序中,然后执行动态库中的代码。这种方式需要.h文件,.dll文件。这种方式是将较大的程序分开加载的,程序运行时只需要将主程序载入内存,软件打开速度快,用户体验好。显式加载使用libdl.so库的API接口在运行中加载和卸载动态库,主要的API有dlopen、dlclose、dlsym、dlerror。

插件和动态库区别

两者都是用于封装部分功能的实现,并降低模块代码耦合度。但其实插件也是被部署为动态库的形式,但是和传统的动态库还是有一些差别的。

  1. 插件主要面向接口编程,**无需访问 .lib 文件,热插拔、利于团队开发。即使在程序运行时 .dll 不存在,也可以正常启动,**只是相应插件的功能无法正常使用而已。

  2. 动态库需要访问 .lib 文件,而且在程序运行时必须保证 .dll 存在,否则无法正常启动。

  3. 插件的应用场景,一个大型项目的开发离不开插件化,可以让整个框架结构更加清晰和容易理解,比如说一个该项目经常会针对不同客户做功能定制,或者对于软件使用的不同场景,功能有所区别,那这时候插件就变得非常有用了,主工程中包含所有功能模块的调用,但是如果某些功能如果不需要,那最终程序打包只要不把插件的dll打包进去就OK了,程序依然可以正常运行,只是该插件的功能无法使用而已。

这样对于多功能模块的情况下,如果不同版本仅需要其中几项功能,就可以不用像动态链接库那样,全部dll都包含进去,从而也节省了安装包的空间。

Qt Plugin

QT插件类型

  1. The High-Level API:用于扩展Qt本身的功能,需放在Qt安装目录下的指定目录里;

  2. The Lower-Level API:用于扩展Qt应用程序的功能;

Qt Plugin按照类型又可分为两种:动态插件(dll)和静态插件(lib);

以下说的均为The Lower-Level API的动态插件。

  1. Qt5不再使用Q_EXPORT_PLUGIN2宏,可以在代码中跳转过去看,会发现这个宏已经作废了,在Qt5中,导出plugin使用Q_PLUGIN_METADATA宏,在Qt助手中搜“How to Create Qt Plugins”可以看到相关说明,还有一个不完整但清晰的demo。

QT插件开发流程

主程序开发流程(接口)

  1. 定义插件接口(抽象类模拟接口)
  2. 使用 Q_DECLARE_INTERFACE() 宏来告诉 Qt 元对象系统有关接口的情况

插件开发流程

  1. 声明一个插件类,该插件类继承自QObject和上一步定义的接口类
  2. 使用Q_INTERFACES宏将该接口类告诉Qt元系统
  3. 使用Q_PLUGIN_METADATA宏导出该插件类(Qt5不再使用Q_EXPORT_PLUGIN2宏)
// 接口声明
#include <QtCore/QtPlugin>#define Interface_iid "Plugin.Interface"class Interface
{
public:virtual ~Interface() {};/// @brief 获取插件名virtual const QString getPluginName() = 0;
};Q_DECLARE_INTERFACE(Interface, Interface_iid);
// 插件主体
#pragma once#include <QtCore/QObject>
#include <QtCore/QtPlugin>#include "../QtPluginTest/Interface.h"class Plugin_1 : public QObject, public Interface
{Q_OBJECTQ_INTERFACES(Interface)Q_PLUGIN_METADATA(IID Interface_iid FILE "xx.json")// FILE是可选参数,他指向一个json文件。// Q_PLUGIN_METADATA(IID Interface_iid) // 这样也可以public:explicit Plugin_1(QObject* parent = nullptr);const QString getPluginName() override;
};#include "Plugin_1.h"Plugin_1::Plugin_1(QObject* parent):QObject(parent)
{
}const QString Plugin_1::getPluginName()
{return QString("Plugin_1");
}

QT插件应用

完成插件代码后,编译插件工程生成dll,拷贝到应用工程中,然后要包含Interface的头文件(如果有Interface.cpp,那么还要加上附加库目录和附加依赖项);

然后通过QPluginLoader类来动态加载插件,也就是xxxx.dll文件,加载比较简单,只要xxxx.dll是一个插件(可以理解为一个有Q_DECLARE_INTERFACE、Q_PLUGIN_METADATA、Q_INTERFACES这三个宏的工程生成的dll就是插件),把它丢到exe所在目录下就可以加载了。

QDir pluginsDir(qApp->applicationDirPath());
auto path = pluginsDir.dirName();
pluginsDir.cd("Plugins");
path = pluginsDir.dirName();foreach(QString fileName, pluginsDir.entryList(QDir::Files)) {if (!fileName.contains(".dll")){continue;}QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));QObject* plugin = pluginLoader.instance();if (plugin) {auto name = plugin->metaObject()->className();Interface* m_pInterface = qobject_cast<Interface*>(plugin);if (m_pInterface)qDebug() << m_pInterface->getPluginName();}
}// or
QDir path(qApp->applicationDirPath());
QPluginLoader loader(path.absoluteFilePath("Plugin.dll"));//Plugin.dll是一个插件
if (!loader.load()) {qDebug() << "It is not a plugin";return;
}
QObject *obj = loader.instance();
if (obj) {Interface *plugin = qobject_cast<Interface *>(obj);
}

// TODO
QCoreApplication::addLibraryPath(“/path/to/your/plugins”) 加载插件
PS:参考文档Qt QCoreApplication addLibraryPath use
参考

QT插件JSON文件

Qt plugin工程在创建时就会自带一个json文件,用于存储元信息和一些配置信息,读取json文件如下。
我个人认为该json就是存储插件的一些信息,方便标识

参考文章

  1. Qt5笔记之Qt5插件的生成与加载及json文件的读取
  2. Qt 插件的json文件如何生成
  3. 【QT】QT中插件化开发及其简单使用
  4. Qt插件化(Plugins)开发扩展应用程序
  5. 实战详细讲解Qt插件plugin的编写与用法

相关文章:

【QT】Qt Plugin开发

目录 插件是什么QT插件是什么 为什么要有插件开发插件开发优势插件和动态库区别 Qt PluginQT插件类型QT插件开发流程QT插件应用QT插件JSON文件 参考文章 插件是什么 插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。…...

快速了解GPU分布通信技术:PCIe、NVLink与NVSwitch

在现代高性能计算和深度学习领域&#xff0c;GPU的强大计算能力使其成为不可或缺的工具。然而&#xff0c;随着模型复杂度的增加&#xff0c;单个GPU已经无法满足需求&#xff0c;需要多个GPU甚至多台服务器协同工作。这就要求高效的GPU互联通信技术&#xff0c;以确保数据传输…...

Python对获取数据的举例说明

当使用Python来获取数据时&#xff0c;有许多不同的方法和库可以根据你的需求来选择。以下是一些常见的示例&#xff0c;说明如何使用Python来从各种来源获取数据。 1. 从网站或API获取JSON数据 你可以使用requests库从网站或API获取JSON格式的数据。例如&#xff0c;从某个API…...

JVMの垃圾回收

在上一篇中&#xff0c;介绍了JVM组件中的运行时数据区域&#xff0c;这一篇主要介绍垃圾回收器 JVM架构图&#xff1a; 1、垃圾回收概述 在第一篇中介绍JVM特点时&#xff0c;有提到过内存管理&#xff0c;即Java语言相对于C&#xff0c;C进行的优化&#xff0c;可以在适当的…...

人工智能就业方向有哪些?

人工智能就业方向有哪些? 随着人工智能技术的不断发展&#xff0c;其应用领域也越来越广泛。对于想要进入人工智能领域的年轻人来说&#xff0c;选择一个合适的职业方向是至关重要的。今天给大家介绍六个热门的人工智能就业方向&#xff0c;分别是机器学习工程师、自然语言处理…...

自定义类型:枚举和联合体

在之前我们已经深入学习了自定义类型中的结构体类型 &#xff0c;了解了结构体当中的内存对齐&#xff0c;位段等知识&#xff0c;接下来在本篇中将继续学习剩下的两个自定义类型&#xff1a;枚举类型与联合体类型&#xff0c;一起加油&#xff01;&#xff01; 1.枚举类型 …...

负载均衡加权轮询算法

随机数加权轮询算法 public int select() {int[] weights {10, 20, 50};int totalWeight weights[0] weights[1] weights[2];// 取随机数int offset ThreadLocalRandom.current().nextInt(totalWeight);for (int i 0; i < weights.length; i) {offset - weights[i];i…...

PyTorch 相关知识介绍

一、PyTorch和TensorFlow 1、PyTorch PyTorch是由Facebook开发的开源深度学习框架&#xff0c;它在动态图和易用性方面表现出色。它以Python为基础&#xff0c;并提供了丰富的工具和接口&#xff0c;使得构建和训练神经网络变得简单快捷。 发展历史和背景 PyTorch 是由 Fac…...

1千2初中英语语法题库ACCESS\EXCEL数据库

英语语法是针对英语语言进行研究后&#xff0c;系统地总结归纳出来的一系列语言规则。英语语法的精髓在于掌握语言的使用。比如词类有名词、代词、数词、感叹词等&#xff0c;时态有一般状态、进行状态、完成状态和完成进行状态四种&#xff0c;语态有主动语态、被动语态等。 …...

高德面试:为什么Map不能插入null?

在 Java 中&#xff0c;Map 是属于 java.util 包下的一个接口&#xff08;interface&#xff09;&#xff0c;所以说“为什么 Map 不能插入 null&#xff1f;”这个问题本身问的不严谨。Map 部分类关系图如下&#xff1a; 所以&#xff0c;这里面试官其实想问的是&#xff1a;为…...

MySQL数据库主从配置

MySQL主从配置 1. 修改数据库my.cnf文件 修改数据库my.cnf文件&#xff0c;在文件中添加如下内容&#xff0c;其中主数据库的server-id必须要比从库的更小。 # 注册集群id server-id101 # 开启二进制日志文件 log-binmysql-bin # 设置日志格式 binlog-formatrow # 开启中继日…...

测试工程师经常使用的Python中的库,以及对应常用的函数

os (操作系统接口) 该库提供了许多与操作系统交互的函数&#xff0c;如文件处理、目录操作、进程管理等。 常用功能包括&#xff1a; os.name: 获取操作系统的名称。 os.path: 用于操作文件路径的模块&#xff0c;如os.path.join拼接路径。 os.mkdir: 创建目录。 os.remove: 删…...

【frp】服务端配置与systemd启动

ini配置的方式已经废弃。官方文档是toml 。阿里云ecs 部署服务端参考大神的文章 使用Frp配置内网访问(穿透) 0.54 版本 我现在用最新的0.58版本。systemd apt install systemdfrp服务端配置 /root/frp目录 vim frps.toml#服务绑定的IP与端口 bindAddr = "0.0.0.0" …...

计算机网络学习实践:模拟RIP动态路由

计算机网络学习实践&#xff1a;模拟RIP动态路由 模拟动态路由RIP协议 1.实验准备 实验环境&#xff1a;华为模拟器ENSP 实验设备&#xff1a; 3个路由器&#xff0c;3个二层交换机&#xff08;不是三层的&#xff09;&#xff0c;3个PC机 5个网段 192.168.1.0 255.255.…...

详解 Flink 的常见部署方式

一、常见部署模式分类 1. 按是否依赖外部资源调度 1.1 Standalone 模式 独立模式 (Standalone) 是独立运行的&#xff0c;不依赖任何外部的资源管理平台&#xff0c;只需要运行所有 Flink 组件服务 1.2 Yarn 模式 Yarn 模式是指客户端把 Flink 应用提交给 Yarn 的 ResourceMa…...

【UE5.1 角色练习】11-坐骑——Part1(控制大象移动)

前言 在上一篇&#xff08;【UE5.1 角色练习】10-物体抬升、抛出技能 - part2&#xff09;基础上创建一个新的大象坐骑角色&#xff0c;并实现控制该角色行走的功能。 效果 步骤 1. 在商城中下载“African Animal Pack”资产和“ANIMAL VARIETY PACK”资产导入工程中 2. 复…...

数据结构严蔚敏版精简版-线性表以及c语言代码实现

线性表、栈、队列、串和数组都属于线性结构。线性结构的基本特点是除第一个元素无直接前驱&#xff0c;最后一个元素无直接后继之外&#xff0c;其他每个数据元素都有一个前驱和后继。 1 线性表的定义和特点 如此类由n&#xff08;n大于等于0&#xff09;个数据特性相同的元素…...

【react】react项目支持鼠标拖拽的边框改变元素宽度的组件

目录 安装使用方法示例Props 属性方法示例代码调整兄弟div的宽度 re-resizable github地址 安装 $ npm install --save re-resizable这将安装re-resizable库并将其保存为项目的依赖项。 使用方法 re-resizable 提供了一个 <Resizable> 组件&#xff0c;它可以包裹任何…...

QT 创建文件 Ui 不允许使用不完整类型,可以尝试添加一下任何头文件

#include "debug.h" #include "qmessagebox.h" #pragma execution_character_set("utf-8") //QT 创建文件 Ui 不允许使用不完整类型,尝试添加一下任何头文件&#xff0c;或者添加ui_xx.h头文件 debug::debug(QWidget *parent) : QDialog(p…...

Python:深入探索其生态系统与应用领域

Python&#xff1a;深入探索其生态系统与应用领域 Python&#xff0c;作为一种广泛应用的编程语言&#xff0c;其生态系统之丰富、应用领域之广泛&#xff0c;常常令人叹为观止。那么&#xff0c;Python究竟涉及哪些系统&#xff1f;本文将从四个方面、五个方面、六个方面和七…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

高防服务器价格高原因分析

高防服务器的价格较高&#xff0c;主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因&#xff1a; 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器&#xff0c;因此…...

深度解析云存储:概念、架构与应用实践

在数据爆炸式增长的时代&#xff0c;传统本地存储因容量限制、管理复杂等问题&#xff0c;已难以满足企业和个人的需求。云存储凭借灵活扩展、便捷访问等特性&#xff0c;成为数据存储领域的主流解决方案。从个人照片备份到企业核心数据管理&#xff0c;云存储正重塑数据存储与…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...