相关开源代码:https://gitee.com/jiangtao008/GoSlowDetection/tree/master
相关项目介绍:https://blog.csdn.net/weixin_42887343
项目整体结构如下图所示:
主体分为插件使用方与插件方,插件使用即你的业务项目,插件方则包含很多插件子项目。
插件子项目编译后可输出dll文件(插件文件),将dll文件放到业务项目下的固定目录,然后业务项目中的插件管理模块扫描目录下的所有插件,再加载所有插件,加载后,即可通过插件接口(纯虚类)访问、调用插件。
插件接口
此插件接口为qt库自带,如使用QGenericPlugin
类为插件接口,qt插件接口种类可查看看下图:
插件h文件
#ifndef QTTESTPLUGIN_H
#define QTTESTPLUGIN_H
#include
class qtTestPlugin : public QGenericPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "qtTestPlugin.json")
public:
explicit qtTestPlugin(QObject *parent = nullptr);
private:
QObject *create(const QString &name, const QString &spec) override;
};
#endif // QTTESTPLUGIN_H
插件cpp文件
#include "qttestplugin.h"
qtTestPlugin::qtTestPlugin(QObject *parent)
: QGenericPlugin(parent)
{
}
QObject *qtTestPlugin::create(const QString &name, const QString &spec)
{
static_assert(false, "You need to implement this function");
}
自定义的接口(plugininterface.h)
#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include
#include
#include
class PluginInterface
{
public:
virtual ~PluginInterface(){}
virtual QString getName() = 0; //必要要实现
virtual QIcon getIcon() = 0;
virtual QWidget* creactUi(QWidget *parent = 0) = 0;
virtual bool deleteUi() = 0;
virtual bool isOpenUi() = 0;
};
//定义唯一的ID号
#define pluginInterface_iid "io.qt.dynamicplugin"
//向Qt元对象系统声明了这个接口
Q_DECLARE_INTERFACE(PluginInterface, pluginInterface_iid)
#endif // PLUGININTERFACE_H
插件h文件(plugin.h)
#ifndef PLUGINMAIN_H
#define PLUGINMAIN_H
#include
#include
#include "../../plugininterface.h"
class Plugin : public QObject,PluginInterface
{
Q_OBJECT
//导入元数据,必须要有,否则无法加载
Q_PLUGIN_METADATA(IID pluginInterface_iid)
//导入接口
Q_INTERFACES(PluginInterface)
public:
explicit Plugin(QObject *parent = nullptr);
~Plugin();
QString getName(); //必要要实现
QIcon getIcon();
QWidget* creactUi(QWidget *parent = 0);
bool deleteUi();
bool isOpenUi();
private:
QWidget *mWidget;
};
#endif // PLUGINMAIN_H
插件cpp文件(plugin.cpp)
#include "plugin.h"
Plugin::Plugin(QObject *parent) : QObject(parent),mWidget(nullptr)
{
}
Plugin::~Plugin()
{
//closeWindow();
}
QString Plugin::getName()
{
return "插件测试";
}
QIcon Plugin::getIcon()
{
return QIcon(":/new/prefix1/defaultIcon.png");
}
QWidget* Plugin::creactUi(QWidget *parent)
{
if(isOpenUi())
return nullptr;
mWidget = new QWidget(parent);
mWidget->setWindowFlags(Qt::Dialog);
mWidget->setGeometry(100,100,300,200);
return mWidget;
}
bool Plugin::deleteUi()
{
if(!isOpenUi())
return 0;
delete mWidget;
return 1;
}
bool Plugin::isOpenUi()
{
if(!mWidget)
return 0;
return !mWidget->isHidden();
}
此模块是以3.1.2中的自定义插件接口为基础实现。
插件管理类h文件(pluginmanage.h)
#ifndef PLUGINMANAGE_H
#define PLUGINMANAGE_H
#include
#include
class PluginManage : public QObject
{
Q_OBJECT
public:
explicit PluginManage(QObject *parent = nullptr);
//插件文件级别操作
QStringList findPlugin(); //发现插件
bool addPlugin(const QString &filePath); //添加插件
bool removePlugin(const QString &filePath); //删除插件
bool removeAllPlugin(); //清空插件
//插件对象实例化级别操作
bool loadPlugin(const QString &filePath); //加载插件
void loadAllPlugin();
bool unloadPluin(const QString &filePath); //卸载插件
void unloadAllPlugin();
bool isLoaded(const QString &filePath); //判断插件是否加载
PluginInterface* getPlugin(const QString &filePath);
QHash<QString, PluginInterface*> getAllPlugin();
signals:
void sigLoadPlugin(PluginInterface* plugin);
void sigUnloadPlugin(PluginInterface* plugin);
private:
QString mPluginDir;
QHash<QString, PluginInterface*> mPluginHash; //插件路径(dll名字):插件实例化对象
};
#endif // PLUGINMANAGE_H
插件管理类cpp文件(pluginmanage.cpp)
#include "pluginmanage.h"
#include
#include
#include
PluginManage::PluginManage(QObject *parent) : QObject(parent)
{
QDir pluginsDir(QDir::currentPath());
pluginsDir.cd("plugins");
mPluginDir = pluginsDir.path();
}
QStringList PluginManage::findPlugin()
{
QStringList fileList;
QDir pluginsDir(mPluginDir);
QFileInfoList pluginsInfo = pluginsDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
for(QFileInfo fileinfo : pluginsInfo)
fileList.append(fileinfo.absoluteFilePath());
return fileList;
}
//输入插件路径,拷贝到本地plugins目录下,并加入到插件系统
bool PluginManage::addPlugin(const QString &filePath)
{
QFile pluginFile(filePath);
if(!pluginFile.exists())
return 0;
//拷贝复制
pluginFile.copy(mPluginDir + "/" + pluginFile.fileName());
//还需要加载插件,如果加载不了还需要删除插件文件
return 1;
}
bool PluginManage::removePlugin(const QString &filePath)
{
QFile pluginFile(filePath);
if(!pluginFile.remove())
return 0;
//还需要卸载插件
return 1;
}
bool PluginManage::removeAllPlugin()
{
QDir pluginsDir(mPluginDir);
QFileInfoList pluginsInfo = pluginsDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
for(QFileInfo fileinfo : pluginsInfo)
QFile::remove(fileinfo.absoluteFilePath());
//判断是否清空
pluginsInfo = pluginsDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
return pluginsInfo.isEmpty();
}
void PluginManage::loadAllPlugin()
{
QStringList pluginFiles = findPlugin();
for(QString file : pluginFiles)
loadPlugin(file);
}
#include
#include
bool PluginManage::loadPlugin(const QString &filePath)
{
if(!QLibrary::isLibrary(filePath))
return 0;
QPluginLoader loader(filePath);
if(loader.load())
{
PluginInterface *plugin = qobject_cast<PluginInterface *>(loader.instance());
if(plugin)
{
mPluginHash.insert(filePath,plugin);
emit sigLoadPlugin(plugin);
qDebug()<<Q_FUNC_INFO<<"插件加载成功,路劲:"<<filePath<<" 插件名字:"<<plugin->getName();
return 1;
}
else
qDebug()<<Q_FUNC_INFO<<"插件加载失败,路劲:"<<filePath<<" 插件实例化失败!";
}
else
qDebug()<<Q_FUNC_INFO<<"插件加载失败,路劲:"<<filePath<<" 错误信息:"<<loader.errorString();
return 0;
}
void PluginManage::unloadAllPlugin()
{
QStringList pluginFiles = mPluginHash.keys();
for(QString file : pluginFiles)
unloadPluin(file);
}
bool PluginManage::unloadPluin(const QString &filePath)
{
if(!isLoaded(filePath))
{
qDebug()<<Q_FUNC_INFO<<"插件卸载失败,路劲:"<<filePath<<" 插件未被加载!";
return 0;
}
QPluginLoader loader(filePath);
//卸载插件,并从内部数据结构中移除
if(loader.unload())
{
//emit sigLoadPlugin(plugin);
mPluginHash.remove(filePath);
qDebug()<<Q_FUNC_INFO<<"插件卸载成功,路劲:"<<filePath;
return 1;
}
qDebug()<<Q_FUNC_INFO<<"插件卸载失败,路劲:"<<filePath<<" 错误信息:"<<loader.errorString();
return 0;
}
bool PluginManage::isLoaded(const QString &filePath)
{
return mPluginHash.contains(filePath);
}
PluginInterface *PluginManage::getPlugin(const QString &filePath)
{
return mPluginHash.value(filePath);
}
QHash<QString, PluginInterface *> PluginManage::getAllPlugin()
{
return mPluginHash;
}