Qt 插件开发详解

news2025/1/11 2:21:34

1.简介

Qt插件是一种扩展机制,用于将应用程序的功能模块化,并且可以在运行时动态加载和卸载。Qt框架为插件提供了一套标准的接口和管理机制,使得插件的使用和集成变得简单和灵活,通过插件机制,可以将应用程序的功能划分为独立的可插拔的模块,使得应用程序更加可扩展和维护。

Qt插件系统具有以下特点:

  • 动态加载:Qt插件是在运行时动态加载的,允许在不重新编译或重新启动应用程序的情况下添加或移除插件。
  • 跨平台:Qt插件系统可以在不同的平台上运行,这意味着开发者可以使用相同的插件代码在Windows、macOS、Linux等多个操作系统上构建应用程序。
  • 松耦合:通过使用插件系统,应用程序可以以松耦合的方式使用插件。插件之间可以独立开发,编译和测试,然后在运行时动态加载到应用程序中。
  • 扩展性:Qt插件系统允许开发者根据应用程序的需求来设计和实现插件接口。这样,可以根据需要逐渐增加和扩展插件功能,而不会对应用程序的其他部分产生影响。

2.插件和动态库的区别

  • 功能和用途:动态库是一种包含可执行代码和数据的库,可以通过链接器将其与应用程序静态或动态地链接在一起。而Qt插件是一种特殊类型的动态库,用于扩展和增强Qt应用程序的功能。
  • API设计:动态库一般是一个完整的功能模块,可以直接调用其中的函数或使用其中的类。而Qt插件是基于插件接口或抽象类来设计的,通过继承插件接口并实现其纯虚函数来扩展插件的功能。
  • 动态加载:动态库通常需要在应用程序编译时与之链接,并在运行时加载。而Qt插件则是在运行时动态加载,可以根据需要添加或移除插件,而无需重新编译或启动应用程序。
  • 插件管理:Qt插件系统提供了更高级的插件管理功能,包括插件的自动发现、元信息的提取和注册、插件之间的依赖管理等。这使得使用和管理插件变得更加简单和灵活。

程序运行时需要动态库,否则运行不了,而插件不需要,在程序运行时动态加载。

3.如何创建插件

Qt提供了两个用于创建插件的API:

  • 一个高级API,用于编写Qt本身的扩展:自定义数据库驱动程序、图像格式、文本编解码器、自定义样式等。
  • 用于扩展Qt应用程序的低级API。

例如:如果您想编写一个自定义的QStyle子类并让Qt应用程序动态加载它,那么您可以使用更高级别的API。

编写一个扩展Qt本身的插件(高级API)是通过子类化适当的插件基类、实现一些函数和添加一个宏来实现的。

下表总结了插件基类,Qt的版本不同,插件会有些差别。 

Base ClassDirectory NameQt ModuleKey Case Sensitivity

QAccessibleBridgePlugin

accessiblebridgeQt GUICase Sensitive
QImageIOPluginimageformatsQt GUICase Sensitive
QPictureFormatPlugin (obsolete)pictureformatsQt GUICase Sensitive
QAudioSystemPluginaudioQt MultimediaCase Insensitive
QDeclarativeVideoBackendFactoryInterfacevideo/declarativevideobackendQt MultimediaCase Insensitive
QGstBufferPoolPluginvideo/bufferpoolQt MultimediaCase Insensitive
QMediaPlaylistIOPluginplaylistformatsQt MultimediaCase Insensitive
QMediaResourcePolicyPluginresourcepolicyQt MultimediaCase Insensitive
QMediaServiceProviderPluginmediaserviceQt MultimediaCase Insensitive
QSGVideoNodeFactoryPluginvideo/videonodeQt MultimediaCase Insensitive
QBearerEnginePluginbearerQt NetworkCase Sensitive
QPlatformInputContextPluginplatforminputcontextsQt Platform AbstractionCase Insensitive
QPlatformIntegrationPluginplatformsQt Platform AbstractionCase Insensitive
 
QPlatformThemePluginplatformthemesQt Platform AbstractionCase Insensitive
QGeoPositionInfoSourceFactorypositionQt PositioningCase Sensitive
QPlatformPrinterSupportPluginprintsupportQt Print SupportCase Insensitive
QSGContextPluginscenegraphQt QuickCase Sensitive
QScriptExtensionPluginscriptQt ScriptCase Sensitive
QSensorGesturePluginInterfacesensorgesturesQt SensorsCase Sensitive
QSensorPluginInterfacesensorsQt SensorsCase Sensitive
QSqlDriverPluginsqldriversQt SQLCase Sensitive
QIconEnginePluginiconenginesQt SVGCase Insensitive
QAccessiblePluginaccessibleQt WidgetsCase Sensitive
QStylePluginstylesQt Widgets

Case Insensitive

创建Qt本身的扩展:

如果你有一个名为MyStyle的新样式类,你想让它作为插件使用,那么这个类需要定义如下(mystyleplugin.h):

//.h
class MyStylePlugin : public QStylePlugin
  {
      Q_OBJECT
      Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "mystyleplugin.json")
  public:
      QStyle *create(const QString &key);
  };

//.cpp
  #include "mystyleplugin.h"

  QStyle *MyStylePlugin::create(const QString &key)
  {
      if (key.toLower() == "mystyle")
          return new MyStyle;
      return 0;
  }

QStylePlugin不区分大小写,在我们的create()实现中使用了小写版本;大多数其他插件都是区分大小写的。

对于数据库驱动程序、图像格式、文本编解码器和大多数其他插件类型,不需要显式的对象创建。Qt将根据需要查找并创建它们。style是个例外,因为您可能希望在代码中显式地设置样式。要应用样式,请使用以下代码。

 QApplication::setStyle(QStyleFactory::create("MyStyle"));

创建扩展Qt应用程序:

通过插件使应用程序可扩展包括以下步骤:

  • 定义一组用于与插件对话的接口(仅具有纯虚拟函数的类)。
  • 使用Q_DECLARE_INTERFACE()宏告诉Qt的元对象系统有关接口的信息。
  • 在应用程序中使用QPluginLoader来加载插件。
  • 使用qobject_cast()测试插件是否实现了给定的接口。

编写插件需要以下步骤:

  • 声明一个从QObject和插件想要提供的接口继承的插件类。
  • 使用Q_INTERFACES()宏告诉Qt的元对象系统有关接口的信息。
  • 使用Q_plugin_METADATA()宏导出插件。
  • 使用合适的.pro文件构建插件。

示例:

声明一个抽象接口类。

#ifndef COMPUTEINTERFACE_H
#define COMPUTEINTERFACE_H

#include <QtPlugin>

//定义接口
class ComputeInterface
{
public:
    virtual ~ComputeInterface() {}
    virtual int add(int a,int b) = 0;
    virtual int sub(int a,int b) = 0;
};

#define ComputeInterface_iid "Test.Plugin.ComputeInterface"   // 唯一标识符

QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(ComputeInterface, ComputeInterface_iid)
QT_END_NAMESPACE



#endif // COMPUTEINTERFACE_H

定义实现该接口的插件类。

#ifndef COMPUTEPLUGIN_H
#define COMPUTEPLUGIN_H

#include <QObject>
#include "../MainWidget/computeinterface.h"

class ComputePlugin : public QObject, public ComputeInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID ComputeInterface_iid)
    Q_INTERFACES(ComputeInterface)
public:
    explicit ComputePlugin(QObject *parent = nullptr);

    virtual int add(int a,int b);
    virtual int sub(int a,int b);
};

#endif // COMPUTEPLUGIN_H


#include "computeplugin.h"

ComputePlugin::ComputePlugin(QObject *parent)
    : QObject(parent)
{

}

int ComputePlugin::add(int a, int b)
{
   return a+b;
}

int ComputePlugin::sub(int a, int b)
{
    return a-b;
}

加载插件:

//加载exe所在目录下  plugin文件夹的所有插件
    QDir path = QDir(qApp->applicationDirPath());
    path.cd("../../plugins");
    foreach (QFileInfo info, path.entryInfoList(QDir::Files | QDir::NoDotAndDotDot))
    {
        QPluginLoader pluginLoader(info.absoluteFilePath());
        QObject *plugin = pluginLoader.instance();
        if (plugin)
        {
            ComputeInterface *app = qobject_cast<ComputeInterface*>(plugin);
            if (app)
            {
                 int ret = app->add(1,2);
                 qDebug()<<"ret = "<<ret;
            }
        }
    }

 以下是工程目录结构:

4.完整工程

https://download.csdn.net/download/wzz953200463/88495546

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

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

相关文章

QT5.15.2搭建Android编译环境及使用模拟器调试(全)

一、安装QT5.15.2 地址&#xff1a;下载 我电脑的windows的&#xff0c;所以选windows 由于官方安装过程非常非常慢&#xff0c;一定要跟着步骤来安装&#xff0c;不然慢到怀疑人生 1&#xff09;打开"命令提示符"&#xff08;开始 -> Windows 系统 -> 命令…

安防监控系统EasyCVR视频汇聚平台,如何实现视频汇聚?

关注我们的朋友都知道&#xff0c;EasyCVR平台最初就是以汇聚为核心而进行打造的&#xff0c;那到底什么是汇聚平台呢&#xff1f;又如何进行视频资源汇聚&#xff1f;简单来说&#xff0c;视频汇聚平台是指能够从不同的视频源&#xff08;例如直播、点播等&#xff09;收集、整…

如何使用Ruby 多线程爬取数据

现在比较主流的爬虫应该是用python&#xff0c;之前也写了很多关于python的文章。今天在这里我们主要说说ruby。我觉得ruby也是ok的&#xff0c;我试试看写了一个爬虫的小程序&#xff0c;并作出相应的解析。 Ruby中实现网页抓取&#xff0c;一般用的是mechanize&#xff0c;使…

【JMeter】插件管理工具

1. 官方下载地址 Documentation :: JMeter-Plugins.org 2.安装 将该插件的jar包移动到lib/ext下 3.重启JMeter就可以看到插件管理器 4. 安装&#xff0c;更新&#xff0c;删除插件 安装插件 删除插件 更新插件

Windows10电脑上的此电脑图标在哪里找到?

Windows10电脑上的此电脑图标在哪里找到&#xff1f; 1、在Windows10电脑桌面上鼠标右键&#xff0c;找到个性化点击打开&#xff1b; 2、打开个性化桌面设置后&#xff0c;找到主题并点击进入&#xff1b; 3、在主题相关的设置中找到桌面图标设置&#xff0c;并点击打开&…

【python基础】魔法参数*args, **kwargs的使用

文章目录 前言一、*args 和 **kwargs 是什么&#xff1f;二、*args 的用法打包参数&#xff1a;将不定数量的参数传递给一个函数拆分参数&#xff1a;调用一个函数 三、**kwargs 的用法打包参数&#xff1a;将不定数量的参数传递给一个函数拆分参数&#xff1a;调用一个函数 四…

【算法专题】双指针—快乐数

一、题目解析 由题目我们可以分析出无非就两种情况&#xff1a; 这个数一直变化最终能变到1这个数一直变化最终是无限循环 其实这两种情况我们也可以抽象成是一种情况&#xff0c;因为第一种情况虽然变到了1但是1再继续变下去也是形成一个环&#xff0c;只不过这个环的数都是…

GROMACS Tutorial - TMD with NeqPCA

Contents IntroductionSystem BuildingGenerate Topologyfrom Solvation to Equilibration Create trajectoriesPCA for TMD Introduction 首先简单介绍一下TMD模拟&#xff0c;类似于SMD模拟&#xff08;可以参考这篇教程&#xff09;&#xff0c;TMD 通过pull_coord1_type …

2.Docker基本架构简介与安装实战

1.认识Docker的基本架构 下面这张图是docker官网上的&#xff0c;介绍了整个Docker的基础架构&#xff0c;我们根据这张图来学习一下docker的涉及到的一些相关概念。 1.1 Docker的架构组成 Docker架构是由Client(客户端)、Docker Host(服务端)、Registry(远程仓库)组成。 …

树型表查询的两种方式(inner join 和 mysql递归查询)

方法一: 使用inner join来查询 SELECTone.id one_id,one.label one_label,two.id two_id,two.label two_label FROMcourse_category oneINNER JOIN course_category two ON two.parentid one.id WHEREone.parentid 1 AND one.is_show 1 AND two.is_show 1查询结果 方法…

IDEA远程调试代码

IDEA->RUN->Edit Configurations 端口随便选一个&#xff0c;选择调试模块&#xff0c;然后用IDEA生成的命令调试 java -agentlib:jdwptransportdt_socket,servery,suspendn,address*:8081 -jar backend-1.18.11.jar &

Android Studio创建项目后Gradle(构建)项目很慢问题解决

Android Studio创建项目后Gradle(构建)项目很慢问题解决 在使用Android Studio创建项目时&#xff0c;会自动从网上下载相关依赖。由于是访问国外服务器&#xff0c;会出现构建项目时下载依赖很慢的问题。为了解决该问题&#xff0c;需要在settings.gradle(或者settings.gradl…

2014年亚太杯APMCM数学建模大赛A题无人机创造安全环境求解全过程文档及程序

2014年亚太杯APMCM数学建模大赛 A题 无人机创造安全环境 原题再现 20 国集团&#xff0c;又称 G20&#xff0c;是一个国际经济合作论坛。2016 年第 11 届 20 国集团峰会将在中国召开&#xff0c;这是继 APEC 后中国将举办的另一个大型峰会。此类大型峰会&#xff0c;举办城市…

瓦斯抽采VR应急救援模拟仿真系统筑牢企业安全生产防线

矿工素质对安全生产的影响很大。传统的煤矿安全事故培训出于条件差、经验少加上侥幸心理&#xff0c;导致其在教学内容时过于简单且不切合实际&#xff0c;无法真正发挥培训作用。瓦斯检查作业VR模拟实操培训通过真实还原煤矿作业环境&#xff0c;让受训者身临其境地进入三维仿…

Windows10电脑如何测试宽带网速是多少?

Windows10电脑如何测试宽带网速是多少&#xff1f; 1、Windows10电脑上安装并打开360安全卫士&#xff1b; 2、在360安全卫士搜索框内找到宽带测速器&#xff1b; 3、点击打开360宽带测速器&#xff0c;开始测试本机网速&#xff1b; 4、耐心等待360宽带测速器完成&#xff0c…

【Docker】十分钟完成redis安装,你也可以的!!!

十分钟完成redis安装&#xff0c;你也可以的 前言安装步骤1.创建安装目录2.创建docker-compose.yml3.创建redis.conf文件4.启动容器5.连接redis 总结 前言 本文基于Docker安装redis&#xff0c;首先确保系统安装了docker和docker-compose。 没有使用过docker朋友可以去看看博主…

2023-macOS下安装anaconda,终端自动会出现(base)字样,如何取消

2023-macOS下安装anaconda&#xff0c;终端自动会出现(base)字样&#xff0c;如何取消 安装后&#xff0c;我们再打开终端&#xff0c;就会自动出现了&#xff08;base&#xff09; 就会出现这样子的&#xff0c;让人头大&#xff0c; 所以我们要解决它 具体原因是 安装了anac…

开放式耳机和骨传导耳机区别是什么?哪个更好一点?

开放式耳机和骨传导耳机最大的区别就是传声方式不同&#xff01;如果说推荐的话&#xff0c;骨传导耳机要好一些&#xff01; 其实骨传导耳机也算开放式耳机的一种&#xff0c;另一种则被称作为气传导耳机。 一、气传导耳机和骨传导耳机传声方式有什么区别&#xff1f; 气传导…

dy ios抓包及ios六神

1.抓包&#xff1a; 众所周知&#xff0c;dy协议都是无法直接抓包的。 a.在安卓中&#xff0c;我们可以通过改so及hook降级&#xff08;frida或xposed&#xff09;的方式来抓取数据流。 ~ b.在ios中&#xff0c;则需要手机越狱&#xff0c;来配个frida或者logos插件。 作者这里…

51单片机锅炉监控系统仿真设计( proteus仿真+程序+原理图+报告+讲解视频)

51单片机锅炉监控系统仿真设计( proteus仿真程序原理图报告讲解视频&#xff09; 1.主要功能&#xff1a;讲解视频2.仿真3. 程序代码4. 原理图5. 设计报告6. 设计资料内容清单&&下载链接资料下载链接&#xff08;可点击&#xff09;&#xff1a; 51单片机锅炉监控系统仿…