Send QJsonObject from plugin to main app
-
Hi, I have a main application that will load many future developed plugins with the same interface:
#ifndef PLUGIN_API_H #define PLUGIN_API_H #include <QString> #include <QDebug> class Plugin_API { public: virtual ~Plugin_API() = default; virtual QJsonObject data_from_plugin2app(void) = 0; virtual void open_ui(const int id) = 0; virtual void run(const int id) = 0; }; // Declare our interface: Q_DECLARE_INTERFACE(Plugin_API, "com.lamar.plugin") #endif // PLUGIN_HThe loaded plugins will be placed by the user in a custom serial sequence of execution.
Now I can call the
plugin->open_ui()and I get the plugin GUI on my screen. So I can fill the plugin input text with some data.My problem is:
I have to save this plugin data (QJsonObject) in a mainQJsonArray plugins_datathat is a variable located in the main application.How can I send the data from my plugin (*.dll) to my main application?
-
@jsulm it's not possible because I have many different plugins that share the same
Plugin_API...As you can see in the top, the
Plugin_APIhave all methods that I use in all different plugins.So, when I load all plugins inside a
foreach()loop, I have to cast they using thePlugin_API.Each individual
plugininherit thePlugin_APIclass.
And inside each individualpluginI have declared:class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_API { Q_OBJECT Q_PLUGIN_METADATA(IID "com.lamar.plugin") Q_INTERFACES(Plugin_API)What I'm doing wrong?
Thank you @SGaist and @jsulm
With your help I think that I found a solution! Here is the code:My plugin interface is called
Plugin_API. So theplugin_api.his:#ifndef PLUGIN_API_H #define PLUGIN_API_H #include <QString> #include <QDebug> #include <QJsonObject> #include <QObject> // You have to import and inherit QOBject in the plugin interface class Plugin_API : public QObject { // USE Q_OBJECT MACRO inside the interface Q_OBJECT public: virtual ~Plugin_API() = default; virtual QJsonObject get_data(void) = 0; virtual void set_project_path(const QString project_path) = 0; virtual void open_ui(const QJsonObject ui_data) = 0; virtual void run(const int job_id) = 0; // ===== SIGNALS ===== // // You have to declare the signals in the interface too: virtual void send_msg(const QString msg) = 0; }; // Declare our interface: Q_DECLARE_INTERFACE(Plugin_API, "com.lamar.plugin") #endif // PLUGIN_API_HAfter that, in the
plugin.hI have:// Do NOT inherit plublic QObject here: class PLUGINSHARED_EXPORT Plugin: public Plugin_API { // ADD Q_OBJECT MACRO HERE TOO: Q_OBJECT Q_PLUGIN_METADATA(IID "com.lamar.plugin") Q_INTERFACES(Plugin_API) ... // Overide the signal method: signals: void send_msg(const QString msg) override;In my Main Application header
main.hI have:public slots: void receive_msg(const QString msg);And finally, the implementaion of the main application slot is:
void main_app::receive_msg(const QString msg) { qDebug() << "I RECEIVE THIS MSG: " << msg; } -
Hi,
Well, you load your plugin and then call the corresponding method from its interface.
What have you tried ?
-
Hi,
Well, you load your plugin and then call the corresponding method from its interface.
What have you tried ?
@SGaist Sorry, but I'm not seeing how can I do it. Could you help me?
How the main application will know when the button
savewas clicked in the plugin UI window?
Is possible to inform that only using interfaces? Or I need to usesignals and slots.Today I tried to connect the plugin and the main app using
signals and slots.
So, inside theplugin.cppin theconstructor(), I type:connect(this, SIGNAL(send_msg(QString)), ???, SLOT(receive_msg(QString)));But, what I have to write in
????Obs.: I'm loading the plugins using
QPluginLoader:QPluginLoader loader(file); loader.load() Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance());I'm confused about this topic...
Could you please help me a little more? -
@SGaist Sorry, but I'm not seeing how can I do it. Could you help me?
How the main application will know when the button
savewas clicked in the plugin UI window?
Is possible to inform that only using interfaces? Or I need to usesignals and slots.Today I tried to connect the plugin and the main app using
signals and slots.
So, inside theplugin.cppin theconstructor(), I type:connect(this, SIGNAL(send_msg(QString)), ???, SLOT(receive_msg(QString)));But, what I have to write in
????Obs.: I'm loading the plugins using
QPluginLoader:QPluginLoader loader(file); loader.load() Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance());I'm confused about this topic...
Could you please help me a little more?@fem_dev Do not connect inside plug-in as it does not know anything about receiver of its signals (and it should not!).
Do the connect in main window (or where-ever you use the plug-in).
So, likeMainWindow::MainWindow(...) { connect(plugin, SIGNAL(send_msg(QString)), this, SLOT(receive_msg(QString))); }plugin->data_from_plugin2app(); -
@fem_dev Do not connect inside plug-in as it does not know anything about receiver of its signals (and it should not!).
Do the connect in main window (or where-ever you use the plug-in).
So, likeMainWindow::MainWindow(...) { connect(plugin, SIGNAL(send_msg(QString)), this, SLOT(receive_msg(QString))); }plugin->data_from_plugin2app();@jsulm thank you....I think that this is the half of solution...
foreach(QString file, plugins) { QPluginLoader loader(file); if(loader.load()) { Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance()); if(plugin) { // HERE I GOT A COMPILATION ERROR: // Cannot convert argument 1 from 'Plugin_API *' to 'const QObject *' connect(plugin, SIGNAL(send_msg(QString)), this, SLOT(receive_msg(QString))); } else { qCritical() << "Wrong Plugin API! Could not cast: " << loader.fileName(); } } else { qCritical() << "ERROR: " << loader.fileName() << " - Msg: " << loader.errorString(); } }Buy my
plugin.hhaveQ_OBJECTmacro:#ifndef PLUGIN_H #define PLUGIN_H #include <QObject> #include <QtPlugin> #include <QJsonDocument> #include <QJsonArray> #include <QJsonObject> #include <QFile> #include <QByteArray> #include "analysis_x_global.h" #include "../plugin_api.h" #include "dialog.h" class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_API { Q_OBJECT Q_PLUGIN_METADATA(IID "com.lamar.plugin") Q_INTERFACES(Plugin_API) public: explicit Plugin(QObject* parent = nullptr); ~Plugin() override; QJsonObject get_data(void) override; void open_ui(const QJsonObject ui_data) override; void run(const int job_id) override; signals: void send_msg(const QString msg); public slots: void onMessage(QJsonObject updated_ui_data); }; #endif // PLUGIN_HSecond: to call a plugin method from the main app, I know that can be done using:
plugin->method()But my plugin have a Window (UI) and some buttons, like
save.
How can I send a plugin data to my main app when the user hits thesavebutton in the plugin Window UI? -
@jsulm thank you....I think that this is the half of solution...
foreach(QString file, plugins) { QPluginLoader loader(file); if(loader.load()) { Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance()); if(plugin) { // HERE I GOT A COMPILATION ERROR: // Cannot convert argument 1 from 'Plugin_API *' to 'const QObject *' connect(plugin, SIGNAL(send_msg(QString)), this, SLOT(receive_msg(QString))); } else { qCritical() << "Wrong Plugin API! Could not cast: " << loader.fileName(); } } else { qCritical() << "ERROR: " << loader.fileName() << " - Msg: " << loader.errorString(); } }Buy my
plugin.hhaveQ_OBJECTmacro:#ifndef PLUGIN_H #define PLUGIN_H #include <QObject> #include <QtPlugin> #include <QJsonDocument> #include <QJsonArray> #include <QJsonObject> #include <QFile> #include <QByteArray> #include "analysis_x_global.h" #include "../plugin_api.h" #include "dialog.h" class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_API { Q_OBJECT Q_PLUGIN_METADATA(IID "com.lamar.plugin") Q_INTERFACES(Plugin_API) public: explicit Plugin(QObject* parent = nullptr); ~Plugin() override; QJsonObject get_data(void) override; void open_ui(const QJsonObject ui_data) override; void run(const int job_id) override; signals: void send_msg(const QString msg); public slots: void onMessage(QJsonObject updated_ui_data); }; #endif // PLUGIN_HSecond: to call a plugin method from the main app, I know that can be done using:
plugin->method()But my plugin have a Window (UI) and some buttons, like
save.
How can I send a plugin data to my main app when the user hits thesavebutton in the plugin Window UI?@fem_dev said in Send QJsonObject from plugin to main app:
How can I send a plugin data to my main app when the user hits the save button in the plugin Window UI?
Via signals/slots.
"Cannot convert argument 1 from 'Plugin_API *' to 'const QObject *'" - this is because your plug-in class is not derived from QObject and does not contain Q_OBJECT macro.
-
@fem_dev said in Send QJsonObject from plugin to main app:
How can I send a plugin data to my main app when the user hits the save button in the plugin Window UI?
Via signals/slots.
"Cannot convert argument 1 from 'Plugin_API *' to 'const QObject *'" - this is because your plug-in class is not derived from QObject and does not contain Q_OBJECT macro.
@jsulm please, look my
plugin.hheader above. It have theQ_OBJECTmacro.
And the class declaration is:class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_APIWhat is wrong?
I tried to add the
public QObjectandQ_OBJECTmacro inside theplugin_APIclass, but I got these compilation warnings/errors:'Plugin': base-class 'QObject' is already a base-class of 'Plugin_API' -
@jsulm please, look my
plugin.hheader above. It have theQ_OBJECTmacro.
And the class declaration is:class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_APIWhat is wrong?
I tried to add the
public QObjectandQ_OBJECTmacro inside theplugin_APIclass, but I got these compilation warnings/errors:'Plugin': base-class 'QObject' is already a base-class of 'Plugin_API'@fem_dev said in Send QJsonObject from plugin to main app:
What is wrong?
Problem is that plugin bellow is Plugin_API* and not Plugin*:
connect(plugin, SIGNAL(send_msg(QString)), this, SLOT(receive_msg(QString)));Cast to Plugin* instead of Plugin_API*.
-
@fem_dev said in Send QJsonObject from plugin to main app:
What is wrong?
Problem is that plugin bellow is Plugin_API* and not Plugin*:
connect(plugin, SIGNAL(send_msg(QString)), this, SLOT(receive_msg(QString)));Cast to Plugin* instead of Plugin_API*.
@jsulm it's not possible because I have many different plugins that share the same
Plugin_API...As you can see in the top, the
Plugin_APIhave all methods that I use in all different plugins.So, when I load all plugins inside a
foreach()loop, I have to cast they using thePlugin_API.Each individual
plugininherit thePlugin_APIclass.
And inside each individualpluginI have declared:class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_API { Q_OBJECT Q_PLUGIN_METADATA(IID "com.lamar.plugin") Q_INTERFACES(Plugin_API)What I'm doing wrong?
-
@jsulm it's not possible because I have many different plugins that share the same
Plugin_API...As you can see in the top, the
Plugin_APIhave all methods that I use in all different plugins.So, when I load all plugins inside a
foreach()loop, I have to cast they using thePlugin_API.Each individual
plugininherit thePlugin_APIclass.
And inside each individualpluginI have declared:class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_API { Q_OBJECT Q_PLUGIN_METADATA(IID "com.lamar.plugin") Q_INTERFACES(Plugin_API)What I'm doing wrong?
Thank you @SGaist and @jsulm
With your help I think that I found a solution! Here is the code:My plugin interface is called
Plugin_API. So theplugin_api.his:#ifndef PLUGIN_API_H #define PLUGIN_API_H #include <QString> #include <QDebug> #include <QJsonObject> #include <QObject> // You have to import and inherit QOBject in the plugin interface class Plugin_API : public QObject { // USE Q_OBJECT MACRO inside the interface Q_OBJECT public: virtual ~Plugin_API() = default; virtual QJsonObject get_data(void) = 0; virtual void set_project_path(const QString project_path) = 0; virtual void open_ui(const QJsonObject ui_data) = 0; virtual void run(const int job_id) = 0; // ===== SIGNALS ===== // // You have to declare the signals in the interface too: virtual void send_msg(const QString msg) = 0; }; // Declare our interface: Q_DECLARE_INTERFACE(Plugin_API, "com.lamar.plugin") #endif // PLUGIN_API_HAfter that, in the
plugin.hI have:// Do NOT inherit plublic QObject here: class PLUGINSHARED_EXPORT Plugin: public Plugin_API { // ADD Q_OBJECT MACRO HERE TOO: Q_OBJECT Q_PLUGIN_METADATA(IID "com.lamar.plugin") Q_INTERFACES(Plugin_API) ... // Overide the signal method: signals: void send_msg(const QString msg) override;In my Main Application header
main.hI have:public slots: void receive_msg(const QString msg);And finally, the implementaion of the main application slot is:
void main_app::receive_msg(const QString msg) { qDebug() << "I RECEIVE THIS MSG: " << msg; }