I'm trying to follow the Qt Remote Objects example, and I wrote a small example using Qt 6.3.
The code for the server is compiling, but the code of the client process does not compile, and I'm getting this error:
Error C2661 'SharedObject::SharedObject': no overloaded function takes 2 arguments C:\Qt\6.3.0\qtremoteobjects\src\remoteobjects\qremoteobjectnode.h 78
Which is caused by this line:
auto sharedObject = node.acquire<SharedObject>();
server
// remoteobject.h
#include <QRemoteObjectRegistry>
#include <QRemoteObjectRegistryHost>
#include <QRemoteObjectHost>
class SharedObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
QString text() const { return m_text; }
void setText(const QString& text)
{
if (m_text != text) {
m_text = text;
emit textChanged(m_text);
}
}
signals:
void textChanged(const QString& text);
private:
QString m_text;
};
// main.cpp
#include "remoteobject.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SharedObject sharedObject;
sharedObject.setObjectName("sharedObject");
QRemoteObjectHost host;
host.setHostUrl(QUrl("local:sharedObject"));
host.enableRemoting(&sharedObject);
return a.exec();
}
client
// remoteobject.h
#include <QRemoteObjectRegistry>
#include <QRemoteObjectRegistryHost>
#include <QRemoteObjectHost>
class SharedObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
QString text() const { return m_text; }
void setText(const QString& text)
{
if (m_text != text) {
m_text = text;
emit textChanged(m_text);
}
}
signals:
void textChanged(const QString& text);
private:
QString m_text;
};
// main.cpp
#include "remoteobject.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QRemoteObjectNode node;
node.connectToNode(QUrl("local:sharedObject"));
auto sharedObject = node.acquire<SharedObject>();
QObject::connect(sharedObject, &SharedObject::textChanged, [&](const QString& text) {
qDebug() << "Text changed to:" << text;
});
QTimer::singleShot(10000, [&]() {
qDebug() << "Current text:" << sharedObject->text();
});
return a.exec();
}
Before I dive into the answer, let me describe a widget I added to make the example more interactive, by allowing the text to be modified by hand from either the server or the client. The widget contains:
For the sake of providing a code that works by itself without making people copy parts of your question, I will reproduce everything, including what works from what you wrote.
Server-side
Very few mistakes there.
If anything, I'd say you must specify a name in
enableRemoting()(I called it"MySharedObject")Client-side
This is where you got lost.
The error
'SharedObject::SharedObject': no overloaded function takes 2 argumentsis about the constructor expected to have 2 parameters. If you do not know what parameters are expected there, it is absolutely normal and I am going to describe what you should have done instead in a minute.Before that, let us see what changes I made to the client's
main.cpp:"MySharedObject"object identifier.SharedObjecttoSharedObjectReplica.Now, we have a
SharedObjectReplicadefined nowhere, whose constructor must have 2 parameters that we do not choose...The trick to get ourselves unstuck is to have Qt generate the
SharedObjectReplicaclass for us.The server has the object with all the code; the client only needs a reference of the remote data.
To do this:
We create a very simple
remoteobject.repfile (documented here). YourSharedObjectclass only has 1 read/write property with a signal. That is exactly what we type in the file.Similar to the meta-object compiler (
moc.exe), we compile the above file with the replica compiler (repc.exe).This creates our
SharedObjectReplicaclass in a header file, with the correct property, methods and signal. You will notice the constructor has 2 parameters like we wanted.Finally, we moc
remoteobject.hThe result
This is something I wanted to demonstrate: when you change the text from the client window, you will immediately get the
textChangedsignal from the server in return, and it happens so fast it is practically impossible to event see the text flicker (keep your finger onto a key and you will see this happen, eventually).This is usually not a problem, because it never matters where the change originated from, but you may want to keep that in mind ... maybe.
Going beyond
(Edit to address the comment with link to there).
Structures can indeed be shared with a bit of effort. You must follow this page (a link to it is provided in the
repchelppage from above).It is important
MyStructsupports queued connections (I know there is a warning somewhere about this fact but I could not find it to add the link).-> we need to follow the instruction until and including the section [Creating and Destroying Custom Objects].
We declare the
structwith required default constructor, destructor, and copy constructor.As stated above, in the
mainfunction, we need to addqRegisterMetaType<MyStruct>();.In the server's
ShareObjectclass, we add the property (that I leave for now incomplete, to illustrate something later):I let you implement the getter/setter for the property.
On the client's side, we include the same declaration/definition for
MyStruct,operator>>andoperator<<.The
remoteobject.repfile must now look like:This will generate:
dataStruct()and asetDataStructmethod for the replica (it does not matter the names are not the same as the server's object).qRegisterMetaType<MyStruct>();inside the generated class, so we do not have to add it ourselves.I declare the property with
READWRITEfor the sake of having a more complete illustration but I invite you to test the other keyworksCONSTANT,READONLY,PERSISTED,READWRITE,READPUSH(default),SOURCEONLYSETTERand look at the generated class to see what getter, setter and signal you get out of each.The code from the above sample can now be edited for illustration:
On the server, I changed the
setTextmethod so that the attached struct counts how many times it was edited + what the last value was (I declared the private member asMyStruct myStruct;):On the client, we can now make use of the previously unused
label2, from themainfunction, by adding:You will notice that
label2does not get updated unless you restart the client, contrary to what the connection would suggest. It is able to write a new structure into the server but nothing is visible in real time.This is caused by the fact no signal is attached to the
dataStructproperty.Without a signal, the client does not know the structure changes and keeps a copy of it; this is the same behavior as property binding in QML.
To correct it, you therefore need to change the property declaration to
Then add the signal to your class. Do not forget to actually emit the
dataStructChanged(...);inside the modifiedsetTextmethod.And voila! the client can get the structure, gets notified when it changes and can also write into it.