Получение ошибки незарегистрированного типа данных в QML, когда структура Q_GADGET находится в отдельном файле заголовка

У меня есть обычай struct который я использую как Q_PROPERTY введите QMediaPlayerпроизводный класс. Но вот код:

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;

    ...
}

И я использую его в Label:

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

Это работает как шарм, но вот поворот: если я скопирую и вставлю объявление struct в отдельный файл заголовка (и, очевидно, включил его) с Q_DECLARE_METATYPE макрос, я получаю следующую ошибку:

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

Итак, у меня есть два вопроса:

  1. Менее важно: зачем мне использовать Q_DECLARE_METATYPEмакрос, если в документации написано, что он мне не нужен сQ_GADGET макрос, потому что он автоматически регистрирует тип?
  2. Более важно: почему я не могу переместить объявление в другой файл заголовка? Что мне не хватает?

Заранее спасибо!

РЕДАКТИРОВАТЬ:

Это может быть актуально: я использую Qt v5.15 в проекте Visual Studio (MSVC v142). (Нет в Qt Creator.)

1 ответ

Решение

Q_GADGET основное использование - позволить типу, отличному от QObject, заниматься самоанализом.

Макрос Q_GADGET - это облегченная версия макроса Q_OBJECT для классов, которые не наследуются от QObject, но все же хотят использовать некоторые возможности отражения, предлагаемые QMetaObject. Как и макрос Q_OBJECT, он должен находиться в закрытом разделе определения класса.

Q_GADGET могут иметь Q_ENUM, Q_PROPERTY и Q_INVOKABLE, но не могут иметь сигналов или слотов.

Q_GADGET делает доступным член класса staticMetaObject. staticMetaObject имеет тип QMetaObject и обеспечивает доступ к перечислениям, объявленным с помощью Q_ENUMS.

Про регистрацию типа ничего не сказано.

Также Q_DECLARE_METATYPE не регистрирует тип, а объявляет его.

Зарегистрироваться VideoMeta тебе нужно позвонить qRegisterMetaType<VideoMeta>(). В документации Qt прямо указано, чтоqRegisterMetaType<T>() должен вызываться, чтобы тип работал в системе свойств Qt.

Кроме того, чтобы использовать тип T с API QObject::property(), перед его использованием необходимо вызвать qRegisterMetaType(), обычно в конструкторе класса, использующего T, или в функции main ().

См. https://doc.qt.io/qt-5/qmetatype.html.

Другие вопросы по тегам