c++enumsqmlqt6

How to expose enum to QML from non QObject in C++ (Qt 6.2+)


I want to expose an enum to QML from C++ without creating a QObject but it's not working for me. Any ideas?

For comparison, I've included minimal code exposing an enum to QML using Q_ENUM() from a QObject that contains Q_OBJECT and QML_ELEMENT.

I have tried using a class that contains Q_GADGET and uses Q_ENUM(). I have also tried using a namespace with Q_NAMESPACE() and Q_ENUM_NS(). In both cases the enum doesn't get recognised by QML.

Full QObject QML_ELEMENT example

#include <QObject>
#include <QtQml>

class MyFullQObject : public QObject {
  Q_OBJECT
  QML_ELEMENT
public:
  using QObject::QObject;

  enum MyEnum {
    First,
    Second,
    Third
  };
  Q_ENUM(MyEnum)
};

Q_GADGET example

#include <QtQml>

class MyGadget {
  Q_GADGET
public:
  enum MyEnum {
    First,
    Second,
    Third
  };
  Q_ENUM(MyEnum)
};

Q_NAMESPACE example

#include <QObject>

namespace MyNamespace {

Q_NAMESPACE

enum MyEnum {
  First,
  Second,
  Third
};
Q_ENUM_NS(MyEnum)

}

Usage in QML

import QtQuick
import MyModule

Item {
  Component.onCompleted: {
    console.log("MyFullQObject enum: " + MyFullQObject.First)
    console.log("MyGadget enum: " + MyGadget.First)
    console.log("MyNamespace enum: " + MyNamespace.First)
  }
}

In QML, the first console line will work. The second one generates an error "ReferenceError: MyGadget is not defined". Likewise for the third one (if the second one is commented out to allow the program to continue).

Within CMake, both classes and the namespace are included in the same CMake module and I link the generated MyModuleLibplugin to the executable, which successfully makes it available for QML import.


Solution

  • You can also make namespaces tagged with Q_NAMESPACE available this way, in order to expose any enums tagged with Q_ENUM_NS they contain:

     namespace MyNamespace {
       Q_NAMESPACE
       QML_ELEMENT
    
       enum MyEnum {
           Key1,
           Key2,
       };
       Q_ENUM_NS(MyEnum)
     }
    

    In QML, you can then use the enums:

     Component.onCompleted: console.log(MyNamespace.Key2)