问题
Im using QT 5 with a WebChannel to communicate with a HTML Page. I successfully able to communicate texts and strings. however i woud like to communicate some points data.
the official documentation says
"No manual message passing and serialization of data is required," http://doc.qt.io/qt-5/qwebchannel.html
When i try to send a object or an array, instead of a string, the application throw this message:
Don't know how to handle 'data', use qRegisterMetaType to register it.
How can I emit a signal with a Point class instead of a string object? Or to serialize a class to a string.
This is the object that i would like to send to my HTML
Point class
class MyData{
public :
int x,y,z;
};
Q_DECLARE_METATYPE(MyData)
Map class
class MyMap : public QObject{
Q_OBJECT
public:
explicit MyMap ();
signals:
updateText(const QString &text); // registered
updateData(MyData &data); // Don't know how to handle 'data', use qRegisterMetaType to register it.
public slots:
receiveText(const QString &text);
};
and the main code
qRegisterMetaType<MyData>();
// setup the channel
QWebChannel channel;
QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected, &channel, &QWebChannel::connectTo);
// setup the dialog and publish it to the QWebChannel
channel.registerObject(QStringLiteral("map"), &map);
map.updateText("text");
MyData data;
data.x=10;
data.y=12;
data.z=13;
map.updateData(data);
回答1:
Per Qt documentation:
To use the type T in QVariant, using Q_DECLARE_METATYPE() is sufficient. To use the type T in queued signal and slot connections, qRegisterMetaType() must be called before the first connection is established.
In my own code, I use Q_DECLARE_METATYPE for classes I want to store in a QVariant (this macro has to by put at global scope). And I qRegisterMetaType<T>() for classes I want to be passed to signals/slots (this function has to be called before the signal.slot connection is made). I never had to call both if using only one feature.
So, for your example, this should work:
qRegisterMetaType<MyData>( "MyData" );
// then, form here, you can connect `updateData(MyData)` signal to any slot taking a MyData parameter
For signal/slot declaration:
- If
qRegisterMetaTypewas not called, you can only use signal/slot passingMyDataby reference or pointer (declare thesignalasvoid updateData(MyData& data);orvoid updateData(MyData* data);). Then, you must be very careful if doing asynchonous connection (likeQt::QueuedConnection) because, as theslotwill be executed "later", you must guarantee that object reference remains valid untill theslotgets executed after you emited thesignal. - If
qRegisterMetaTypewas called, you can use signal/slot passingMyDataby copy (declare thesignalasvoid updateData(MyData data);). And it's safe to do asynchonous connection with those objects passed by copy as Qt is able to serialize the object (meaning that if theslotis executed "later" it will in the end be called with a brand newMyDataobject copied from the original one you emited the signal with....withoutqRegisterMetaTypebeing called, Qt is unable to do this "copy").
Make sure MyData declaration is known when you do this (no forward declaration).
Note also that not all classes/structs can be registered this way, they must have:
a public default constructor, a public copy constructor, and a public destructor
It's the case for your MyData class (default ones are OK), so it should work smoothly.
回答2:
You simply need a line somewhere before your slot like this:
qRegisterMetaType<Block>();
What you are doing is telling the Meta Object Compiler (MOC) all about your class and how to pass it around. Further reading can be found here which discusses this problem in much more detail, and gives examples.
回答3:
You also need to pass a string representation of a type name as a parameter to the function
qRegisterMetaType<MyData>("MyData");
来源:https://stackoverflow.com/questions/34818557/how-to-register-a-class-for-use-it-in-a-qwebchannel-signal-in-qt