Qtライブラリで拡張システムを作成する

プラグイン(拡張機能)



拡張機能は、メインアプリケーションの実行中にロードされるように設計された共有動的ライブラリであり、少なくとも1つの特別なインターフェイスを実装する必要があります。



拡張機能は2つのタイプに分けられます。









独自の拡張システムとその拡張機能自体を作成する方法を理解しましょう。

拡張機能との通信は、インターフェイス(信号、スロット、クラスメソッド)を使用して実行されます。 拡張機能は、 QPluginLoaderクラスを使用してアプリケーションによってロードされます。 拡張機能をロードするには、 instance()メソッドを使用します。このメソッドは、拡張機能オブジェクトを作成し、それへのポインターを返します。 unload()メソッド 、拡張機能をアンロードするために使用されます。







パート1



最初の例では、拡張機能から関数(アルゴリズム、式)を使用する拡張機能を作成します。



プロジェクトの視覚的なスキームは次のようになります。











ステージ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:



拡張機能をダウンロードする基本的なアプリケーションを作成しましょう。 ボタンを押すと、拡張機能が検索され、システムにロードされます。 さらにインターフェースを通じて、関数を使用します。



基本アプリケーション:



mainproject.h







 //--------------------------------------------------- #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:



拡張機能を作成するには、最初に行うことはプロファイルでビルドされるプロジェクトのタイプを変更することです。このため、次の行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フォルダーに移動して開始します。 この場合、拡張機能はメインプログラムにロードされ、単一の拡張機能オブジェクトが作成されます。 インスタンス()関数を再利用しようとすると、関数は既に作成されている拡張オブジェクトへのポインターを返します。



プログラム実行











パート2







タスクを複雑にするために、今度は拡張機能がウィジェットであり、そのようなウィジェットをいくつか作成できる必要があります。 メインプログラムはプラグインからメッセージを受信し、応答を送り返します。 新しいプロジェクトを作成しましょう。最初の段階では、2つのクラスのインターフェイスが必要です。1つは拡張機能のロードとウィジェットの作成を担当し、もう1つはウィジェット自体の操作を担当します。



プロジェクトのスキームは次のようになります。











ステージ1:



最初のインターフェイスクラスには、プラグイン名を取得するプラグインウィジェットを取得する2つの関数があります。 プラグインの名前は、システムで識別できるように保存されます。 メインアプリケーションのMDIウィンドウにプラグインウィジェットを追加します。







2番目のクラスはグラフィカルウィジェット自体であり、QWidgetから継承されます。ここで必要な機能を指定しました。ウィジェットはメッセージを受信し、メインプログラムに送信します。



interface.h







 //------------------------------------------------------------------------- #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ウィンドウに配置すると、プラグインオブジェクト自体をシステムからアンロードできます。



mainproject.h







 //------------------------------------------------ #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()); } //-------------------------------------------------------------------
      
      





メインプログラムの出力:










All Articles