How to access C++ enum from QML?

C++QtQmlQtquick2

C++ Problem Overview


class StyleClass : public QObject {
public:
    typedef enum
        {
            STYLE_RADIAL,
            STYLE_ENVELOPE,
            STYLE_FILLED
        }  Style;

    Style m_style;
    //...
};

The .h file has the above code. How to access the above enum through QML?

C++ Solutions


Solution 1 - C++

You can wrap the enum in a class which derives from QObject (and that you expose to QML):

style.hpp :

#ifndef STYLE_HPP
#define STYLE_HPP

#include <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
    // Qt 4
    #include <QDeclarativeEngine>
#else
    // Qt 5
    #include <QQmlEngine>
#endif

// Required derivation from QObject
class StyleClass : public QObject
{
    Q_OBJECT

    public:
        // Default constructor, required for classes you expose to QML.
        StyleClass() : QObject() {}
        
        enum EnStyle
        {
            STYLE_RADIAL,
            STYLE_ENVELOPE,
            STYLE_FILLED
        };
        Q_ENUMS(EnStyle)

        // Do not forget to declare your class to the QML system.
        static void declareQML() {
            qmlRegisterType<StyleClass>("MyQMLEnums", 13, 37, "Style");
        }
};

#endif    // STYLE_HPP

main.cpp:

#include <QApplication>
#include "style.hpp"

int main (int argc, char ** argv) {
    QApplication a(argc, argv);

    //...

    StyleClass::declareQML();

    //...

    return a.exec();
}

QML Code:

import MyQMLEnums 13.37
import QtQuick 2.0    // Or 1.1 depending on your Qt version

Item {
    id: myitem

    //...

    property int item_style: Style.STYLE_RADIAL

    //...
}

Solution 2 - C++

As of Qt 5.8 you can expose enums from a namespace:

Define the namespace and enum:

#include <QObject>

namespace MyNamespace
{
    Q_NAMESPACE         // required for meta object creation
    enum EnStyle {
        STYLE_RADIAL,
        STYLE_ENVELOPE,
        STYLE_FILLED
    };
    Q_ENUM_NS(EnStyle)  // register the enum in meta object data
}

Register the namespace (eg. in main(), before creating a Qml View/Context):

qmlRegisterUncreatableMetaObject(
  MyNamespace::staticMetaObject, // meta object created by Q_NAMESPACE macro
  "my.namespace",                // import statement (can be any string)
  1, 0,                          // major and minor version of the import
  "MyNamespace",                 // name in QML (does not have to match C++ name)
  "Error: only enums"            // error in case someone tries to create a MyNamespace object
);

Use it in a QML file:

import QtQuick 2.0
import my.namespace 1.0

Item {
    Component.onCompleted: console.log(MyNamespace.STYLE_RADIAL)
}

References:

https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/

http://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableMetaObject

http://doc.qt.io/qt-5/qobject.html#Q_ENUM_NS

Solution 3 - C++

Additional information (not documented prior to Qt 5.5):

Your enum value names must start with a Capital letter.

This will work:

enum EnStyle
{
    STYLE_RADIAL,
    STYLE_ENVELOPE,
    STYLE_FILLED
};
Q_ENUMS(EnStyle)

This does not:

enum EnStyle
{
    styleRADIAL,
    styleENVELOPE,
    styleFILLED
};
Q_ENUMS(EnStyle)

You won't get any kind of error at compile time, they are just ignored by the QML engine.

Solution 4 - C++

I found a very nice solution for using ENUMs from C++ class in QML, here: Enums in Qt QML - qml.guide. The post was so good, I felt obliged to share it here with the SO community. And IMHO attribution should always be done, hence added the link to the post.

The post basically describes:

  1. How to create an ENUM type in Qt/C++:
// statusclass.h

#include <QObject>

class StatusClass
{
    Q_GADGET
public:
    explicit StatusClass();

    enum Value {
        Null,
        Ready,
        Loading,
        Error
    };
    Q_ENUM(Value)
};
  1. How to register the class with QML engine as an "Uncreatable Type":
    (This is the part which makes this solution nice and distinct.)
// main.cpp

...
QQmlApplicationEngine engine;
qmlRegisterUncreatableType<StatusClass>("qml.guide", 1, 0, "StatusClass",
                                        "Not creatable as it is an enum type.");
...

Use of qmlRegisterUncreatableType prevents instantiation of StatusClass in QML. A warning will be logged if a user tries to instantiate this class:

qrc:/main.qml:16 Not creatable as it is an enum type.
  1. Finally, how to use the ENUM in a QML file:
// main.qml

import QtQuick 2.9
import QtQuick.Window 2.2

import qml.guide 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Component.onCompleted: {
        console.log(StatusClass.Ready); // <--- Here's how to use the ENUM.
    }
}

Important note:
ENUM is supposed to be used by referencing it with the class name, like this StatusClass.Ready. If the same class is also being used in QML as a context property...

// main.cpp

...
QQmlApplicationEngine engine;
qmlRegisterUncreatableType<StatusClass>("qml.guide", 1, 0, "StatusClass",
                                        "Not creatable as it is an enum type.");

StatusClass statusClassObj; // Named such (perhaps poorly) for the sake of clarity in the example.
engine.rootContext()->setContextProperty("statusClassObj", &statusClassObj); // <--- like this
...

...then, sometimes people accidentally use the ENUM with the context property instead of the class name.

// main.qml

...
Component.onCompleted: {
    // Correct
    console.log(StatusClass.Ready);    // 1

    // Wrong
    console.log(statusClassObj.Ready); // undefined
}
...

The reason people tend to make this mistake is because Qt Creator's autocomplete feature lists ENUM as option, both when referencing using class name as well as the context property. So just exercise caution when in such a situation.

Solution 5 - C++

Qt also supports QML-defined enum types since Qt version 5.10. As an alternative to the C++-based answer by air-dex, you can now also use QML to create enum types:

Style.qml:

import QtQuick 2.0

QtObject {
  enum EnStyle {
    STYLE_RADIAL,
    STYLE_ENVELOPE,
    STYLE_FILLED
  }
}

If you only intend to use the enums in your QML code, this solution is much simpler. You can access the above enum with the Style type in qml then, for example:

import VPlayApps 1.0
import QtQuick 2.9

App {

  property int enStyle: Style.EnStyle.STYLE_RADIAL

  Component.onCompleted: {
    if(enStyle === Style.EnStyle.STYLE_ENVELOPE)
      console.log("ENVELOPE")
    else
      console.log("NOT ENVELOPE")
  }
}

See here for another usage example of a QML-based enum type.

Solution 6 - C++

All this solutions can't enabled used this enum-class as parameter for signal/slot. This code compile, but not work in QML:

class DataEmitter : public QObject
{
    Q_OBJECT

public:
    ...
signals:
    void setStyle(StyleClass::EnStyle style);
}

...

emit setStyle(StyleClass.STYLE_RADIAL);

QML-part:

Connections {
    target: dataEmitter
    onSetStyle: {
         myObject.style=style
    }
}

And this code generate runtime error, as this:

IndicatorArea.qml:124: Error: Cannot assign [undefined] to int

For this code working, you must additional registry Qt metaobject type:

qRegisterMetaType<StyleClass::EnStyle>("StyleClass.EnStyle");

More details written here: https://webhamster.ru/mytetrashare/index/mtb0/1535044840rbtgvfmjys (rus)

Solution 7 - C++

Make the moc aware of your enum using the Q_ENUMS macro, as described in the docs. You must register the class that 'owns' the enum before it is used, as described in the docs.

Ashif's quote block is only valid if the enum is a global or is owned by a non-QObject derived class.

Solution 8 - C++

My variant (for backward compatibility when namespaces were not available, use manual pre-defined macro ENABLE_USE_ENUM_NAMESPACES):

// enum.h
#pragma once

#include <QObject>

#ifndef ENABLE_USE_ENUM_NAMESPACES
class TaskTypeEnums : public QObject
{
    Q_OBJECT
    Q_ENUMS(TaskTypeEnum)

 public:
    explicit TaskTypeEnums(QObject *parent = nullptr): QObject(parent) {}
#else
namespace TaskTypeEnums {
    Q_NAMESPACE
#endif
    enum TaskTypeEnum {
        TaskConnectDev,
        TaskDisconnectDev,
        TaskPingDev,
        TaskResetDev,
        TaskTakeControlDev,
        TaskSetAkaModDev,
        TaskFirmwareUpdDev,
        TaskConnectDevs,
        TaskDisconnectAll,
        TaskMainTestSot,
        TaskMainTestBA,
    };
#ifndef ENABLE_USE_ENUM_NAMESPACES
};
#else
    Q_ENUM_NS(TaskTypeEnum)
}
#endif
// ----------------------------------------------------------------------------

// fragment from main.cpp
//...
#ifdef ENABLE_USE_ENUM_NAMESPACES
    qmlRegisterUncreatableMetaObject(TaskTypeEnums::staticMetaObject, "Vip.Enums.Tasks", 1, 0, "Tasks", "");
#else
    qmlRegisterType<TaskTypeEnums>("Vip.Enums.Tasks", 1, 0, "Tasks");
#endif
//...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAquarius_GirlView Question on Stackoverflow
Solution 1 - C++air-dexView Answer on Stackoverflow
Solution 2 - C++Maxim PapernoView Answer on Stackoverflow
Solution 3 - C++Richard1403832View Answer on Stackoverflow
Solution 4 - C++zeFreeView Answer on Stackoverflow
Solution 5 - C++GDevTView Answer on Stackoverflow
Solution 6 - C++XintreaView Answer on Stackoverflow
Solution 7 - C++cmannett85View Answer on Stackoverflow
Solution 8 - C++Vitalja AlexView Answer on Stackoverflow