Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to expose enum in class to QML
Forum Updated to NodeBB v4.3 + New Features

How to expose enum in class to QML

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
11 Posts 4 Posters 2.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
    sandro4912
    wrote on last edited by
    #1

    I have a class like this to change the language of the application at runtime:

    class LanguageSelector : public QObject {
        Q_OBJECT
    public:
        enum class Language { german, english, spanish };
        Q_ENUM(Language)
    
        explicit LanguageSelector(QObject *parent = nullptr);
    
        Q_INVOKABLE void changeLanguage(Language newLanguage);
    
        QTranslator *getTranslator() const;
    
    private:
        QTranslator *mTranslator;
    
        void loadGerman();
        void loadEnglish();
        void loadSpanish();
    
        void loadLanguage(const QLocale::Language &newLanguage);
    
    signals:
        void languageChanged();
    };
    
    Q_DECLARE_METATYPE(LanguageSelector::Language);
    

    This class gets exposed to qml like this:

    QQmlApplicationEngine engine;
    
    auto context = engine.rootContext();
    context->setContextProperty("languageSelector", &languageSelector);
    

    In QML then I thought I could change the language like this (refering to the enum):

            ToolButton {
                //...
                onClicked: languageSelector.changeLanguage(languageSelector.spanish)
            }
    

    No matter what I pass:

    onClicked: languageSelector.changeLanguage(languageSelector.german)
    
    onClicked: languageSelector.changeLanguage(languageSelector.english)
    
    onClicked: languageSelector.changeLanguage(languageSelector.spanish)
    

    In C++ always german gets selected.

    I know the method works correct because if i pass the numerical values:

    onClicked: languageSelector.changeLanguage(0) // german
    
    onClicked: languageSelector.changeLanguage(1) // english
    
    onClicked: languageSelector.changeLanguage(2) // spanish
    

    Then it works.

    So 2 questions here:

    Is the enum exposed correctly? If not how to do it correctly.
    Is it the correct way to add this class as a context or should it be made a singleton or something like that?

    1 Reply Last reply
    0
    • fcarneyF Offline
      fcarneyF Offline
      fcarney
      wrote on last edited by fcarney
      #2

      Register the type:

      qmlRegisterType<LanguageSelector>("LanguageSelectors",1,0,"LanguageSelector");
      

      // or qmlRegisterTypeNotAvailable qmlRegisterUncreatableType if you don't want to instantiate in QML

      Then in qml:

      import LanguageSelectors 1.0
      
      ...
      
      languageSelector.changeLanguage(LanguageSelector.german)
      

      C++ is a perfectly valid school of magic.

      J.HilkJ 1 Reply Last reply
      1
      • fcarneyF fcarney

        Register the type:

        qmlRegisterType<LanguageSelector>("LanguageSelectors",1,0,"LanguageSelector");
        

        // or qmlRegisterTypeNotAvailable qmlRegisterUncreatableType if you don't want to instantiate in QML

        Then in qml:

        import LanguageSelectors 1.0
        
        ...
        
        languageSelector.changeLanguage(LanguageSelector.german)
        
        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #3

        @fcarney I think thats the wrong register call. Enums aren't types!

        qmlRegisterUncreatableType< LanguageSelector >("LanguageSelectors",1,0,"LanguageSelector","Enum is not a type");
        

        it says so in the documentation 😉
        https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableType


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        GrecKoG fcarneyF 2 Replies Last reply
        2
        • J.HilkJ J.Hilk

          @fcarney I think thats the wrong register call. Enums aren't types!

          qmlRegisterUncreatableType< LanguageSelector >("LanguageSelectors",1,0,"LanguageSelector","Enum is not a type");
          

          it says so in the documentation 😉
          https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableType

          GrecKoG Offline
          GrecKoG Offline
          GrecKo
          Qt Champions 2018
          wrote on last edited by
          #4

          @J-Hilk That's the correct register call but the error message you put is misleading.

          This would appear while trying to do LanguageSelector {} in QML, so the link with Enum is not really apparent. Just mention that LanguageSelector is not instantiable in QML code.

          J.HilkJ 1 Reply Last reply
          1
          • GrecKoG GrecKo

            @J-Hilk That's the correct register call but the error message you put is misleading.

            This would appear while trying to do LanguageSelector {} in QML, so the link with Enum is not really apparent. Just mention that LanguageSelector is not instantiable in QML code.

            J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #5

            @GrecKo I actually have that from here:
            https://doc.qt.io/archives/qt-5.10/qtbluetooth-heartrate-game-main-cpp.html

            and it's still in the newest documentation

            https://code.qt.io/cgit/qt/qtconnectivity.git/tree/examples/bluetooth/heartrate-game/main.cpp?h=5.15


            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            1 Reply Last reply
            1
            • J.HilkJ J.Hilk

              @fcarney I think thats the wrong register call. Enums aren't types!

              qmlRegisterUncreatableType< LanguageSelector >("LanguageSelectors",1,0,"LanguageSelector","Enum is not a type");
              

              it says so in the documentation 😉
              https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableType

              fcarneyF Offline
              fcarneyF Offline
              fcarney
              wrote on last edited by fcarney
              #6

              @J-Hilk said in How to expose enum in class to QML:

              Enums aren't types!

              Edit: I think I am slow this morning.

              Your right, it should be qmlRegisterUncreatableType

              C++ is a perfectly valid school of magic.

              1 Reply Last reply
              2
              • S Offline
                S Offline
                sandro4912
                wrote on last edited by sandro4912
                #7

                Thank you all for all the answers. I tried to go with the uncreateable type but I get an Error.

                Here is what I did:

                Change the enum names to uppercase (German, English, Spanish) because qml complains they have to be uppercase.

                In Cpp:

                qmlRegisterUncreatableType<LanguageSelector>(
                    "LanguageSelectors", 1, 0, "LanguageSelector",
                    "LanguageSelector is not instantiatable in QML");
                

                In QML:

                import LanguageSelectors 1.0
                
                Component.onCompleted: {
                        LanguageSelector.changeLanguage(LanguageSelector.German)
                    }
                

                This line gives me an error:

                TypeError: Property 'changeLanguage' of object [object Object] is not a function
                

                I don't get it why. In the class it is invokeable like this:

                class LanguageSelector : public QObject {
                    Q_OBJECT
                public:
                    enum class Language { German, English, Spanish };
                    Q_ENUM(Language)
                
                    explicit LanguageSelector(QObject *parent = nullptr);
                
                    Q_INVOKABLE void changeLanguage(Language newLanguage);
                //....
                
                private:
                //....
                signals:
                    void languageChanged();
                
                }
                

                A second concern. When I call changeLanguge in QML the signal "languageChanged". When that happends we need to call
                QQmlApplicationEngine::retranslate to retranslate the ui.

                Is that possible to connect to the uncreateable type?

                Before when i exposed it with the context I simply did:

                    QObject::connect(&languageSelector,
                    &LanguageSelector::languageChanged,
                                     &engine, &QQmlApplicationEngine::retranslate);
                

                Maybe for that I still have to create an object? Or is there annother way to call retranslate from QML when languageChanged is called in QML?

                Since I have the signal isn't it then a canidate for qmlRegisterSingletonInstance ?

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  sandro4912
                  wrote on last edited by
                  #8

                  I could get it to work with the singleton approach:

                  QScopedPointer<LanguageSelector> languageSelector(new LanguageSelector);
                  
                  //..
                  
                  
                  qmlRegisterSingletonInstance<LanguageSelector>(
                      "LanguageSelectors", 1, 0, "LanguageSelector", languageSelector.get());
                  
                  
                  //..
                  
                  QObject::connect(languageSelector.get(), &LanguageSelector::languageChanged,
                                   &engine, &QQmlApplicationEngine::retranslate);
                  engine.load(url);
                  

                  In QML:

                  import LanguageSelectors 1.0
                  
                  
                  //....
                  
                  Component.onCompleted: {
                              showButtonsIfConditionsAreMet()
                              LanguageSelector.changeLanguage(LanguageSelector.German)
                  }
                  

                  Now the only strange thing. I get a complain from QT Creator that it does not know the import:

                  159964ab-1b2e-45da-9ab3-21d5176abda6-image.png

                  Any way to get rid of that or is it like a bug in creator?

                  1 Reply Last reply
                  0
                  • fcarneyF Offline
                    fcarneyF Offline
                    fcarney
                    wrote on last edited by
                    #9

                    @sandro4912 said in How to expose enum in class to QML:

                    This class gets exposed to qml like this:
                    QQmlApplicationEngine engine;

                    auto context = engine.rootContext();
                    context->setContextProperty("languageSelector", &languageSelector);

                    In QML then I thought I could change the language like this (refering to the enum):
                    ToolButton {
                    //...
                    onClicked: languageSelector.changeLanguage(languageSelector.spanish)
                    }

                    Backup, I built upon the code above. I was using the languageSelector context property you set. Do not capitalize this object.

                    This code is not an error. languageSelector.changeLanguage should appear like this because your context property cannot be capitalized.
                    LanguageSelector.german is capitalized because you are using it as a QML type. Don't mix this up.

                    import LanguageSelectors 1.0
                    
                    ...
                    
                    languageSelector.changeLanguage(LanguageSelector.german)
                    

                    C++ is a perfectly valid school of magic.

                    1 Reply Last reply
                    1
                    • GrecKoG Offline
                      GrecKoG Offline
                      GrecKo
                      Qt Champions 2018
                      wrote on last edited by
                      #10

                      Note that qmlRegisterSingletonInstance should be preferred over setContextProperty for new code.

                      @J-Hilk said in How to expose enum in class to QML:

                      @GrecKo I actually have that from here:
                      https://doc.qt.io/archives/qt-5.10/qtbluetooth-heartrate-game-main-cpp.html

                      and it's still in the newest documentation

                      https://code.qt.io/cgit/qt/qtconnectivity.git/tree/examples/bluetooth/heartrate-game/main.cpp?h=5.15

                      What a weird place to copy code from :) Still, it doesn't really make sense even there.

                      1 Reply Last reply
                      1
                      • S Offline
                        S Offline
                        sandro4912
                        wrote on last edited by sandro4912
                        #11

                        Maybe I was not clear in the last post. I got rid of context property complete and only registered the type with qmlRegisterSingletonInstance.

                        Now just wonder why creator complains about the import even if all the code works fine.

                        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