在Qt库上创建扩展系统

插件(扩展名)


扩展是一个共享的动态库,旨在在执行主应用程序时加载,该程序必须实现至少一个特殊接口。

扩展分为两种类型:

  • 对于Qt
  • 对于本机应用

让我们弄清楚如何创建自己的扩展系统以及扩展本身。

与扩展的通信是使用接口(信号,插槽和类方法)进行的。 该扩展由应用程序使用QPluginLoader类加载。 要加载扩展,请使用instance()方法,该方法创建一个扩展对象并返回指向该对象的指针。 unload()方法用于卸载扩展。

第一部分


在第一个示例中,创建一个扩展,该扩展将使用该扩展中的函数(算法,公式)。

该项目的视觉方案将如下所示。



阶段1:


第一步是创建一个继承自QObject的接口类,作为接口,将有一个方法采用QString类型的变量并以大写形式返回相同的字符串。 使用Q_DECLARE_INTERFACE宏,设置接口的标识符,编译器c生成标识符字符串的元信息。 该模块是插件和主程序之间的通信协议,将在插件项目和主项目中使用。

该类如下所示。

//--------------------------------------------------- #ifndef INTERFACE_H #define INTERFACE_H //------------------------------------------------------- #include <QObject> //------------------------------------------------------- class interface : public QObject { public: /// \brief   virtual ~interface() = default; /// \brief   virtual QString getUpString(QString str) = 0; }; //---------------------------------------------------------------- Q_DECLARE_INTERFACE(interface, "com.mysoft.Application.interface") //---------------------------------------------------------------- #endif // INTERFACE_H //---------------------------------------------------------------- 


阶段2:


让我们创建一个将下载扩展的基本应用程序。 按下按钮,将搜索该扩展名并将其加载到系统中。 进一步通过界面,我们将使用我们的功能。

基本应用程序:

主项目

 //--------------------------------------------------- #ifndef MAINPROJECT_H #define MAINPROJECT_H //------------------------------------------------------- #include <QWidget> #include <QPluginLoader> #include <QDir> #include "interface.h" //------------------------------------------------------- namespace Ui { class mainProject; } //------------------------------------------------------- class mainProject : public QWidget { Q_OBJECT public: /// \brief  explicit mainProject(QWidget *parent = nullptr); /// \brief  ~mainProject(); private slots: /// \brief   void on_searchPlugin_clicked(); /// \brief   void on_getUp_clicked(); private: Ui::mainProject *ui; interface *pluginObject; ///<     }; //------------------------------------------------------- #endif // MAINPROJECT_H //------------------------------------------------------- 

mainproject.cpp

 //--------------------------------------------------- #include "mainproject.h" #include "ui_mainproject.h" //------------------------------------------------------- mainProject::mainProject(QWidget *parent) : QWidget(parent), ui(new Ui::mainProject) { ui->setupUi(this); } //------------------------------------------------------- mainProject::~mainProject() { delete ui; } //------------------------------------------------------- void mainProject::on_searchPlugin_clicked() { QStringList listFiles; QDir dir(QApplication::applicationDirPath() + "/Plugins/"); //      "Plugins" if(dir.exists()) listFiles = dir.entryList(QStringList("*"), QDir::Files); //     for(QString str: listFiles) { QPluginLoader loader(dir.absolutePath() + "/" +str); QObject *pobj = 0; //   pobj = qobject_cast<QObject*>(loader.instance()); if(!pobj) continue; pluginObject = 0; //   pluginObject = qobject_cast<interface *>(pobj); //      if(pluginObject) { ui->label->setText(" "); break; } } } //------------------------------------------------------- void mainProject::on_getUp_clicked() { QString tmp; tmp = ui->lineEdit->text(); //   getUpString() tmp = pluginObject->getUpString(tmp); ui->label_2->setText(tmp); } //------------------------------------------------------- 


阶段3:


创建扩展,首先要做的是更改pro文件中正在构建的项目的类型,为此,您需要添加以下行TEMPLATE = lib,并为CONFIG + =插件扩展设置项目配置。

upperstringplugin.pro

 #------------------------------------------------- # # Project created by QtCreator 2019-04-03T11:35:18 # #------------------------------------------------- QT += core greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = upperStringPlugin TEMPLATE = lib CONFIG += plugin DESTDIR = ../Plugins DEFINES += QT_DEPRECATED_WARNINGS CONFIG += c++11 SOURCES += \ upperstringplugin.cpp HEADERS += \ upperstringplugin.h \ interface.h 

接下来,我们为将来的扩展创建一个类,该类应从接口的类继承。 宏Q_INTERFACES ,您需要编译器为扩展生成所有必要的元信息。 Q_PLUGIN_METADATA()宏将入口点设置为扩展和对Qt库的访问。 您还需要创建一个具有元信息的inteface.json文件(该文件必须位于项目的根目录中),在本例中,该文件中没有任何信息,因此只需在文件中写空的引号{}。

upperstringplugin.h

 //--------------------------------------------------- #ifndef UPPERSTRINGPLUGIN_H #define UPPERSTRINGPLUGIN_H //--------------------------------------------------- #include "interface.h" //--------------------------------------------------- class upperStringPlugin : public interface { Q_OBJECT Q_INTERFACES(interface) Q_PLUGIN_METADATA(IID "com.mysoft.Application.interface" FILE "interface.json") public: explicit upperStringPlugin(); ~upperStringPlugin(); // interface interface public: QString getUpString(QString str); }; //--------------------------------------------------- #endif // UPPERSTRINGPLUGIN_H //--------------------------------------------------- 

upperstringplugin.cpp

 //--------------------------------------------------- #include "upperstringplugin.h" //--------------------------------------------------- upperStringPlugin::upperStringPlugin() {} //--------------------------------------------------- upperStringPlugin::~upperStringPlugin() {} //--------------------------------------------------- QString upperStringPlugin::getUpString(QString str) { return str.toUpper(); } //--------------------------------------------------- 

在编译项目的输出中,我们得到一个扩展名为.so的文件,将该文件移到主项目的Plugins文件夹中,然后启动它。 在这种情况下,扩展被加载到主程序中并创建一个扩展对象。 如果尝试重用instance()函数,该函数将返回一个指向已创建的扩展对象的指针。

程序执行



第二部分


为了使我们的任务复杂化,现在我们需要将扩展​​名添加为小部件,并具有创建多个此类小部件的能力。 主程序将从插件接收消息并发送回响应。 我们将创建新项目,在第一阶段,我们需要两类接口,一类负责加载扩展并创建小部件,另一类负责小部件本身的操作。

项目计划如下所示:



阶段1:


第一个接口类将具有两个函数,获取插件的名称和获取插件的小部件。 插件的名称将被存储以在系统中标识。 我们将插件小部件添加到主应用程序的MDI窗口中。

第二类是图形控件本身,它是从QWidget继承的,这里我们指定了所需的功能,该控件将接收一条消息并将其发送到主程序。

接口

 //------------------------------------------------------------------------- #ifndef INTERFACE_H #define INTERFACE_H //------------------------------------------------------------------------- #include <QWidget> class QString; //------------------------------------------------------------------------- class interface : public QObject { public: /// \brief  virtual ~interface(){} /// \brief    virtual QString getNamePlugin() = 0; /// \brief    virtual QObject *getPluginWidget() = 0; }; //------------------------------------------------------------------------- class interfaceWidget: public QWidget { public: /// \brief  virtual ~interfaceWidget() = default; signals: /// \brief      virtual void signal_writeText(QString str) = 0; public slots: /// \brief      virtual void slot_getText(QString str) = 0; }; //------------------------------------------------------------------------- Q_DECLARE_INTERFACE(interface, "com.mysoft.Application.interface") //------------------------------------------------------------------------- #endif // INTERFACE_H //------------------------------------------------------------------------- 

阶段2:


主程序包含一个MDI窗口,在该窗口中有一个主窗口小部件,用于接收来自插件的消息,以及在调用插件时动态显示的其他窗口。

创建插件窗口小部件时,我们将信号从插件连接到插槽,并使用sender()函数获得指向发送消息的插件的指针。 我们将创建的窗口小部件放置在MDI窗口中,然后可以从系统中卸载插件对象本身。

主项目

 //------------------------------------------------ #ifndef MAINPROJECT_H #define MAINPROJECT_H //------------------------------------------------ #include <QMainWindow> #include <QDir> #include <QPluginLoader> #include "interface.h" //------------------------------------------------ namespace Ui { class mainProject; } //------------------------------------------------ typedef struct str_plugin { QString namePlugin; ///<   QString dirPlugin; ///<   }TSTR_PLUGIN; //------------------------------------------------ class mainWidget; //------------------------------------------------ class mainProject : public QMainWindow { Q_OBJECT public: explicit mainProject(QWidget *parent = nullptr); ~mainProject(); private slots: void on_action_triggered(); /// \brief    void slot_showPlugin(); /// \brief          void slot_getTextFromPlugin(QString str); private: Ui::mainProject *ui; mainWidget *widget; ///<   QVector<TSTR_PLUGIN > vecPlugin; ///<   }; //------------------------------------------------ #endif // MAINPROJECT_H //------------------------------------------------ 

mainproject.cpp

 //------------------------------------------------ #include "mainproject.h" #include "ui_mainproject.h" #include "mainwidget.h" #include <QMdiSubWindow> //------------------------------------------------ mainProject::mainProject(QWidget *parent) : QMainWindow(parent), ui(new Ui::mainProject) { ui->setupUi(this); QMdiSubWindow *sWPS = new QMdiSubWindow; widget = new mainWidget(); sWPS->setWidget(widget); ui->mdiArea->addSubWindow(sWPS); } //------------------------------------------------ mainProject::~mainProject() { delete ui; } //------------------------------------------------ void mainProject::on_action_triggered() { ui->menu_2->clear(); QStringList listFiles; QDir dir(QApplication::applicationDirPath() + "/Plugins/"); if(dir.exists()) { listFiles = dir.entryList(QStringList("*"), QDir::Files); } for(QString str: listFiles) { QPluginLoader loader(dir.absolutePath() + "/" +str); QObject *pobj = 0; pobj = qobject_cast<QObject*>(loader.instance()); if(!pobj) continue; interface *plW = 0; plW = qobject_cast<interface *>(pobj); if(!plW) continue; QString namePlugin = plW->getNamePlugin(); QAction *action = new QAction(namePlugin); ui->menu_2->addAction(action); connect(action, SIGNAL(triggered()), this, SLOT(slot_showPlugin())); TSTR_PLUGIN plug; plug.namePlugin = namePlugin; plug.dirPlugin = dir.absolutePath() + "/" +str; vecPlugin.push_back(plug); delete plW; } } //------------------------------------------------ void mainProject::slot_showPlugin() { QObject *pobj = sender(); QAction *action = qobject_cast<QAction *>(pobj); QString namePlugin = action->iconText(); for(int i = 0; i < vecPlugin.size(); i++) { if(namePlugin == vecPlugin[i].namePlugin) { QMdiSubWindow *sWPS = new QMdiSubWindow; ui->mdiArea->addSubWindow(sWPS); sWPS->setAttribute(Qt::WA_DeleteOnClose, true); QPluginLoader loader(vecPlugin[i].dirPlugin); QObject *pobj = qobject_cast<QObject*>(loader.instance()); if(!pobj) continue; interface *plW = qobject_cast<interface *>(pobj); if(!plW) continue; QObject *ob = plW->getPluginWidget(); if(!ob) continue; interfaceWidget *interFaceW = dynamic_cast<interfaceWidget *>(ob); if(!interFaceW) continue; sWPS->setWidget(interFaceW); sWPS->show(); QSize size = interFaceW->minimumSize(); size.setHeight(size.height() + 20); size.setWidth(size.width() + 20); sWPS->resize(size); loader.unload(); connect(interFaceW, SIGNAL(signal_writeText(QString)), this, SLOT(slot_getTextFromPlugin(QString))); } } } //------------------------------------------------ void mainProject::slot_getTextFromPlugin(QString str) { //     QObject *pobj = sender(); interfaceWidget *pPlug = dynamic_cast<interfaceWidget *>(pobj); widget->slot_getText("   "); widget→slot_getText(str); widget->slot_getText(" "); widget→slot_getText("------------------------------"); pPlug->slot_getText(" "); } //------------------------------------------------ 

主窗口接受该消息并显示。

mainwidget.h

 //---------------------------------------------------------- #ifndef MAINWIDGET_H #define MAINWIDGET_H //---------------------------------------------------------- #include <QWidget> //---------------------------------------------------------- namespace Ui { class mainWidget; } //---------------------------------------------------------- class mainWidget : public QWidget { Q_OBJECT public: explicit mainWidget(QWidget *parent = nullptr); ~mainWidget(); public slots: /// \brief      void slot_getText(QString str); private: Ui::mainWidget *ui; }; //---------------------------------------------------------- #endif // MAINWIDGET_H //---------------------------------------------------------- 

mainwidget.cpp

 //---------------------------------------------------------- #include "mainwidget.h" #include "ui_mainwidget.h" //---------------------------------------------------------- mainWidget::mainWidget(QWidget *parent) : QWidget(parent), ui(new Ui::mainWidget) { ui->setupUi(this); } //---------------------------------------------------------- mainWidget::~mainWidget() { delete ui; } //---------------------------------------------------------- void mainWidget::slot_getText(QString str) { ui->textEdit->append(str); } //---------------------------------------------------------- 

阶段2:


我们创建一个插件,它的想法是它是一个用于创建小部件的工厂。

plugin.h

 //------------------------------------------------- #ifndef PLUGIN_H #define PLUGIN_H //------------------------------------------------- #include "interface.h" #include "texttranferwidget.h" //------------------------------------------------- class plugin : public interface { Q_OBJECT Q_INTERFACES(interface) Q_PLUGIN_METADATA(IID "com.mysoft.Application.interface" FILE "interface.json") public: explicit plugin(); ~plugin(); // interface interface public: /// \brief    QString getNamePlugin(); /// \brief    QObject *getPluginWidget(); }; //------------------------------------------------- #endif // PLUGIN_H //------------------------------------------------- 

plugin.cpp

 //------------------------------------------------- #include "plugin.h" //------------------------------------------------- plugin::plugin() { } //------------------------------------------------- plugin::~plugin() { } //------------------------------------------------- QString plugin::getNamePlugin() { return " 1"; } //------------------------------------------------- QObject *plugin::getPluginWidget() { textTranferWidget *widget = new textTranferWidget(); return qobject_cast<QObject *>(widget); } //------------------------------------------------- 

插件创建的小部件。

texttranferwidget.h

 //------------------------------------------------------------------- #ifndef TEXTTRANFERWIDGET_H #define TEXTTRANFERWIDGET_H //------------------------------------------------------------------- #include "interface.h" //------------------------------------------------------------------- namespace Ui { class textTranferWidget; } //------------------------------------------------------------------- class textTranferWidget : public interfaceWidget { Q_OBJECT public: /// \brief  explicit textTranferWidget(); /// \brief  ~textTranferWidget(); private: Ui::textTranferWidget *ui; // interfaceWidget interface signals: /// \brief      void signal_writeText(QString str); public slots: /// \brief      void slot_getText(QString str); private slots: void on_pushButton_clicked(); }; //------------------------------------------------------------------- #endif // TEXTTRANFERWIDGET_H //------------------------------------------------------------------- 

texttranferwidget.cpp

 //------------------------------------------------------------------- #include "texttranferwidget.h" #include "ui_texttranferwidget.h" //------------------------------------------------------------------- textTranferWidget::textTranferWidget() : ui(new Ui::textTranferWidget) { ui->setupUi(this); } //------------------------------------------------------------------- textTranferWidget::~textTranferWidget() { delete ui; } //------------------------------------------------------------------- void textTranferWidget::slot_getText(QString str) { ui->textEdit->append(str); } //------------------------------------------------------------------- void textTranferWidget::on_pushButton_clicked() { emit signal_writeText(ui->lineEdit->text()); } //------------------------------------------------------------------- 

主程序的输出:

Source: https://habr.com/ru/post/zh-CN448806/


All Articles