Qt插件的学习

QPluginLoader的使用

介绍:QPluginLoader是框架中的一个类,用于动态加载插件。它可以运行时加载插件,并且可以在程序运行时卸载插件。通过 QPluginLoader,我们可以实现插件化的开发,使得程序的功能更加灵活和可扩展。

延申一下:插件是一种遵循一定规范的应用程序接口编写出来的程序,定位于开发实现应用软件平台不具备的功能的程序。插件与宿主程序之间通过接口联系,就像硬件插卡一样,可以被随时删除,插入和修改,所以结构很灵活,容易修改,方便软件的升级和维护

一、编写插件的步骤

1 定义一个PluginInterface

  • 该类只有头文件(如果 virtual ~PluginInterface() =default)
  • 该类定义中一般只包含纯虚函数的声明
  • 要包含下面的宏
    QT_BEGIN_NAMESPACE
    #define AbstractInterface_IID "MyPlugin_id"
    Q_DECLARE_INTERFACE(AbstractPlugin,AbstractInterface_IID)  //该宏用作将IID标识符与指定的类名相关联
    QT_END_NAMESPACE

2 创建一个插件(类)

  • .pro文件中添加”CONFIG += plugin“

  • 该类继承PluginInterface和Object(多继承哦)

  • 实现接口中的纯虚函数

  • .h文件中要保护下面的宏

        //使用Q_PLUGIN_METADATA宏导出插件
        Q_PLUGIN_METADATA(IID AbstractInterface_IID FILE "AbstractPluginAPI.json")
        //声明这个插件实现是基于哪个插件接口的
        Q_INTERFACES(AbstractPlugin)
    

3 构建plugin项目

  • 生成dll文件
  • 将dll文件和接口的.h文件需要复制下来给使用插件的项目

注意:通过Debug构建的dll最好后面加一个d,例如MyPlugind.dll,和Release构建进行区分(MyPlugin.dll),这样做的目的是,当使用者通过Debug编译时必须使用MyPlugind.dll,如果混用就会报错xxx incompatible Qt Library,同理使用Release也是一样,切记不要混用。

4 示例代码

1 .pro文件
QT += core

TEMPLATE = lib    #指定项目的模板为库
CONFIG += plugin  #告诉构建系统此库是一个插件,并且会生成相应的元数据文件,这是为了能够使用Qt的插件框架功能

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    mypluginimpl1.cpp

HEADERS += \
    AbstractPlugin.h \
    mypluginimpl1.h

DISTFILES += \
    AbstractPluginAPI.json

# Default rules for deployment.
!isEmpty(target.path): INSTALLS += target

2 接口文件
#ifndef ABSTRACTPLUGIN_H
#define ABSTRACTPLUGIN_H

#include <QObject>

class AbstractPlugin
{
public:
//    AbstractPlugin();
    virtual ~AbstractPlugin() = default;
    virtual QString doSomething()=0;
};

//下面的必须要有
QT_BEGIN_NAMESPACE
#define AbstractInterface_IID "MyPlugin_id"
Q_DECLARE_INTERFACE(AbstractPlugin,AbstractInterface_IID)  //该宏用作将IID标识符与指定的类名相关联
QT_END_NAMESPACE

#endif // ABSTRACTPLUGIN_H

#define xxx xx

xx表示可以自定义

3 实现类.h
#ifndef MYPLUGINIMPL1_H
#define MYPLUGINIMPL1_H

#include "AbstractPlugin.h"

class MyPluginImpl1 : public QObject,public AbstractPlugin
{
    Q_OBJECT
    //下面的要有 
    //使用Q_PLUGIN_METADATA宏导出插件
    Q_PLUGIN_METADATA(IID AbstractInterface_IID FILE "AbstractPluginAPI.json")
    //声明这个插件实现是基于哪个插件接口的
    Q_INTERFACES(AbstractPlugin)
public:
    MyPluginImpl1(QObject *parent=NULL);
     ~MyPluginImpl1();
    
    // AbstractPlugin interface
    virtual QString doSomething() override;
};

#endif // MYPLUGINIMPL1_H

注意 它继承了ObjectAbstractPlugin两个类

4 继承类.cpp
#include "mypluginimpl1.h"

MyPluginImpl1::MyPluginImpl1(QObject *parent):QObject(parent)
{

}

MyPluginImpl1::~MyPluginImpl1()
{

}

QString MyPluginImpl1::doSomething()
{
    return "MyPluginImpl1 doing........";
}

二、使用QPluginLoader加载插件

1加载插件的准备工作

  • 建议取消影子构建(shadow build),在左侧工具栏–》项目–》取消勾选Shadow build

  • 在当前项目(要使用插件的项目)包含pro的文件夹中,创建两个文件夹,一个建议命名为include(用于存放插件接口的头文件.h),另一个建议命名为lib(用于存放插件的dll文件)

  • 在.pro文件中通过配置INCLUDEPATH包含头文件

    INCLUDEPATH += $$PWD/include

    注意:$$PWD是指当前项目的.pro所在位置

2加载插件示例代码

#include "AbstractPlugin.h"  //导入接口头文件

#include <QPluginLoader>
#include <QApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QPluginLoader loader("../lib/MyPlugin1d.dll");
    loader.load();
    qDebug()<<loader.metaData();

    QObject *plugin = loader.instance(); //创建插件实例

    if(plugin)
    {
        AbstractPlugin *printStr = qobject_cast<AbstractPlugin*>(plugin);
        if(printStr)
        {
            QString str = printStr->doSomething();
            qDebug() << str;
        }
        else
        {
            qWarning()<<"Fail to cast to AbstractPlugin";
        }

    }
    else
    {
        qWarning()<<loader.errorString();
    }
    qDebug() << "quit=========";
    return a.exec();
}

注意 用plugin和printStr之间记得判空,防止加载插件失败时,访问空指针

3插件卸载

    //卸载插件
    loader.unload();
    if(loader.isLoaded())
    {
        qDebug() << "卸载失败";
    }
    else
    {
        qDebug() << "卸载成功";
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值