Solved Sharing data between application and module
-
I have written a GUI application and then a module (dll/dylib) to share data with a web app. I can share data from the main application to the module by declaring a function in the interface class and then calling that function from the main application.
Now I want to update a field in the main application window when the module receives data from the web server. So in this case, the module would send data back to the main application. However, I haven't found a way to link a function in the main application to the module. I've looked at IPC's but that seems relatively heavy. Is there an easier way to do it?
-
Define a signal in a class that's exposed to the application and connect it to the slot in the GUI code. For all intents and purposes the application code and the shared library are the same code.
-
I don't think it is possible to make an interface class extend QObject. I have tried that in the past but it doesn't work for some reason, can't remember why. Without QObject, I can't use the connect calls, I believe.
-
@mgreenish said in Sharing data between application and module:
I don't think it is possible to make an interface class extend QObject.
It is, that's how the plugins get loaded to begin with.
I have tried that in the past but it doesn't work for some reason, can't remember why.
You have had some other error then.
Without QObject, I can't use the connect calls, I believe.
Indeed.
-
So I found that with a dynamic cast, I can connect the main application to the plugin as follows :
QObject::connect( this, SIGNAL(effectsSent(QJsonDocument)), dynamic_cast< QObject * >(reactionsserverInterface), SLOT(saveReactionFile(QJsonDocument)) );
even if the interface does not extend QObject. reactionsserverInterface is the plugin object. This works for sending signals from the main app to the plugin, meaning the plugin gets the signal and acts on it.
However, in the other direction,
QObject::connect( dynamic_cast< QObject * >(reactionsserverInterface), SIGNAL(requestingReactionFile), this, SLOT(rsSaveReactionFile()));
it compiles but doesn't work. My application doesn't seem to receive the signals from the plugin. I did step through the plugin code and it is getting to the emit call but in the case above, the breakpoints in rsSaveReactionFile don't get triggered.
The plugin signal requestingReactionFile is exposed to the main application in the interface as below:
signals: virtual void requestingReactionFile() = 0;
so everything compiles, but it does not work.
Again, when my interface class extends QObject, I get errors when compiling my plugin wherever I use connect even for signals/slots that are local to my plugin, as below:
connect( ui->configButton, SIGNAL(clicked(bool)), rsPluginObject, SLOT(displayConfigDialog()) ); ambiguous conversion from derived class 'ReactionsServerPlugin' to base class 'const QObject': class ReactionsServerPlugin -> class QObject class ReactionsServerPlugin -> class ReactionsServerInterface -> class QObject connect( rsPluginObject, SIGNAL(reactionFileNameUpdated(QString)), this, SLOT(setCurrentReactionFileName(QString)) );
The connect above is called from a QDialog object that is a part of the plugin and the rsPluginObject is the plugin object that instantiates that QDialog object.
Do plugin signals not get injected into the main application event loop?
-
@mgreenish said in Sharing data between application and module:
The only bit I know about is:Again, when my interface class extends QObject, I get errors when compiling my plugin wherever I use connect even for signals/slots that are local to my plugin, as below:
connect( ui->configButton, SIGNAL(clicked(bool)), rsPluginObject, SLOT(displayConfigDialog()) ); ambiguous conversion from derived class 'ReactionsServerPlugin' to base class 'const QObject': class ReactionsServerPlugin -> class QObject class ReactionsServerPlugin -> class ReactionsServerInterface -> class QObject connect( rsPluginObject, SIGNAL(reactionFileNameUpdated(QString)), this, SLOT(setCurrentReactionFileName(QString)) );
The connect above is called from a QDialog object that is a part of the plugin and the rsPluginObject is the plugin object that instantiates that QDialog object.
That won't stop the principle working, it's just a compilation issue to get round. I presume your
ReactionsServerPlugin
inherits directly fromQObject
, but it also inherits fromReactionsServerInterface
, which inherits fromQObject
too. So you have to tell the compiler which "route" you want it to take to reach a'const QObject'
. Right? Sorry if you already know this.Now I'm not a C++er, but there must be a syntax to disambiguate. I don't even know if it matters which of the two "routes" you tell the compiler to take. But with no testing/evidence from me, wouldn't it work if for instance you wrote:
dynamic_cast< QObject * >( dynamic_cast< ReactionsServerInterface * >(rsPluginObject) )
?
[In this case you presumably don't even need the outer
QObject*
cast, sodynamic_cast< ReactionsServerInterface * >(rsPluginObject)
would probably be the same.] -
Your approach is wrong. You shall not derive multiple times from
QObject
. If your abstract class derives fromQObject
, i.e. it's not a pure interface, then you need to put in a dynamic library that is linked both with the application and the plugin. However I really don't see a reason for you to have your interface derive fromQObject
. Could you elaborate? That's needed for the actual implementation, but not for the abstract class in principle.@JonB said in Sharing data between application and module:
Now I'm not a C++er, but there must be a syntax to disambiguate. I don't even know if it matters which of the two "routes" you tell the compiler to take. But with no testing/evidence from me, wouldn't it work if for instance you wrote
There is, but unfortunately it's much more complicated than that. What is needed in standard C++ is virtual inheritance, however:
- For the 99.5% of cases it's neither needed nor a good thing to do.
- It's not supported for
QObject
derived classes.
-
So thank you kshegunov for confirming that my interface class should not derive QObject. I did find my mistake above, very slight but enough to not throw any warnings yet still not work. The following code:
QObject::connect( dynamic_cast< QObject * >(reactionsserverInterface), SIGNAL(requestingReactionFile), this, SLOT(rsSaveReactionFile()));
should be
QObject::connect( dynamic_cast< QObject * >(reactionsserverInterface), SIGNAL(requestingReactionFile()), this, SLOT(rsSaveReactionFile()));
I just missed the () on the of the function name inside the SIGNAL() macro. Once I put that, it worked, I was able to get data going both ways.
-
Hi,
For QObject based classes use qobject_cast.
You should also consider using the new Qt 5 syntax for connection, it will give you compile time warning and avoid the situation you encountered.