文章目录
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
注意 它继承了Object
和AbstractPlugin
两个类
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() << "卸载成功";
}