4

I have a Q_ENUM declared in MyClass like below:

class MyClass {
public:
    enum Enum_Test {
        eTestA,
        eTestB
    }
    Q_ENUM(Enum_Test)

    Q_OBJECT
    Q_PROPERTY(MyClass::Enum_Test enumTest READ GetEnumTest WRITE SetEnumTest )
}

I have MyClass registered on the QML side like below and able to access it.

auto my_class = std::make_shared<MyClass>();
qmlRegisterUncreatableType<MyClass>("MyClass", 1,0, "MyClass","Cannot create type MyClass in QML");
rootContext()->setContextProperty("my_class", my_class.get());

How do I access Q_ENUM Enum_Test from QML?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
TheWaterProgrammer
  • 7,055
  • 12
  • 70
  • 159
  • The shown piece of code is not how you _register_ a class, this is setting a context property. You need `qmlRegisterType` after which you can do `MyClass.TestA`. Also the enum _must_ start with a capital – Amfasis Mar 29 '21 at 13:34
  • 1
    I updated my question. If I get an example of how to access the Q_ENUM which is the primary point of my question, I can take care of registering the class properly. – TheWaterProgrammer Mar 29 '21 at 13:37
  • MyClass should be derived from a QObject. – JarMan Mar 29 '21 at 14:05

2 Answers2

6

Your class needs two adjustments.

  1. as pointed out by JarMan, it needs a metaObject, which can be obtained by deriving from QObject and adding Q_OBJECT:

    class MyClass : public QObject
    {
        Q_OBJECT
        ...
    };
    

    Actually, it would also be possible to use Q_GADGET but you already seem to lean towards Q_OBJECT. But, as requested, here we go:

    class MyClass
    {
      Q_GADGET
    
    public:
      enum Enum_Test {
          ETestA,
          ETestB
      };
      Q_ENUM(Enum_Test)
    };
    

    Keep in mind that Q_GADGET cannot have signals, so I left out the property and only have this class as "enum-placeholder".

  2. The enum value names need to be capitalized:

    enum Enum_Test {
        ETestA,
        ETestB
    };
    Q_ENUM(Enum_Test)
    

Then you can use it in QML as:

     QtObject {
         property int myEnumVal: MyClass.ETestA
     }

Note that support for enums is somewhat limited because the mix with JavaScript. The values will be converted to integers. Also, when used in a JavaScript switch-statement, typo's will not be warned about by QtCreator (assuming version 4.14)

Amfasis
  • 3,932
  • 2
  • 18
  • 27
  • 1
    Thanks. I am accepting this. It would be nice to show the `Q_GADGET` based example and I can accept it. Do you mind editing your answer using `Q_GADGET`? – TheWaterProgrammer Mar 29 '21 at 14:27
  • 1
    @TheWaterProgrammer No problem, I have added it – Amfasis Mar 29 '21 at 17:21
  • In my case, "constexpr is not valid here" error in this example because there is no semicolon for definition ```Enum_Test```. I used Visual Studio 2019 and Qt 5.15. What's the difference? – WOOSEOK CHOI Dec 19 '22 at 04:13
  • 1
    @WOOSEOKCHOI That is probably an error in my post, will edit – Amfasis Dec 19 '22 at 08:59
4

The answer provided by @Amfasis is already good. As I tend to do this pretty often, I wrote a little shortcut for defining enums with all the features Qt offers, including the availability in QML here: https://github.com/carlonluca/lqtutils#lqtutils_enumh.

You only need to include the header, define your enum values like:

L_DECLARE_ENUM(Enum_Test,
    ETestA,
    ETestB
)

and register it where you prefer with:

Enum_Test::qmlRegisterMySharedEnum("some.uri", 1, 0);

Also this uses simple namespaces, which is lighter than using QObjects or gadgets.

Actually, I got used to always declare my enums like this when I'm using Qt, because I can also benefit from QMetaEnum. For instance, I really like to be able to log like this:

qDebug() << "Value:" << Enum_Test::ETestA;

getting:

Value: Enum_Test::ETestA

instead of a simple integer.

Luca Carlon
  • 9,546
  • 13
  • 59
  • 91