Crear un sistema de extensi贸n en la biblioteca Qt

Complementos (extensiones)


Extensions es una biblioteca din谩mica compartida dise帽ada para cargarse durante la ejecuci贸n de la aplicaci贸n principal, que necesariamente debe implementar al menos una interfaz especial.

Las extensiones se dividen en dos tipos:

  • Para Qt
  • Para aplicaciones nativas

Vamos a descubrir c贸mo crear su propio sistema de extensi贸n y las extensiones en s铆.

La comunicaci贸n con la extensi贸n se lleva a cabo utilizando la interfaz (se帽ales, slots y m茅todos de clase). La aplicaci贸n carga la extensi贸n utilizando la clase QPluginLoader . Para cargar la extensi贸n, se utiliza el m茅todo instancia () , que crea un objeto de extensi贸n y le devuelve un puntero. El m茅todo unload () se usa para descargar la extensi贸n.

Parte 1


En el primer ejemplo, cree una extensi贸n que usar谩 una funci贸n (algoritmo, f贸rmula) de la extensi贸n.

El esquema visual del proyecto tendr谩 el siguiente aspecto.



Etapa 1:


El primer paso es crear una clase de interfaz heredada de QObject, como interfaz habr谩 un m茅todo que acepte una variable de tipo QString y devuelva la misma cadena en may煤sculas. Usando la macro Q_DECLARE_INTERFACE, establecemos el identificador de las interfaces, el compilador c genera metainformaci贸n para la cadena del identificador. Este m贸dulo es el protocolo de comunicaci贸n entre el complemento y el programa principal y se utilizar谩 en el proyecto del complemento y en el proyecto principal.

La clase se ver谩 de la siguiente manera.

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


Etapa 2:


Creemos una aplicaci贸n b谩sica que descargar谩 la extensi贸n. Al presionar el bot贸n, la extensi贸n se buscar谩 y se cargar谩 en el sistema. Adem谩s a trav茅s de la interfaz usaremos nuestra funci贸n.

Aplicaci贸n base:

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


Etapa 3:


Al crear una extensi贸n, lo primero que debe hacer es cambiar el tipo de proyecto que se est谩 construyendo en el archivo pro, para esto debe agregar la siguiente l铆nea TEMPLATE = lib, y establecer la configuraci贸n del proyecto para la extensi贸n del complemento 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 

A continuaci贸n, creamos una clase para la futura extensi贸n, la clase debe heredarse de la clase de interfaces. Macro Q_INTERFACES , necesita el compilador para generar toda la metainformaci贸n necesaria para la extensi贸n. La macro Q_PLUGIN_METADATA () establece el punto de entrada a la extensi贸n y el acceso a la biblioteca Qt. Tambi茅n debe crear un archivo inteface.json con metainformaci贸n (el archivo debe estar en la ra铆z del proyecto), en nuestro caso no hay informaci贸n all铆, as铆 que simplemente escriba comillas vac铆as {} en el archivo.

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

En la salida de compilar el proyecto, obtenemos un archivo con la extensi贸n .so, movemos este archivo a la carpeta Plugins del proyecto principal y lo iniciamos. En este caso, la extensi贸n se carga en el programa principal y se crea un 煤nico objeto de extensi贸n. Si intenta reutilizar la funci贸n instancia (), la funci贸n devolver谩 un puntero al objeto de extensi贸n ya creado.

Ejecuci贸n del programa



Parte 2


Para complicar nuestra tarea, ahora necesitamos que la extensi贸n sea un widget y la capacidad de crear varios de estos widgets. El programa principal recibir谩 mensajes de complementos y enviar谩 una respuesta. Crearemos nuevos proyectos, en la primera etapa necesitaremos dos clases de interfaces, una ser谩 responsable de cargar la extensi贸n y crear el widget, y la otra para el funcionamiento del widget en s铆.

El esquema del proyecto tendr谩 el siguiente aspecto:



Etapa 1:


La primera clase de interfaz tendr谩 dos funciones: obtener el nombre del complemento y obtener el widget del complemento. El nombre del complemento se almacenar谩 para su identificaci贸n en el sistema. Agregaremos el widget de complemento a las ventanas MDI de la aplicaci贸n principal.

La segunda clase es el widget gr谩fico en s铆, se hereda de QWidget, aqu铆 hemos especificado las funciones que necesitamos, el widget recibir谩 un mensaje y lo enviar谩 al programa principal.

interfaz.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 //------------------------------------------------------------------------- 

Etapa 2:


El programa principal consta de una ventana MDI, en la que hay un widget principal para recibir mensajes de complementos y ventanas adicionales que aparecen din谩micamente a medida que se llaman los complementos.

Al crear un widget de complemento, conectamos la se帽al del complemento a la ranura y, mediante la funci贸n remitente (), obtenemos un puntero al complemento que envi贸 el mensaje. Colocamos el widget creado en la ventana MDI, y el objeto del complemento en s铆 mismo puede descargarse del sistema.

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鈫抯lot_getText(str); widget->slot_getText(" "); widget鈫抯lot_getText("------------------------------"); pPlug->slot_getText(" "); } //------------------------------------------------ 

La ventana principal acepta el mensaje y lo muestra.

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

Etapa 2:


Creamos un complemento, su idea es que sea una f谩brica para crear un widget.

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

Widget creado por el complemento.

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

La salida del programa principal:

Source: https://habr.com/ru/post/448806/


All Articles