Using QVariant to store custom types in Qt6.5.1
-
In all the tutorials I've found, it is mentioned that "you must use Q_DECLARE_METATYPE to declare custom types to the Qt meta-system."
I created a example for testing and found that I can directly call QVariant::setValue() to store custom types without using Q_DECLARE_METATYPE.#include <QCoreApplication> #include <QVariant> struct Entity { int value; QString str; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Entity entity; entity.value = 12345; entity.str = "hello, world"; QVariant variant; variant.setValue(entity); Entity receiver = variant.value<Entity>(); qDebug() << receiver.value; qDebug() << receiver.str; return a.exec(); }
When is it necessary to use Q_DECLARE_METATYPE?
-
When you want to do this
public: void onEntityChanged(Entity e);
signal: void entityChanged(Entity e);
connect(this, &MyWidget::entityChanged, otherWidget, &OtherWidget::onEntityChanged);
You need to register
Entity
in order to fully use it in the meta-object system including sending it via signal -
@Pl45m4 Thank you for your response. I added a Sender class to send Entity objects, and the code still runs fine.
// head.h #pragma once #include <QCoreApplication> #include <QVariant> struct Entity { int value; QString str; }; class Sender: public QObject { Q_OBJECT signals: void sig_sendEntity(Entity e); public slots: void slot_getEntity(Entity e); };
// main.cpp #include "head.h" void Sender::slot_getEntity(Entity e) { qDebug() << "slot get Entity value: " << e.value << ", str: " << e.str; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Entity entity; entity.value = 12345; entity.str = "hello, world"; QVariant variant; variant.setValue(entity); Entity receiver = variant.value<Entity>(); qDebug() << receiver.value; qDebug() << receiver.str; Sender sender; QObject::connect(&sender, &Sender::sig_sendEntity, &sender, &Sender::slot_getEntity); emit sender.sig_sendEntity(entity); return a.exec(); }
Does the Qt configuration environment affect the execution of the program?
-
It might work when on the same thread (also you should register it anyway) but as soon as you have
QueuedConnections
this will probably fail without registering the type globally.The part here even says, that declaring is necessary for direct signal and slot connections:
The Message class only needs a suitable implementation in order to be usable. However, Qt's type system will not be able to understand how to store, retrieve and serialize instances of this class without some assistance. For example, we will be unable to store Message values in QVariant.
The class in Qt responsible for custom types is QMetaType. To make the type known to this class, we invoke the Q_DECLARE_METATYPE() macro on the class in the header file where it is defined:
Q_DECLARE_METATYPE(Message);
This now makes it possible for Message values to be stored in QVariant objects and retrieved later. See the Custom Type Example for code that demonstrates this.
The Q_DECLARE_METATYPE() macro also makes it possible for these values to be used as arguments to signals, but only in direct signal-slot connections. To make the custom type generally usable with the signals and slots mechanism, we need to perform some extra work.
As stated reading further here:
Although the declaration in the previous section makes the type available for use in direct signal-slot connections, it cannot be used for queued signal-slot connections, such as those that are made between objects in different threads. This is because the meta-object system does not know how to handle creation and destruction of objects of the custom type at run-time.
To enable creation of objects at run-time, call the qRegisterMetaType() template function to register it with the meta-object system. This also makes the type available for queued signal-slot communication as long as you call it before you make the first connection that uses the type.
-