Привет!
Порою удобнее в 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", QVariant::fromValue( dynamic_cast<QObject*>(interface) ));
Напрямую в QVariant интерфейс засовывать нельзя, т.к. он не знает необходимой информации, поэтому преобразовываем сначала в QObject*, а благодаря тому, что мы прописал Q_DECLARE_INTERFACE метасистема знает как работать с этим интерфейсом.
Полный код примера тут: https://github.com/Riflio/QMLInterfaces
Вот как-то так =)