I'm a bit new to Qt, after reading this question I'm trying to learn more about QRemoteObject, following the mentioned question, comments, and links, I tried to write a class to share data between processes.
Based on the doc I build this .rep file into the two processes:
class SharedObject
{
SIGNAL(signalAPP1(QString text))
SIGNAL(signalAPP2(QString text))
};
However, when I press F2 on APP1 it's not firing the lambda on APP2
connect(ptr.data(), &SharedObjectReplica::signalAPP1, this, [](QString text) {
qDebug() << "signalAPP1! text:" << text;
});
The same thing happens when i press F2 on APP2, it's not firing the lambda on APP1
connect(sharedObject, &SharedObject::signalAPP2, this, [=](QString text) {
qDebug() << "signalAPP2! text:" << text;
});
What i'm missing?
app1.h
#include "rep_sharedobject_source.h"
class SharedObject : public SharedObjectSource
{
Q_OBJECT
public:
signals:
void signalAPP1(QString text);
void signalAPP2(QString text);
};
QT_BEGIN_NAMESPACE
namespace Ui { class APP1Class; };
QT_END_NAMESPACE
class APP1 : public QMainWindow
{
Q_OBJECT
public:
SharedObject* sharedObject = nullptr;
QRemoteObjectHost srcNode;
Ui::APP1Class *ui;
APP1(QWidget *parent = nullptr) : QMainWindow(parent), ui(new Ui::APP1Class())
{
ui->setupUi(this);
sharedObject = new SharedObject();
sharedObject->setObjectName("sharedObject");
srcNode.setHostUrl(QUrl(QStringLiteral("local:sharedObject")));
srcNode.enableRemoting(sharedObject);
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this);
connect(shortcut, &QShortcut::activated, [=] {
qDebug() << "emiting...";
emit sharedObject->signalAPP1("hello from APP1");
});
connect(sharedObject, &SharedObject::signalAPP2, this, [=](QString text) {
qDebug() << "signalAPP2! text:" << text;
});
}
};
app2.h
#include "rep_sharedobject_replica.h"
QT_BEGIN_NAMESPACE
namespace Ui { class APP2Class; };
QT_END_NAMESPACE
class APP2 : public QMainWindow
{
Q_OBJECT
public:
Ui::APP2Class *ui;
QSharedPointer<SharedObjectReplica> ptr;
QRemoteObjectNode repNode;
APP2(QWidget *parent = nullptr) : QMainWindow(parent), ui(new Ui::APP2Class())
{
ui->setupUi(this);
repNode.connectToNode(QUrl(QStringLiteral("local:sharedObject")));
ptr.reset(repNode.acquire<SharedObjectReplica>());
connect(ptr.data(), &SharedObjectReplica::initialized, this, [=]
{
qDebug() << "conected...";
connect(ptr.data(), &SharedObjectReplica::signalAPP1, this, [](QString text) {
qDebug() << "signalAPP1! text:" << text;
});
});
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this);
connect(shortcut, &QShortcut::activated, [=] {
QString str = "hello from APP2";
emit ptr.data()->signalAPP2(str);
});
}
};
I managed to reproduce your problem with the code you provided and solved it.
First thing first: I find it strange your subclass of
QMainWindowis what is in charge of publishing/retrieving the remove object, let alone do it in the constructor.Now for your issue. According to my analysis, the replica fails to acquire a connection to the original object because you did not name it.
That is something I warned about in the other question you consulted and I believe you should have notice you never get to execute the lambda connected to the
SharedObjectReplica::initializedsignal that you expect. That was a big clue as to where exactly your code was not meeting your expectations.In APP1, do, with a name:
And the corresponding in APP2:
Now that the replica is connected to the object, we need to address your
SharedObjectclass. As you have defined aSharedObjectSourcesuperclass from a.repfile, the signalssignalAPP1andsignalAPP2are already defined after compiling it.SharedObject::signalAPP1/SharedObject::signalAPP2conflict withSharedObjectSource::signalAPP1/SharedObjectSource::signalAPP1, so remove them fromSharedObject.And finally,
signalAPP1works as expected (but notsignalAPP2).The reason for that comes from a misunderstanding on your end: signals only flow from the server to the client.
Put another way: the client application can request the state of an object hosted on server (aka original object) to be changed but it makes no sense that the client application notifies the server said original object has changed.
signalAPP1flows from the server to the client, so everything is good.signalAPP2, in your code, is designed to flow from the client to the server which, like I said, makes no sense.The correct approach was to create a
Q_INVOKABLEmethod on the server.and in the
.repfile, declare a slot:And finally, what you must connect to the
F2key shortcut:Final note:
This way of connecting signals on the client is IMO wrong:
A
SharedObjectReplicais a validQObjectso as long as you have a valid instance, you can create the connection even ifSharedObjectReplica::isInitialized()returns false for that instance.The consequence of waiting for the
&SharedObjectReplica::initializedsignal to be emitted is that if the server shuts down and then restarts, you will receive a new signal, therefore create a new connection. After that happens (and since you did not specifyQt::UniqueConnectionon&SharedObjectReplica::signalAPP1), your lambda is executed twice for everysignalAPP1receives.Then 3 times if the server restarts again, then 4 and so on.
The correct way to connect signals from a replica is to ignore whether or not the connection was established, i.e. simply do: