Skip to content

Instantly share code, notes, and snippets.

@oclero
Last active July 16, 2021 12:24
Show Gist options
  • Save oclero/0f48900bb5ec3dc898f02e2060861b54 to your computer and use it in GitHub Desktop.
Save oclero/0f48900bb5ec3dc898f02e2060861b54 to your computer and use it in GitHub Desktop.

How to use C++ enums with Qt/Qml

Utilisation d'une enum ou enum class dans un QObject

C++

Déclaration de la classe qui hérite de QObject dans les fichiers .cpp/.hpp:

  • Macro Q_OBJECT : déclare le méta-type pour la classe MyObject.
  • Macro Q_ENUM : déclare les infos nécessaires pour l'enum MyEnum.
  • Une fonction statique init() qui déclare le type MyObject à QML.
#pragma once
#include <QObject>
#include <QtQml/qqml.h>

namespace my::namespace {
class MyQObject : public QObject {
  Q_OBJECT

  Q_PROPERTY(my::namespace::MyEnum myEnum READ myEnum WRITE setMyEnum)

public:
  enum class MyEnum {
    Foo,
    Bar,
  };
  Q_ENUM(MyEnum)

public:
  // ctor...

  // A mettre dans le .cpp
  static void init() {
    qmlRegisterType<MyQObject>("My.Namespace", // QML import statement
                               1,              // Major version of QML import
                               0,              // Minor version of QML import
                               "MyObject");    // name in QML
  }
};
}

Dans main.cpp (ou n'importe où avant la création de l'engine QML) :

my::namespace::MyQObject::init();

QML

Utilisation de l'enum class C++ en QML:

  • QML représente toujours les enums sous forme d'int. Si on fait console.log(MyQObject.MyEnum.Bar), cela affiche 1.
  • Les property QML qui l'utilisent doivent être de type int.
  • Si on veut l'afficher sous forme de string, il faut faire soi-même la conversion. Deux façons :
    • Si l'on souhaite afficher une chaîne traduite, il est préférable de garder tout côté View, en QML.
    • Si l'on souhaite afficher le nom de l'enum tel qu'il est écrit en C++, alors il faut passer par une classe qui sera exposée à QML en tant que singleton (instancié une seule fois par QML), avec une méthode Q_INVOKABLE qui convertit MyObject::MyEnum vers QString.
import My.Namespace 1.0

Text {
  property int myEnum: MyObject.MyEnum.Bidule

  id: _text
  text: myObjectMyEnumToString(myEnum)

  function myObjectMyEnumToString(myEnum) {
    switch (myEnum) {
    case MyObject.MyEnum.Foo:
      return qsTr("Foo") // traduction
    case MyObject.MyEnum.Bar:
      return qsTr("Bar") // traduction
    default:
      return ""
    }
  }
}

Utilisation d'une enum class dans un namespace

C++

Déclaration du namespace dans les fichiers .cpp/.hpp:

  • Macro Q_NAMESPACE : déclare le méta-type pour le namespace my::namespace.
  • Macron Q_ENUM_NS : déclare les infos nécessaires pour l'enum MyEnum.
  • Une fonction statique init() qui déclare le namespace à QML.
#pragma once
#include <qobjectdefs.h>
#include <QMetaObject>
#include <QtQml/qqml.h>

namespace my::namespace {
Q_NAMESPACE

enum class MyEnum {
  Foo,
  Bar,
};
Q_ENUM_NS(MyEnum)

// Implémentation à mettre dans le .cpp.
void init() {
  qmlRegisterUncreatableMetaObject(staticMetaObject,
                                   "My.Namespace",       // QML import statement
                                   1,                    // Major version of QML import
                                   0,                    // Minor version of QML import
                                   "Namespace",          // name in QML
                                   "Error: only enums"); // error in case someone tries to create a MyNamespace object
}
}

Dans main.cpp (ou n'importe où avant la création de l'engine QML) :

my::namespace::init();

QML

import My.Namespace 1.0

Text {
  property int myEnum: Namespace.MyEnum.Foo

  id: _text
  text: myNamespaceMyEnumToString(myEnum)

  function myNamespaceMyEnumToString(myEnum) {
    switch (myEnum) {
    case Namespace.MyEnum.Foo:
      return qsTr("Foo") // traduction
    case Namespace.MyEnum.Bar:
      return qsTr("Bar") // traduction
    default:
      return ""
    }
  }
}

enum class d'une classe A en Q_PROPERTY d'une classe B

Soit une classe A dans un namespace my::long::namespace ayant une enum appelée MyEnum :

namespace my::first::namespace {
class A : public QObject {
  Q_OBJECT

public:
  enum class MyEnum {
    Foo,
    Bar,
  };
  Q_ENUM(MyEnum)
};
}

Si on désire utiliser cette enum comme Q_PROPERTYdans une autre classe, il faut mettre le namespace en entier :

namespace my::second::namespace {
class B : public QObject {
  Q_OBJECT
  Q_PROPERTY(my::first::namespace::MyEnum myEnum READ myEnum WRITE setMyEnum)
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment