Привет!
Порою удобнее в QML работать именно с интерфейсом класса, а так же иметь возможность засунуть его в QVariant.
Разумеется простым способом в «лоб» не получится, т.к. Qt в QML работает с QObject, а мы от него не унаследовались и никакой информации для метасистемы не дали.
Долго я копался в недрах метасистемы Qt, уж собирался делать костыли, но наткнулся на макрос Q_DECLARE_INTERFACE.
И так, допустим мы хотим сделать интерфейс класса для работы с одним свойством myProperty, тем самым заставив определить функции получения, установки значения и сигнала (который сам по себе то же функция) об изменении значения.
Пишем:
#ifndef IINTERFACE_H #define IINTERFACE_H #include <QObject> class IInterface { public: virtual QString myProperty() const =0; virtual void setMyProperty(QString myProperty) =0; virtual void myPropertyChanged(QString myProperty) =0; }; Q_DECLARE_INTERFACE(IInterface, "pavelk.iinterface") #endif // IINTERFACE_H
Обратите внимание на строку с «Q_DECLARE_INTERFACE» — тем самым мы даём понять метаобъектной системе Qt, что это интерфейс, что бы он прописал необходимые функции по получению исходного класса.
Ну и сам класс:
#ifndef MYCLASS_H #define MYCLASS_H #include <QObject> #include "iinterface.h" class MyClass : public QObject, public IInterface { Q_OBJECT Q_INTERFACES(IInterface) Q_PROPERTY(QString myProperty READ myProperty WRITE setMyProperty NOTIFY myPropertyChanged) public: explicit MyClass(QObject *parent = nullptr); QString myProperty() const; signals: void myPropertyChanged(QString myProperty); public slots: void setMyProperty(QString myProperty); private: QString m_myProperty; }; #endif // MYCLASS_H
Обратите внимание на строку с «Q_INTERFACES(IInterface)» — тем самым мы даём знать Qt как именно преобразовывать этот класс к указанному интерфейсу. Кстати, можно наследоваться сразу от нескольких интерфейсов — просто пропишите через пробел их все.
Ну и теперь самое интересное. Преобразовываем класс к интерфейсу и передаём этот интерфейс в QML
MyClass * myClass = new MyClass(0); IInterface * interface = myClass; engine.rootObjects().at(0)->setProperty("myClassInterface", qVariantFromValue( dynamic_cast<QObject*>(interface) ));
Напрямую в QVariant интерфейс засовывать нельзя, т.к. он не знает необходимой информации, поэтому преобразовываем сначала в QObject*, а благодаря тому, что мы прописал Q_DECLARE_INTERFACE метасистема знает как работать с этим интерфейсом.
Полный код примера тут: https://github.com/Riflio/QMLInterfaces
Вот как-то так =)