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_H
The 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_data
that 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_API
have 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
plugin
inherit thePlugin_API
class.
And inside each individualplugin
I 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.h
is:#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_H
After that, in the
plugin.h
I 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.h
I 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
save
was 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.cpp
in 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
save
was 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.cpp
in 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.h
haveQ_OBJECT
macro:#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_H
Second: 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 thesave
button 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.h
haveQ_OBJECT
macro:#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_H
Second: 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 thesave
button 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.h
header above. It have theQ_OBJECT
macro.
And the class declaration is:class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_API
What is wrong?
I tried to add the
public QObject
andQ_OBJECT
macro inside theplugin_API
class, but I got these compilation warnings/errors:'Plugin': base-class 'QObject' is already a base-class of 'Plugin_API'
-
@jsulm please, look my
plugin.h
header above. It have theQ_OBJECT
macro.
And the class declaration is:class PLUGIN_SHARED_EXPORT Plugin: public QObject, public Plugin_API
What is wrong?
I tried to add the
public QObject
andQ_OBJECT
macro inside theplugin_API
class, 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_API
have 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
plugin
inherit thePlugin_API
class.
And inside each individualplugin
I 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_API
have 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
plugin
inherit thePlugin_API
class.
And inside each individualplugin
I 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.h
is:#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_H
After that, in the
plugin.h
I 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.h
I 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; }