c++qtstructqmlqgadget

Getting 'unregistered datatype' error in QML when Q_GADGET struct is in a separate header file


I have a custom struct which I use as a Q_PROPERTY type in a QMediaPlayer derived class. But here's the code:

struct VideoMeta
{
    Q_GADGET

    Q_PROPERTY(int width MEMBER width)
    Q_PROPERTY(...)
    ....

public:

    int width;
    ...
};

Q_DECLARE_METATYPE(VideoMeta)

class FrameProvider : public QMediaPlayer
{
    Q_OBJECT

    Q_PROPERTY(VideoMeta videoMeta READ getVideoMeta WRITE setVideoMeta NOTIFY videoLoaded)

    VideoMeta m_videoMeta;

    ...
}

And I use it in a Label:

Label {
    text: "Cached frames: " + cacheLoaded + " / " + frameProvider.videoMeta.framecount
}

This works like charm but here comes the twist: If I copy and paste the declaration of the struct into a separate header file (and obviously included it) with the Q_DECLARE_METATYPE macro, I get the following error:

QMetaProperty::read: Unable to handle unregistered datatype 'VideoMeta' for property 'FrameProvider::videoMeta'

So I have two questions:

  1. The less important: Why do I need to use the Q_DECLARE_METATYPE macro, if the documentation says that I don't need it with the Q_GADGET macro because it automatically registers the type?
  2. The more important: Why can't I move the declaration into an other header file? What am I missing?

Thanks in advance!

EDIT:

This might be relevant: I use Qt v5.15 in a Visual Studio (MSVC v142) project. (Not in Qt Creator.)


Solution

  • Q_GADGET main usage is to allow a non QObject type to have introspection.

    The Q_GADGET macro is a lighter version of the Q_OBJECT macro for classes that do not inherit from QObject but still want to use some of the reflection capabilities offered by QMetaObject. Just like the Q_OBJECT macro, it must appear in the private section of a class definition.

    Q_GADGETs can have Q_ENUM, Q_PROPERTY and Q_INVOKABLE, but they cannot have signals or slots.

    Q_GADGET makes a class member, staticMetaObject, available. staticMetaObject is of type QMetaObject and provides access to the enums declared with Q_ENUMS.

    It does not say anything about registering the type.

    Also Q_DECLARE_METATYPE does not register a type, but declares it.

    To register VideoMeta you need to call qRegisterMetaType<VideoMeta>(). Qt documentation specifically states that qRegisterMetaType<T>() must be called for a type to work in the Qt property system.

    Also, to use type T with the QObject::property() API, qRegisterMetaType() must be called before it is used, typically in the constructor of the class that uses T, or in the main() function.

    See https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1