QT插件学习系列(一) 初识QtPlugin

QT插件学习系列(一) 初识QtPlugin

1、 概述

为什么我们要学习插件化,其和 windows 导出 dll 有什么区别呢?

  1. 导出的动态库如果缺失,程序不能运行。但插件可以。
  2. 同一套代码,即可分别在 windows 下和 linux 下生成插件。

QT 本身提供两种插件支持,一种称为高级 API,一种称为低级 API。

  1. 高级API的作用是扩展 QT 程序本身,需要子类化 QT 提供的插件基类,例如现有的 QTSqlDriver,因此你可也以编写自己的 QTStyle 扩展 QT。
  2. 低级 API 的作用是扩展自己的程序,也就是动态库的形式,在windows下就是个dll。同时因为高级 API 基于低级 API 创建,因此掌握低级 API 用法,高级 API 的用法也不在话下。

QT 的插件加载需要用到类 QPluginloader,你可以编写支持任意功能的插件。如何创建一个插件和加载这个插件 QT Assist 中是这样描述的:

创建一个扩展应用程序的插件:

  1. 定义一组用于与插件对话的接口(仅具有纯虚拟函数的类)。(预留好接口,方便建立通信)。
  2. 接口内使用 Q_DECLARE_INTERFACE() 宏告诉qt的元对象系统有关接口的信息。
  3. 使用 QPluginLoader 加载插件。
  4. 使用 qobject_cast 检验插件是否实现了既定的接口(以防外部插件注入),转换成功即可得到插件实例。

插件编写具体步骤(代码编写):

  1. 声明插件类,并继承 QObject 和 实现上面提到的既定接口。
  2. 使用 Q_INTERFACES 告诉 QT 元对象系统有关这个接口的信息(虚方法)。
  3. 使用 Q_PLUGIN_METADATA 导出插件。(Q_PLUGIN_METADATA 是 QT5的宏,QT4 使用的是 Q_EXPORT_PLUGIN2)
  4. 编写合适的 .pro 文件。

2、 实例

一、 新建子目录项目 PluginApp

二、 在 PluginApp 下 新建 QWidget 项目,名为 Main

三、 右键 PluginApp 新建子项目 pluginA


四、 项目目录结构

五、 编写接口,在 Main 下新建头文件 interfaceplugin.h

#interfaceplugin.h

#ifndef INTERFACEPLUGIN_H
#define INTERFACEPLUGIN_H

#include <QString>
#include <QtPlugin>

//定义接口
class InterfacePlugin
{
public:
    virtual ~InterfacePlugin() {}
    virtual QString output(const QString &message) = 0;
};

#define InterfacePlugin_iid "Test.Plugin.InterfacePlugin"   // 唯一标识符

Q_DECLARE_INTERFACE(InterfacePlugin, InterfacePlugin_iid)

#endif

六、 加载插件

#main.cpp

#include "widget.h"
#include <QApplication>
#include <QDir>
#include <QPluginLoader>
#include "interfaceplugin.h"
#include <QObject>
#include <QDebug>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
//    Widget w;
//    w.show();

    //加载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)
                {
                    InterfacePlugin *app = qobject_cast<InterfacePlugin*>(plugin);
                    if (app)
                    {
                        app->output("i am a plugin");
                    }
                }
        }
    return a.exec();
}

七、 编写插件 .pro 文件、头文件、 cpp 文件

#pluginA.pro

TEMPLATE        = lib           #表示这个makefile是一个lib的makefile
CONFIG         += plugin        #应用程序是一个插件
TARGET          = pluginA       #生成插件的名称
DESTDIR         = ../plugins    #生成插件的目录

HEADERS += \
    pluginA.h

SOURCES += \
    pluginA.cpp

DISTFILES += \
    programmer.json             #插件描述文件

#this is pluginA.h

#ifndef PLUGINA_H
#define PLUGINA_H

#include <QObject>
#include <QtPlugin>
#include "../Main/interfaceplugin.h"

class PluginA : public QObject, public InterfacePlugin
{
    // programmer.json 插件的信息描述类
    Q_OBJECT
    Q_PLUGIN_METADATA(IID InterfacePlugin_iid FILE "programmer.json") // QT5.0 引入
    Q_INTERFACES(InterfacePlugin)
public:
    explicit PluginA(QObject *parent = 0);
    virtual  QString output(const QString &message) Q_DECL_OVERRIDE;
};
#endif // PLUGINA_H

“programmer.json” 为插件描述文件,会作为元数据被加载到插件中,可在需要的时候手动读取。其中包含了插件的基本信息,更重要的是包含了插件的依赖项,这些依赖项决定了插件的加载顺序,关于插件依赖解决下篇再讲。

{
    "author" : "qht",
    "date" : "2019/05/27",
    "name" : "pluginA",
    "version" : "1.0.0",
    "des" : "这是一个插件A,按此方法加载插件B、C等",
    "dependencies" : []
}

#this is pluginA.cpp

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

PluginA::PluginA(QObject *parent) :
    QObject(parent)
{
}

QString PluginA::output(const QString &message)
{
    qDebug() << message + "插件A加载成功";
    return message;
}

八、 运行

注:
1、Main 项目选择 QWidget GUI项目是有原因的,下篇再说是为什么。
2、windows 下生成的插件为 dll 后缀,linux 下生成的即为 .so后缀(下篇出 linux 测试结果)。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt是一款跨平台的C++应用程序开发框架,支持各种GUI(图形用户界面)和非GUI应用程序开发。Qt提供了件(Plugin)机制,使开发者可以将应用程序的功能模块化,以实现灵活的件化开发。 Qt件机制允许开发者将应用程序的一部分功能独立封装成件,并在运行时动态加载。这样的好处是件可以在不重新编译整个应用程序的情况下进行更新或替换,极大地提升了开发效率和灵活性。 件化开发中,Qt提供了一些关键的类和接口,包括QPluginLoader、QObject和Q_EXPORT_PLUGIN2等。首先,使用QPluginLoader类可以在运行时加载件,并提供了查找和实例化件的功能。其次,件类需要派生自QObject类,并通过宏Q_OBJECT和Q_PLUGIN_METADATA来声明,以便Qt能够正确处理件的元数据和信号槽机制。最后,Q_EXPORT_PLUGIN2宏用于导出件类的实例,使其可以被QPluginLoader动态加载。 利用Qt件机制,开发者可以将应用程序按功能划分为不同的件模块,简化开发过程和项目维护。件可以通过简单的配置文件进行注册和管理,实现件的自动加载和卸载。另外,Qt的信号槽机制可以在件之间进行通信和交互。这使得多个独立开发的件可以灵活地协同工作,提供更丰富的功能和扩展性。 总结来说,Qt件机制使得应用程序的功能模块化,提供了灵活的件化开发方式。开发者可以通过动态加载和卸载件,实现件的更新和替换,提升开发效率和项目的可维护性。件之间可以通过信号槽机制进行通信和交互,实现更丰富的功能和扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值