Qt插件开辟总结6--插件间依靠

[复制链接]
发表于 2026-1-30 09:41:25 | 显示全部楼层 |阅读模式
一、媒介

插件大抵可分为:功能性插件、界面插件;一个软件由一堆插件堆起来,一定难以克制插件间相互引用,比方:插件A调用了插件C中的功能,那么插件A就依靠插件C,以是在步调启动加载插件时,就应该先加载插件C,再加载插件A。
假如插件A是用于初始化的模块,插件C是用于检测软件序列合法性的模块,假如先加载插件A,并直接调勤奋能模块,那么检测软件序列合法性这部分功能就是缺失的,以是必须要检测插件间的依靠关系,并分列插件加载序次,才气使得软件功能正常。
但是插件依靠,不能形成死锁,比方:有向环



  • 图1:先加载插件B和插件C,再加载插件A,即可;
  • 图2:先加载插件C,再加载插件B,再加载插件A,即可;
  • 图3:先加载插件C,再加载插件B,再加载插件A,即可;
  • 图4:加载插件A必要插件B,加载插件B必要插件C,加载插件C必要插件A,就形成死锁了;

二、根本计谋

插件元数据中有一项:dependencies,这个就是用来标识该插件依靠的插件,比方:插件A依靠插件B、插件C
  1. {
  2.     "author" : "Wang_JC",
  3.     "date" : "2022/02/16",
  4.     "name" : "pluginA",
  5.     "version" : "1.0.0",
  6.     "des" : "这是一个插件A",
  7.     "dependencies" : ["pluginB:1.0.0","pluginC:1.0.0"],
  8.     "menu" : "menuFile",
  9.     "action" : ["action_A1","action_A2","action_A3"],
  10.     "widget" : "tabWidget"
  11. }
复制代码
我们在主步调中嗅探、自动加载插件:

在加载插件的时间,我们可以读取插件元数据中的插件依靠信息,然后检测依靠;假如存在依靠,那就暂不加载;假如不存在,那就直接加载。

检测插件是否存在依靠:可以遍历当前插件依靠项

比及自动加载插件全部竣事后,我们再查抄依靠插件栈内是否有还未加载的插件,有的话,再手动加载一下:


三、效果展示

弄了4个插件:A、B、C、D,依靠关系如下:



  • 插件A:依靠插件B和插件C
  • 插件B:无依靠
  • 插件C:无依靠
  • 插件D:无依靠
以是加载插件时,插件B和插件C必须要在插件A之间加载,插件D无所谓


四、关键代码

4.1、主步调

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include <QDebug>
  5. #include "PluginManager.h"
  6. #include <QDir>
  7. #include <QMenuBar>
  8. #include <QToolBar>
  9. #include <QTabWidget>
  10. #include <QWidget>
  11. #include <QHBoxLayout>
  12. #include <QLabel>
  13. #include "./Widget/speeddashbroad.h"
  14. QT_BEGIN_NAMESPACE
  15. namespace Ui { class MainWindow; }
  16. QT_END_NAMESPACE
  17. class MainWindow : public QMainWindow
  18. {
  19.     Q_OBJECT
  20. public:
  21.     MainWindow(QWidget *parent = nullptr);
  22.     ~MainWindow();
  23.     void Init_UI();
  24.     void recvMsgFromManager(PluginMetaData metaData);
  25.     QMenuBar* menuBar;
  26.     QMenu* menuFile;
  27.     QMenu* menuEdit;
  28.     QMenu* menuView;
  29.     QMenu* menuTool;
  30.     QTabWidget* tabWidget;
  31. public:
  32.     SpeedDashBroad* sdb;
  33. signals:
  34.     void sendMsgToManager(PluginMetaData);
  35. private slots:
  36.     void slot_PluginAction_MenuBar(QString menu,QStringList actionList);    //添加插件菜单栏Action
  37.     void slot_PluginsAction_trigger(bool isChecked);    //响应插件Action
  38.     void slot_PluginWidget(QPluginLoader*,QString);    //添加插件widget
  39. private:
  40.     Ui::MainWindow *ui;
  41. };
  42. #endif // MAINWINDOW_H
复制代码
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. MainWindow::MainWindow(QWidget *parent)
  4.     : QMainWindow(parent)
  5.     , ui(new Ui::MainWindow)
  6. {
  7.     ui->setupUi(this);
  8.     Init_UI();
  9.     //传递主程序指针给插件管理器
  10.     PluginManager::instance()->m_mainWin = this;
  11.     //绑定主程序和插件管理器消息信号槽
  12.     connect(this,&MainWindow::sendMsgToManager,PluginManager::instance(),&PluginManager::recMsgFromPlugin);
  13.     //嗅探到的所有插件
  14.     qDebug()<<"嗅探插件: "<<PluginManager::instance()->CK_allPluginsName().keys();
  15.     //加载所有插件
  16.     foreach(QString pluginName , PluginManager::instance()->CK_allPluginsName().keys()) {
  17.         PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value(pluginName));
  18.     }
  19.     //加载所有插件
  20. //    PluginManager::instance()->loadAllPlugins();
  21.     //加载存在依赖稍候处理的插件
  22.     while(!PluginManager::instance()->m_remainPlugin.isEmpty()) {
  23.         QString plugin_filePath = PluginManager::instance()->m_remainPlugin.pop();
  24.         qDebug()<<endl<<endl<<"加载存在依赖稍候处理的插件: "<<plugin_filePath;
  25.         PluginManager::instance()->loadPlugin(plugin_filePath);
  26.     }
  27.     //加载其中某个插件
  28. //    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginA"));
  29. //    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginB"));
  30. //    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginC"));
  31. //    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginD"));
  32. //    QPluginLoader *loader1 = PluginManager::instance()->getPlugin("pluginA");
  33. //    PluginInterface* pluginInterface1 = qobject_cast<PluginInterface *>(loader1->instance());
  34. //    pluginInterface1->showSomeThing("新增接口API");
  35. //    QPluginLoader *loader2 = PluginManager::instance()->getPlugin("pluginB");
  36. //    PluginInterface* pluginInterface2 = qobject_cast<PluginInterface *>(loader2->instance());
  37. //    pluginInterface2->showSomeThing("新增接口API");
  38. //    //通信测试
  39. //    //================================================================================
  40. //    QPluginLoader *loader1 = PluginManager::instance()->getPlugin("pluginA");
  41. //    if(loader1) {
  42. //        PluginInterface *pluginA = dynamic_cast<PluginInterface*>(loader1->instance());
  43. //        if(pluginA) {
  44. //            PluginMetaData m;
  45. //            m.dest = "pluginB";
  46. //            m.from = "pluginA";
  47. //            m.msg = "插件A发给插件B的消息";
  48. //            pluginA->sendMsgToManager(m);
  49. //        }
  50. //    }
  51. //    QPluginLoader *loader2 = PluginManager::instance()->getPlugin("pluginB");
  52. //    if(loader2) {
  53. //        PluginInterface *pluginB = dynamic_cast<PluginInterface*>(loader2->instance());
  54. //        if(pluginB) {
  55. //            PluginMetaData m;
  56. //            m.dest = "pluginA";
  57. //            m.from = "pluginB";
  58. //            m.msg = "插件B发给插件A的消息";
  59. //            pluginB->sendMsgToManager(m);
  60. //        }
  61. //    }
  62. //    //------------------------------
  63. //    if(loader2) {
  64. //        PluginInterface *pluginB = dynamic_cast<PluginInterface*>(loader2->instance());
  65. //        if(pluginB) {
  66. //            PluginMetaData m1;
  67. //            m1.dest = "mainWin";
  68. //            m1.from = "pluginB";
  69. //            m1.msg = "插件B发给主程序的消息";
  70. //            pluginB->sendMsgToManager(m1);
  71. //        }
  72. //    }
  73. //    //------------------------------
  74. //    PluginMetaData m2;
  75. //    m2.dest = "pluginA";
  76. //    m2.from = "mainWin";
  77. //    m2.msg = "主程序发给插件A的消息";
  78. //    this->sendMsgToManager(m2);
  79. }
  80. MainWindow::~MainWindow()
  81. {
  82.     delete ui;
  83. }
  84. void MainWindow::Init_UI()
  85. {
  86.     QWidget* p = takeCentralWidget();   //删除中央窗体
  87.     if (p) {
  88.         delete p;
  89.     }
  90.     setDockNestingEnabled(true);        //允许嵌套dock
  91.     //-------------------------------------------------
  92.     menuBar = new QMenuBar(this);
  93.     menuFile = new QMenu("文件", this);
  94.     menuBar->addMenu(menuFile);
  95.     this->setMenuBar(menuBar);
  96.     menuEdit = new QMenu("编辑", this);
  97.     menuBar->addMenu(menuEdit);
  98.     this->setMenuBar(menuBar);
  99.     menuView = new QMenu("视图", this);
  100.     menuBar->addMenu(menuView);
  101.     this->setMenuBar(menuBar);
  102.     menuTool = new QMenu("工具", this);
  103.     menuBar->addMenu(menuTool);
  104.     this->setMenuBar(menuBar);
  105.     connect(PluginManager::instance(),&PluginManager::sig_actions,this,&MainWindow::slot_PluginAction_MenuBar);
  106.     //-------------------------------------------------
  107.     tabWidget = new QTabWidget(this);
  108.     tabWidget->setMinimumSize(1000, 800);   // 设置最小宽高
  109.     setCentralWidget(tabWidget);            // 指定为中心窗口
  110.     connect(PluginManager::instance(),&PluginManager::sig_widget,this,&MainWindow::slot_PluginWidget);
  111.     //-------------------------------------------------
  112.     sdb = new SpeedDashBroad;
  113.     tabWidget->addTab(sdb,"表盘");
  114. }
  115. void MainWindow::slot_PluginAction_MenuBar(QString menu,QStringList actionList)
  116. {
  117.     QAction * action = nullptr;
  118.     if(menu == QString::fromLocal8Bit("menuFile")) {
  119.         for(int i=0; i<actionList.size(); ++i) {
  120.             action = new QAction(QIcon(), actionList.at(i), this);
  121.             menuFile->addAction(action);
  122.             connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
  123.         }
  124.     }
  125.     if(menu == QString::fromLocal8Bit("menuEdit")) {
  126.         for(int i=0; i<actionList.size(); ++i) {
  127.             action = new QAction(QIcon(), actionList.at(i), this);
  128.             menuEdit->addAction(action);
  129.             connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
  130.         }
  131.     }
  132.     if(menu == QString::fromLocal8Bit("menuView")) {
  133.         for(int i=0; i<actionList.size(); ++i) {
  134.             action = new QAction(QIcon(), actionList.at(i), this);
  135.             menuView->addAction(action);
  136.             connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
  137.         }
  138.     }
  139.     if(menu == QString::fromLocal8Bit("menuTool")) {
  140.         for(int i=0; i<actionList.size(); ++i) {
  141.             action = new QAction(QIcon(), actionList.at(i), this);
  142.             menuTool->addAction(action);
  143.             connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
  144.         }
  145.     }
  146. }
  147. void MainWindow::recvMsgFromManager(PluginMetaData metaData)
  148. {
  149.     qDebug()<<"主程序接收到消息:"<<metaData.msg;
  150. }
  151. void MainWindow::slot_PluginsAction_trigger(bool isChecked)
  152. {
  153.     QAction* action = qobject_cast<QAction*>(sender());
  154.     for(int i=0; i<PluginManager::instance()->_actionMap.size(); ++i) { //遍历插件管理器action映射表
  155.         if(PluginManager::instance()->_actionMap.at(i).action == action->text()) {  //映射表中匹配到Action对应的方法
  156.             PluginInterface* plugin = qobject_cast<PluginInterface *>(PluginManager::instance()->_actionMap.at(i).plugin->instance());  //获取该action对应的接口指针
  157.             if(plugin) {
  158.                 for(int j=0; j<plugin->_actionName.size(); ++j) {   //遍历该接口指针内的action名字
  159.                     if(plugin->_actionName[j] == action->text()) {
  160.                         plugin->_actionFunction[j](true);
  161.                         break;
  162.                     }
  163.                 }
  164.             }
  165.             break;
  166.         }
  167.     }
  168. }
  169. void MainWindow::slot_PluginWidget(QPluginLoader* loader,QString widget)
  170. {
  171.     if(widget == QString::fromLocal8Bit("tabWidget")) {
  172.         PluginInterface* pluginInterface = qobject_cast<PluginInterface *>(loader->instance());
  173.         QString pluginName = pluginInterface->_Plugin_Name;
  174.         QWidget* widget = pluginInterface->_widget;
  175.         if(widget) {
  176.             tabWidget->addTab(widget,pluginName);
  177.         }
  178.     }
  179.     //也可以预留布局接入点,插件UI嵌入,看自己需求
  180.     if(widget == QString::fromLocal8Bit("xxxLayout")) {
  181.     }
  182. }
复制代码

4.2、插件管理器

  1. #ifndef PLUGINMANAGER_H
  2. #define PLUGINMANAGER_H
  3. #include "../Plugin_Interface/PluginInterface.h"
  4. #include <QObject>
  5. #include <QPluginLoader>
  6. #include <QVariant>
  7. #include <QAction>
  8. #include <QStack>
  9. class MainWindow;
  10. typedef struct manager_action_map
  11. {
  12.     QString action;
  13.     QPluginLoader* plugin;
  14. }MANAGER_ACTION_MAP;
  15. class PluginManager : public QObject
  16. {
  17.     Q_OBJECT
  18. public:
  19.     explicit PluginManager(QObject *parent = nullptr);
  20.     ~PluginManager();
  21.     static PluginManager *instance(){
  22.          if(m_instance==nullptr)
  23.              m_instance=new PluginManager();
  24.          return m_instance;
  25.      }
  26.     MainWindow* m_mainWin;
  27.     QStack<QString> m_remainPlugin;
  28. public:
  29.     QList<MANAGER_ACTION_MAP> _actionMap;
  30.     void deal_metaData(QPluginLoader* loader,QJsonObject& json);
  31. public:
  32.     //扫描JSON文件中的插件元数据
  33.     void scanMetaData(const QString &filepath,QJsonObject& json);
  34.      //加载所有插件
  35.      void loadAllPlugins();
  36.      //加载其中某个插件
  37.      void loadPlugin(const QString &filepath);
  38.      //卸载所有插件
  39.      void unloadAllPlugins();
  40.      //卸载某个插件
  41.      void unloadPlugin(const QString &filepath);
  42.      //获取所有插件名称
  43.      QList<QVariant> allPluginsName();
  44.      //获取所有插件
  45.      QList<QPluginLoader *> allPlugins();
  46.      //获取某个插件名称
  47.      QVariant getPluginName(QPluginLoader *loader);
  48.      //根据名称获得插件
  49.      QPluginLoader* getPlugin(const QString &name);
  50.      //获取库中所有插件名称
  51.      QHash<QString,QString> CK_allPluginsName();
  52. signals:
  53.      void sig_actions(QString,QStringList);
  54.      void sig_widget(QPluginLoader*,QString);
  55. public slots:
  56.      void recMsgFromPlugin(PluginMetaData);
  57.      void slot_test();
  58. private:
  59.      static PluginManager *m_instance;
  60.      class PluginsManagerPrivate;
  61.      PluginsManagerPrivate *managerPrivate;
  62. };
  63. #endif // PLUGINMANAGER_H
复制代码
  1. #include "PluginManager.h"
  2. #include <QDir>
  3. #include <QCoreApplication>
  4. #include <QJsonArray>
  5. #include <QDebug>
  6. #include "mainwindow.h"
  7. PluginManager* PluginManager::m_instance=nullptr;
  8. class PluginManager::PluginsManagerPrivate
  9. {
  10. public:
  11.     PluginsManagerPrivate()
  12.     {
  13.         m_names.clear();
  14.         m_versions.clear();
  15.         m_dependencies.clear();
  16.         m_loaders.clear();
  17.         m_dependencies_temp.clear();
  18.     }
  19.     ~PluginsManagerPrivate(){}
  20.     QHash<QString, QVariant> m_names;               //插件路径--插件名称
  21.     QHash<QString, QVariant> m_versions;            //插件路径--插件版本
  22.     QHash<QString, QVariantList> m_dependencies;    //插件路径--插件额外依赖的其他插件
  23.     QHash<QString, QPluginLoader *> m_loaders;      //插件路径--QPluginLoader实例
  24.     QHash<QString, QVariantList> m_dependencies_temp;
  25.     bool check(const QString &filepath)             //插件依赖检测
  26.     {
  27.         //qDebug()<<QString("=============== bool check(%1) ===============").arg(filepath);
  28.         bool status = true;
  29.         foreach (QVariant item, m_dependencies_temp.value(filepath)) {
  30.             QString dependencyPluginInfo = item.toString();
  31.             // 依赖的插件名称、版本、路径
  32.             QStringList List = dependencyPluginInfo.split(':');
  33.             QString name_str = List[0];
  34.             QString version_str = List[1];
  35.             QString path = m_names.key(name_str);
  36.             qDebug()<<"=== 插件依赖信息 ===";
  37.             qDebug()<<"name_str: "<<name_str;
  38.             qDebug()<<"version_str: "<<version_str;
  39.             qDebug()<<"path: "<<path;
  40.             QVariant name = QVariant(name_str);
  41.             QVariant version = QVariant(version_str);
  42.             /********** 检测插件是否依赖于其他插件 **********/
  43.             // 先检测插件名称
  44.             if (!m_names.values().contains(name)) {
  45.                 qDebug() << "=== 插件" << filepath <<"  缺少依赖插件:" << name.toString();
  46.                 status = false;
  47.                 continue;
  48.             }
  49.             // 再检测插件版本
  50.             if (m_versions.value(path) != version) {
  51.                 qDebug() << "=== 依赖插件: " << name.toString() << "当前版本为: "
  52.                          << m_versions.value(m_names.key(name)).toString() << "但是需要依赖插件版本为: " << version.toString();
  53.                 status = false;
  54.                 continue;
  55.             }
  56.             // 然后,检测被依赖的插件是否还依赖于另外的插件
  57.             if (!check(path)) {
  58.                 qDebug() << "=== 依赖插件:" << name.toString() << "又依赖: " << path;
  59.                 status = false;
  60.                 continue;
  61.             }
  62.         }
  63.         //qDebug()<<"status: "<<status;
  64.         return status;
  65.     }
  66. };
  67. PluginManager::PluginManager(QObject *parent) : QObject(parent)
  68. {
  69.     managerPrivate = new PluginsManagerPrivate;
  70. }
  71. PluginManager::~PluginManager()
  72. {
  73.     delete managerPrivate;
  74. }
  75. void PluginManager::loadAllPlugins()
  76. {
  77.     QDir pluginsDir(qApp->applicationDirPath());    //pluginsDir: "../build-xxx-debug/debug"
  78.     if(pluginsDir.dirName().toLower() == "debug" ||
  79.             pluginsDir.dirName().toLower() == "release") {
  80.         pluginsDir.cdUp();  //pluginsDir: "../build-xxx-debug"
  81.         pluginsDir.cdUp();  //pluginsDir: "../"
  82.     }
  83.     pluginsDir.cd("plugins");
  84.     QFileInfoList pluginsInfo = pluginsDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
  85.     //加载插件
  86.     for(QFileInfo fileinfo : pluginsInfo)
  87.         loadPlugin(fileinfo.absoluteFilePath());
  88. }
  89. void PluginManager::scanMetaData(const QString &filepath,QJsonObject& json)
  90. {
  91.     //判断是否为库(后缀有效性)
  92.     if(!QLibrary::isLibrary(filepath))
  93.         return;
  94.     if(managerPrivate->m_names.keys().contains(filepath)) {
  95.         //qDebug()<<QString("插件: %1 已加载,退出!!!").arg(filepath);
  96.         return;
  97.     }
  98.     //获取元数据
  99.     QPluginLoader *loader = new QPluginLoader(filepath);
  100.     //qDebug()<<loader->metaData().keys();
  101.     json = loader->metaData().value("MetaData").toObject();
  102. //    for(int i=0; i<json.keys().size(); ++i) {
  103. //        qDebug()<<json.keys().at(i)<< " : "<<json.value(json.keys().at(i));
  104. //    }
  105.     managerPrivate->m_names.insert(filepath, json.value("name").toVariant());
  106.     managerPrivate->m_versions.insert(filepath, json.value("version").toVariant());
  107.     managerPrivate->m_dependencies.insert(filepath, json.value("dependencies").toArray().toVariantList());
  108.     //qDebug()<<"dependencies: "<<json.value("dependencies").toArray().toVariantList();
  109.     //qDebug()<<"managerPrivate->m_dependencies: "<<managerPrivate->m_dependencies.values();
  110.     delete loader;
  111.     loader = nullptr;
  112. }
  113. void PluginManager::loadPlugin(const QString &filepath)
  114. {
  115.     //库文件类型检测
  116.     if(!QLibrary::isLibrary(filepath))
  117.         return;
  118.     //读取当前插件依赖
  119.     qDebug()<<"===========================================================================";
  120.     QPluginLoader *loader_temp = new QPluginLoader(filepath);
  121.     QJsonObject json_temp = loader_temp->metaData().value("MetaData").toObject();
  122.     managerPrivate->m_dependencies_temp.insert(filepath, json_temp.value("dependencies").toArray().toVariantList());
  123.     //qDebug()<<"managerPrivate->m_dependencies_temp: "<<managerPrivate->m_dependencies_temp;
  124.     delete loader_temp;
  125.     loader_temp = nullptr;
  126.     qDebug()<<"@@@ 当前加载插件: "<<filepath;
  127.     //检测依赖
  128.     if(!managerPrivate->check(filepath)) {
  129.         qDebug()<<"当前插件存在依赖,入栈,稍候处理: "<<filepath;
  130.         m_remainPlugin.push(filepath);
  131.         //清空当前插件依赖
  132.         managerPrivate->m_dependencies_temp.clear();
  133.         return;
  134.     }
  135.     //清空当前插件依赖
  136.     managerPrivate->m_dependencies_temp.clear();
  137.     //检测当前插件是否已加载
  138.     if(managerPrivate->m_loaders.keys().contains(filepath)) {
  139.         qDebug()<<"当前插件已加载!!!";
  140.         return;
  141.     }
  142.     //加载插件
  143.     QPluginLoader *loader = new QPluginLoader(filepath);
  144.     if(loader->load()) {
  145.         PluginInterface *plugin = qobject_cast<PluginInterface *>(loader->instance());
  146.         if(plugin) {
  147.             //检测元信息
  148.             QJsonObject json;
  149.             scanMetaData(filepath,json);
  150.             deal_metaData(loader,json);
  151.             managerPrivate->m_loaders.insert(filepath, loader);
  152.             connect(loader->instance(),SIGNAL(sendMsgToManager(PluginMetaData)),
  153.                     this,SLOT(recMsgFromPlugin(PluginMetaData)));
  154.             //绑定
  155.             if(plugin->_Plugin_Name == QString::fromLocal8Bit("PluginA")) {
  156.                 //qDebug()<<"plugin->_Plugin_Name: "<<plugin->_Plugin_Name;
  157.                 connect(loader->instance(),SIGNAL(sig_test()),
  158.                         this,SLOT(slot_test()));
  159.             }
  160.             plugin->Info(QString(" %1 加载成功!").arg(plugin->_Plugin_Name));
  161.         }else {
  162.             delete loader;
  163.             loader = nullptr;
  164.         }
  165.     }else{
  166.         qDebug()<<"loadPlugin:"<<filepath<<loader->errorString();
  167.     }
  168. }
  169. void PluginManager::unloadAllPlugins()
  170. {
  171.     for(QString filepath : managerPrivate->m_loaders.keys())
  172.         unloadPlugin(filepath);
  173. }
  174. void PluginManager::unloadPlugin(const QString &filepath)
  175. {
  176.     if(!managerPrivate->m_loaders.keys().contains(filepath)) {
  177.         return;
  178.     }
  179.     QPluginLoader *loader = managerPrivate->m_loaders.value(filepath);
  180.     //卸载插件,并从内部数据结构中移除
  181.     if(loader->unload()) {
  182.         PluginInterface *plugin = qobject_cast<PluginInterface *>(loader->instance());
  183.         if(plugin) {
  184.             plugin->Info("插件卸载成功!");
  185.             managerPrivate->m_loaders.remove(filepath);
  186.             delete loader;
  187.             loader = nullptr;
  188.         }
  189.     }
  190. }
  191. QList<QPluginLoader *> PluginManager::allPlugins()
  192. {
  193.     return managerPrivate->m_loaders.values();
  194. }
  195. QList<QVariant> PluginManager::allPluginsName()
  196. {
  197.     return managerPrivate->m_names.values();
  198. }
  199. QVariant PluginManager::getPluginName(QPluginLoader *loader)
  200. {
  201.     if(loader)
  202.         return managerPrivate->m_names.value(managerPrivate->m_loaders.key(loader));
  203.     else
  204.         return "";
  205. }
  206. QPluginLoader *PluginManager::getPlugin(const QString &name)
  207. {
  208.     return managerPrivate->m_loaders.value(managerPrivate->m_names.key(name));
  209. }
  210. void PluginManager::recMsgFromPlugin(PluginMetaData metaData)
  211. {
  212.     //和主程序通信
  213.     //------------------------------------------------------------
  214.     if(metaData.dest == QString::fromLocal8Bit("mainWin")) {
  215.         if(m_mainWin) {
  216.             m_mainWin->recvMsgFromManager(metaData);
  217.         }
  218.         return;
  219.     }
  220.     //和插件通信
  221.     //------------------------------------------------------------
  222.     auto loader = getPlugin(metaData.dest); //目标插件
  223.     if(loader) {
  224.         auto interface = qobject_cast<PluginInterface*>(loader->instance());
  225.         if(interface) {
  226.             interface->recMsgFromManager(metaData); //转发给对应的插件
  227.         }
  228.     }
  229. }
  230. void PluginManager::slot_test()
  231. {
  232.     //qDebug()<<"触发槽函数: PluginManager::slot_test()";
  233. }
  234. QHash<QString,QString> PluginManager::CK_allPluginsName()
  235. {
  236.     QDir pluginsDir(qApp->applicationDirPath());    //pluginsDir: "../build-xxx-debug/debug"
  237.     if(pluginsDir.dirName().toLower() == "debug" ||
  238.             pluginsDir.dirName().toLower() == "release") {
  239.         pluginsDir.cdUp();  //pluginsDir: "../build-xxx-debug"
  240.         pluginsDir.cdUp();  //pluginsDir: "../"
  241.     }
  242.     pluginsDir.cd("plugins");
  243.     QFileInfoList pluginsInfo = pluginsDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
  244.     //库中插件
  245.     QHash<QString,QString> pluginNames;
  246.     for(QFileInfo fileinfo : pluginsInfo){
  247.         if(fileinfo.fileName().contains(".dll")) {
  248.             QString pluginName = fileinfo.fileName().mid(0,fileinfo.fileName().size()-4);
  249.             QString pluginPath = fileinfo.filePath();
  250.             pluginNames.insert(pluginName,pluginPath);
  251.         }
  252.     }
  253.     return pluginNames;
  254. }
  255. void PluginManager::deal_metaData(QPluginLoader* loader,QJsonObject& json)
  256. {
  257.     QString name;
  258.     if(json.keys().contains("name")) {
  259.         QJsonValue JValue = json.value("name").toString();
  260.         name = JValue.toString();
  261.     }
  262.     //------------------------------------------------------------
  263.     QString menu;
  264.     QStringList actionList;
  265.     if(json.keys().contains("menu")) {
  266.         QJsonValue JValue = json.value("menu").toString();
  267.         menu = JValue.toString();
  268.     }
  269.     if(json.keys().contains("action")) {
  270.        QJsonArray JArray = json.value("action").toArray();
  271.        for(int i=0;i<JArray.size();++i) {
  272.            actionList << JArray.at(i).toString();
  273.            MANAGER_ACTION_MAP manager_action_map;
  274.            manager_action_map.action = JArray.at(i).toString();
  275.            manager_action_map.plugin = loader;
  276.            _actionMap.push_back(manager_action_map);
  277.        }
  278.     }
  279.     QStringList dependencies_List;
  280.     if(json.keys().contains("dependencies")) {
  281.        QJsonArray JArray = json.value("dependencies").toArray();
  282.        for(int i=0;i<JArray.size();++i) {
  283.            dependencies_List << JArray.at(i).toString();
  284.        }
  285.     }
  286.     //qDebug()<<"dependencies_List: "<<dependencies_List;
  287.     //------------------------------------------------------------
  288.     if(!menu.isEmpty() && !actionList.empty()) {
  289.         emit sig_actions(menu,actionList);
  290.     }
  291.     //------------------------------------------------------------
  292.     //------------------------------------------------------------
  293.     QString widget;
  294.     if(json.keys().contains("widget")) {
  295.         QJsonValue JValue = json.value("widget").toString();
  296.         widget = JValue.toString();
  297.         if(!widget.isEmpty()) {
  298.             sig_widget(loader,widget);  //发送:插件对象、主界面预留接入点
  299.         }
  300.     }
  301.     //------------------------------------------------------------
  302. }
复制代码

4.3、插件A

pluginA.json
  1. {
  2.     "author" : "Wang_JC",
  3.     "date" : "2022/02/16",
  4.     "name" : "pluginA",
  5.     "version" : "1.0.0",
  6.     "des" : "这是一个插件A",
  7.     "dependencies" : ["pluginB:1.0.0","pluginC:1.0.0"],
  8.     "menu" : "menuFile",
  9.     "action" : ["action_A1","action_A2","action_A3"],
  10.     "widget" : "tabWidget"
  11. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表