Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Template Q_GADGET with Q_ENUM
Forum Updated to NodeBB v4.3 + New Features

Template Q_GADGET with Q_ENUM

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 4 Posters 1.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    St.Stanislav
    wrote on last edited by
    #1

    Hello everyone!

    I'm having deal with the enums that should be accessible in QML, so I create one class for a one enum in the following way:

    class DisplayInterfaceType {
        Q_GADGET
    public:
        enum Value {
            UNDEFINED = -1,
            DIGITAL,
            ANALOG
        };
        Q_ENUM(Value);
    
        static void registerQML() {
            qmlRegisterUncreatableType<DisplayInterfaceType>("App.Enums", 1, 0, "DisplayInterfaceType", "DisplayInterfaceType");
            qRegisterMetaType<DisplayInterfaceType::Value>("DisplayInterfaceType::Value");
        }
    
        static DisplayInterfaceType::Value fromInt(int value) {
            QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
    
            const char* ptr = metaEnum.valueToKey(value);
                if (ptr != nullptr) {
                bool result = false;
                metaEnum.keyToValue(ptr, &result);
                if (result) {
                    return static_cast<DisplayInterfaceType::Value>(value);
                }
            }
            return DisplayInterfaceType::Value::UNDEFINED;
        }
    };
    

    But now I have a lot of enums created in this way. So every time I need to create one more class, copy already implemented, change class name, change strings in registration method and add necessary enums. Can this process be simplified? I thought about a template inheritance, but Q_GADGET cannot be derived. So my question is: can adding these enums be simplified?

    KroMignonK raven-worxR VRoninV 3 Replies Last reply
    0
    • S St.Stanislav

      Hello everyone!

      I'm having deal with the enums that should be accessible in QML, so I create one class for a one enum in the following way:

      class DisplayInterfaceType {
          Q_GADGET
      public:
          enum Value {
              UNDEFINED = -1,
              DIGITAL,
              ANALOG
          };
          Q_ENUM(Value);
      
          static void registerQML() {
              qmlRegisterUncreatableType<DisplayInterfaceType>("App.Enums", 1, 0, "DisplayInterfaceType", "DisplayInterfaceType");
              qRegisterMetaType<DisplayInterfaceType::Value>("DisplayInterfaceType::Value");
          }
      
          static DisplayInterfaceType::Value fromInt(int value) {
              QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
      
              const char* ptr = metaEnum.valueToKey(value);
                  if (ptr != nullptr) {
                  bool result = false;
                  metaEnum.keyToValue(ptr, &result);
                  if (result) {
                      return static_cast<DisplayInterfaceType::Value>(value);
                  }
              }
              return DisplayInterfaceType::Value::UNDEFINED;
          }
      };
      

      But now I have a lot of enums created in this way. So every time I need to create one more class, copy already implemented, change class name, change strings in registration method and add necessary enums. Can this process be simplified? I thought about a template inheritance, but Q_GADGET cannot be derived. So my question is: can adding these enums be simplified?

      VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #7

      Seems to me what you need is actually a macro:

      #define REGISTERED_ENUM(ClassName, EnumName) \
      Q_ENUM(EnumName); \
      static void registerQML() { \
          qmlRegisterUncreatableType<ClassName>("App.Enums", 1, 0, #ClassName, #ClassName); \
          qRegisterMetaType<ClassName::EnumName>(#ClassName"::"#EnumName); \
      }
      
      class DisplayInterfaceType {
          Q_GADGET
      public:
          enum Value {
              UNDEFINED = -1,
              DIGITAL,
              ANALOG
          };
          REGISTERED_ENUM(DisplayInterfaceType,Value);
          static DisplayInterfaceType::Value fromInt(int value) {
              QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
      
              const char* ptr = metaEnum.valueToKey(value);
                  if (ptr != nullptr) {
                  bool result = false;
                  metaEnum.keyToValue(ptr, &result);
                  if (result) {
                      return static_cast<DisplayInterfaceType::Value>(value);
                  }
              }
              return DisplayInterfaceType::Value::UNDEFINED;
          }
      };
      

      @St-Stanislav said in Template Q_GADGET with Q_ENUM:

      Q_GADGET cannot be derived.

      I don't think this is correct.

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      S 1 Reply Last reply
      1
      • S St.Stanislav

        Hello everyone!

        I'm having deal with the enums that should be accessible in QML, so I create one class for a one enum in the following way:

        class DisplayInterfaceType {
            Q_GADGET
        public:
            enum Value {
                UNDEFINED = -1,
                DIGITAL,
                ANALOG
            };
            Q_ENUM(Value);
        
            static void registerQML() {
                qmlRegisterUncreatableType<DisplayInterfaceType>("App.Enums", 1, 0, "DisplayInterfaceType", "DisplayInterfaceType");
                qRegisterMetaType<DisplayInterfaceType::Value>("DisplayInterfaceType::Value");
            }
        
            static DisplayInterfaceType::Value fromInt(int value) {
                QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
        
                const char* ptr = metaEnum.valueToKey(value);
                    if (ptr != nullptr) {
                    bool result = false;
                    metaEnum.keyToValue(ptr, &result);
                    if (result) {
                        return static_cast<DisplayInterfaceType::Value>(value);
                    }
                }
                return DisplayInterfaceType::Value::UNDEFINED;
            }
        };
        

        But now I have a lot of enums created in this way. So every time I need to create one more class, copy already implemented, change class name, change strings in registration method and add necessary enums. Can this process be simplified? I thought about a template inheritance, but Q_GADGET cannot be derived. So my question is: can adding these enums be simplified?

        KroMignonK Offline
        KroMignonK Offline
        KroMignon
        wrote on last edited by
        #2

        @St-Stanislav said in Template Q_GADGET with Q_ENUM:

        But now I have a lot of enums created in this way. So every time I need to create one more class, copy already implemented, change class name, change strings in registration method and add necessary enums. Can this process be simplified? I thought about a template inheritance, but Q_GADGET cannot be derived. So my question is: can adding these enums be simplified?

        You could create on class who centralize all enums.
        Then you only have to register this one.

        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

        1 Reply Last reply
        0
        • S St.Stanislav

          Hello everyone!

          I'm having deal with the enums that should be accessible in QML, so I create one class for a one enum in the following way:

          class DisplayInterfaceType {
              Q_GADGET
          public:
              enum Value {
                  UNDEFINED = -1,
                  DIGITAL,
                  ANALOG
              };
              Q_ENUM(Value);
          
              static void registerQML() {
                  qmlRegisterUncreatableType<DisplayInterfaceType>("App.Enums", 1, 0, "DisplayInterfaceType", "DisplayInterfaceType");
                  qRegisterMetaType<DisplayInterfaceType::Value>("DisplayInterfaceType::Value");
              }
          
              static DisplayInterfaceType::Value fromInt(int value) {
                  QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
          
                  const char* ptr = metaEnum.valueToKey(value);
                      if (ptr != nullptr) {
                      bool result = false;
                      metaEnum.keyToValue(ptr, &result);
                      if (result) {
                          return static_cast<DisplayInterfaceType::Value>(value);
                      }
                  }
                  return DisplayInterfaceType::Value::UNDEFINED;
              }
          };
          

          But now I have a lot of enums created in this way. So every time I need to create one more class, copy already implemented, change class name, change strings in registration method and add necessary enums. Can this process be simplified? I thought about a template inheritance, but Q_GADGET cannot be derived. So my question is: can adding these enums be simplified?

          raven-worxR Offline
          raven-worxR Offline
          raven-worx
          Moderators
          wrote on last edited by
          #3

          @St-Stanislav
          you can place the enums in a namespace and register the namespace in QML:
          https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableMetaObject

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          S 1 Reply Last reply
          3
          • raven-worxR raven-worx

            @St-Stanislav
            you can place the enums in a namespace and register the namespace in QML:
            https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableMetaObject

            S Offline
            S Offline
            St.Stanislav
            wrote on last edited by
            #4

            @raven-worx Thank you for the answer! Can the conversion method (fromInt in my example) be implemented within this approach? I mean it looks like I cannot implement one conversion method to serve every enum in the defined namespace. Moreover, can this approach be used for registering every enum as a meta type? I have read somewhere that Q_ENUM and Q_ENUMS (maybe Q_ENUM_NS as well) should register it as a meta type. But I remember that I have faced some cases when I needed to implement it directly, because there were some errors (don't remember details, though).

            raven-worxR 1 Reply Last reply
            0
            • S St.Stanislav

              @raven-worx Thank you for the answer! Can the conversion method (fromInt in my example) be implemented within this approach? I mean it looks like I cannot implement one conversion method to serve every enum in the defined namespace. Moreover, can this approach be used for registering every enum as a meta type? I have read somewhere that Q_ENUM and Q_ENUMS (maybe Q_ENUM_NS as well) should register it as a meta type. But I remember that I have faced some cases when I needed to implement it directly, because there were some errors (don't remember details, though).

              raven-worxR Offline
              raven-worxR Offline
              raven-worx
              Moderators
              wrote on last edited by
              #5

              @St-Stanislav
              see https://doc.qt.io/qt-5/qobject.html#Q_NAMESPACE
              For slots / invokable methods you need a QObject

              --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
              If you have a question please use the forum so others can benefit from the solution in the future

              S 1 Reply Last reply
              1
              • raven-worxR raven-worx

                @St-Stanislav
                see https://doc.qt.io/qt-5/qobject.html#Q_NAMESPACE
                For slots / invokable methods you need a QObject

                S Offline
                S Offline
                St.Stanislav
                wrote on last edited by
                #6

                @raven-worx Yes, I know about QObject, but can not get, how can it help in this case.

                Anyway, I have found some kind of a workaround with making one base Q_GADGET class with Q_ENUM and template method to register every derived class.

                1 Reply Last reply
                0
                • S St.Stanislav

                  Hello everyone!

                  I'm having deal with the enums that should be accessible in QML, so I create one class for a one enum in the following way:

                  class DisplayInterfaceType {
                      Q_GADGET
                  public:
                      enum Value {
                          UNDEFINED = -1,
                          DIGITAL,
                          ANALOG
                      };
                      Q_ENUM(Value);
                  
                      static void registerQML() {
                          qmlRegisterUncreatableType<DisplayInterfaceType>("App.Enums", 1, 0, "DisplayInterfaceType", "DisplayInterfaceType");
                          qRegisterMetaType<DisplayInterfaceType::Value>("DisplayInterfaceType::Value");
                      }
                  
                      static DisplayInterfaceType::Value fromInt(int value) {
                          QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
                  
                          const char* ptr = metaEnum.valueToKey(value);
                              if (ptr != nullptr) {
                              bool result = false;
                              metaEnum.keyToValue(ptr, &result);
                              if (result) {
                                  return static_cast<DisplayInterfaceType::Value>(value);
                              }
                          }
                          return DisplayInterfaceType::Value::UNDEFINED;
                      }
                  };
                  

                  But now I have a lot of enums created in this way. So every time I need to create one more class, copy already implemented, change class name, change strings in registration method and add necessary enums. Can this process be simplified? I thought about a template inheritance, but Q_GADGET cannot be derived. So my question is: can adding these enums be simplified?

                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by VRonin
                  #7

                  Seems to me what you need is actually a macro:

                  #define REGISTERED_ENUM(ClassName, EnumName) \
                  Q_ENUM(EnumName); \
                  static void registerQML() { \
                      qmlRegisterUncreatableType<ClassName>("App.Enums", 1, 0, #ClassName, #ClassName); \
                      qRegisterMetaType<ClassName::EnumName>(#ClassName"::"#EnumName); \
                  }
                  
                  class DisplayInterfaceType {
                      Q_GADGET
                  public:
                      enum Value {
                          UNDEFINED = -1,
                          DIGITAL,
                          ANALOG
                      };
                      REGISTERED_ENUM(DisplayInterfaceType,Value);
                      static DisplayInterfaceType::Value fromInt(int value) {
                          QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
                  
                          const char* ptr = metaEnum.valueToKey(value);
                              if (ptr != nullptr) {
                              bool result = false;
                              metaEnum.keyToValue(ptr, &result);
                              if (result) {
                                  return static_cast<DisplayInterfaceType::Value>(value);
                              }
                          }
                          return DisplayInterfaceType::Value::UNDEFINED;
                      }
                  };
                  

                  @St-Stanislav said in Template Q_GADGET with Q_ENUM:

                  Q_GADGET cannot be derived.

                  I don't think this is correct.

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  S 1 Reply Last reply
                  1
                  • VRoninV VRonin

                    Seems to me what you need is actually a macro:

                    #define REGISTERED_ENUM(ClassName, EnumName) \
                    Q_ENUM(EnumName); \
                    static void registerQML() { \
                        qmlRegisterUncreatableType<ClassName>("App.Enums", 1, 0, #ClassName, #ClassName); \
                        qRegisterMetaType<ClassName::EnumName>(#ClassName"::"#EnumName); \
                    }
                    
                    class DisplayInterfaceType {
                        Q_GADGET
                    public:
                        enum Value {
                            UNDEFINED = -1,
                            DIGITAL,
                            ANALOG
                        };
                        REGISTERED_ENUM(DisplayInterfaceType,Value);
                        static DisplayInterfaceType::Value fromInt(int value) {
                            QMetaEnum metaEnum = QMetaEnum::fromType<DisplayInterfaceType::Value>();
                    
                            const char* ptr = metaEnum.valueToKey(value);
                                if (ptr != nullptr) {
                                bool result = false;
                                metaEnum.keyToValue(ptr, &result);
                                if (result) {
                                    return static_cast<DisplayInterfaceType::Value>(value);
                                }
                            }
                            return DisplayInterfaceType::Value::UNDEFINED;
                        }
                    };
                    

                    @St-Stanislav said in Template Q_GADGET with Q_ENUM:

                    Q_GADGET cannot be derived.

                    I don't think this is correct.

                    S Offline
                    S Offline
                    St.Stanislav
                    wrote on last edited by
                    #8

                    @VRonin Thank you for your MACROS version, I thought about it, but firstly have tried templates. I will check your suggestion, thanks again. My template solution is:

                    template<typename T>
                    static void registerQML() {
                    	QString typeName = QString(typeid (T).name()).split(" ").last();
                    
                    	qmlRegisterUncreatableType<T>("App.Enums", 1, 0, typeName.toLocal8Bit().data(), typeName);
                    	qRegisterMetaType<T::Value>(QString("%1::Value").arg(typeName).toLocal8Bit().data());
                    }
                    
                    template<typename T>
                    static auto fromInt(int value) {
                    	QMetaEnum metaEnum = QMetaEnum::fromType<T::Value>();
                    
                    	const char* ptr = metaEnum.valueToKey(value);
                    	if (ptr != nullptr) {
                    		bool result = false;
                    		metaEnum.keyToValue(ptr, &result);
                    
                    		if (result) {
                    			return static_cast<typename T::Value>(value);
                    		}
                    	}
                    	return T::UNDEFINED;
                    }
                    

                    @VRonin said in Template Q_GADGET with Q_ENUM:

                    I don't think this is correct.

                    Yes, I found my typo, I meant "templated" :)

                    VRoninV 1 Reply Last reply
                    0
                    • S St.Stanislav

                      @VRonin Thank you for your MACROS version, I thought about it, but firstly have tried templates. I will check your suggestion, thanks again. My template solution is:

                      template<typename T>
                      static void registerQML() {
                      	QString typeName = QString(typeid (T).name()).split(" ").last();
                      
                      	qmlRegisterUncreatableType<T>("App.Enums", 1, 0, typeName.toLocal8Bit().data(), typeName);
                      	qRegisterMetaType<T::Value>(QString("%1::Value").arg(typeName).toLocal8Bit().data());
                      }
                      
                      template<typename T>
                      static auto fromInt(int value) {
                      	QMetaEnum metaEnum = QMetaEnum::fromType<T::Value>();
                      
                      	const char* ptr = metaEnum.valueToKey(value);
                      	if (ptr != nullptr) {
                      		bool result = false;
                      		metaEnum.keyToValue(ptr, &result);
                      
                      		if (result) {
                      			return static_cast<typename T::Value>(value);
                      		}
                      	}
                      	return T::UNDEFINED;
                      }
                      

                      @VRonin said in Template Q_GADGET with Q_ENUM:

                      I don't think this is correct.

                      Yes, I found my typo, I meant "templated" :)

                      VRoninV Offline
                      VRoninV Offline
                      VRonin
                      wrote on last edited by
                      #9

                      @St-Stanislav said in Template Q_GADGET with Q_ENUM:

                      Yes, I found my typo, I meant "templated" :)

                      There is a workaround for this: https://github.com/woboq/verdigris but I don't think it's worth it in your case

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved