Search code examples
c++qtenumsqmlqqmllistproperty

How to expose a Qlist of enums from C++ to QML?


I have a list of errors in c++ and I want to expose it to QML. Enum is registered using Q_ENUM and property is registered using Q_PROPERTY. You can see details below:

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<LoginErrorCode> loginErrors READ getLoginErrors NOTIFY loginErrorsChanged)
    ...

public:
    ...
    enum LoginErrorCode {
        UsernameOrPassIsNotValid
    };
    Q_ENUM(LoginErrorCode)
    enum GetUserInfoErrorCode {
        GetUserInfoError_TokenIsNotValid
    };
    Q_ENUM(GetUserInfoErrorCode)

    QList<LoginErrorCode> getLoginErrors() const;
    ...
signals:
    ...
    void loginFailed();
    ...
    void loginErrorsChanged();
    ...
private:
    QList<LoginErrorCode> m_loginErrors;
};

and I registered MyClass using following line in main.cpp:

qmlRegisterType<MyClass>("ir.MyComponents", 1, 0, "MyClass");

and in QML I used that class using:

MyClass {
    id: myClass
    Component.onCompleted: login("irani", "iravani");
    onLoginFailed: console.log("Login failed with errors count: "+loginErrors.length);
}

and output is:

QMetaProperty::read: Unable to handle unregistered datatype 'QList<LoginErrorCode>' for property 'MyClass::loginErrors'
qrc:/main.qml:46: TypeError: Cannot read property 'length' of undefined

What is the problem?!
How can I expose my list of enums to qml?

For QQmlListProperty documentation says:

Note: QQmlListProperty can only be used for lists of QObject-derived object pointers.


Solution

  • As you can see from the documentation, QList is supported only for a limited set of types (int, qreal, and so on). See section Sequence Type to JavaScript Array for further details.
    You should use QVariantList for your purposes instead. It is directly mapped to JavaScript Array. See section QVariantList and QVariantMap to JavaScript Array and Object for further details.
    Note also the explicit mention:

    Other sequence types are not supported transparently, and instead an instance of any other sequence type will be passed between QML and C++ as an opaque QVariantList.

    Of course, you can still use a QList<LoginErrorCode> internally, but a conversion to a QVariantList is required whenever you want to return it within the QML environment.