qt实现插件管理与开发

1 说明

相关开源代码:https://gitee.com/jiangtao008/GoSlowDetection/tree/master
相关项目介绍:https://blog.csdn.net/weixin_42887343

2 设计

项目整体结构如下图所示:
qt实现插件管理与开发_第1张图片
主体分为插件使用方与插件方,插件使用即你的业务项目,插件方则包含很多插件子项目。

插件子项目编译后可输出dll文件(插件文件),将dll文件放到业务项目下的固定目录,然后业务项目中的插件管理模块扫描目录下的所有插件,再加载所有插件,加载后,即可通过插件接口(纯虚类)访问、调用插件。

2.1 插件设计

2.2 插件管理模块设计

3实现

3.1插件实现

3.1.1qt自带的接口插件

插件接口

此插件接口为qt库自带,如使用QGenericPlugin类为插件接口,qt插件接口种类可查看看下图:
qt实现插件管理与开发_第2张图片

插件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");
}

3.1.2自定义接口插件

自定义的接口(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.2 插件管理模块实现

此模块是以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;
}

你可能感兴趣的:(C++\QT,qt,插件,动态库,qt插件,插件系统)