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. using C++ classes and structs in QML
Forum Update on Monday, May 27th 2025

using C++ classes and structs in QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
30 Posts 9 Posters 5.3k Views
  • 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.
  • GrecKoG Offline
    GrecKoG Offline
    GrecKo
    Qt Champions 2018
    wrote on last edited by GrecKo
    #19

    You can now instantiate Gadgets from QML with undocumented macros (so maybe don't use it).

    Use QML_VALUE_TYPE(typeName) with a lower case name like you currently do.
    Then you can add QML_CONSTRUCTIBLE_VALUE or QML_STRUCTURED_VALUE (even both).

    QML_CONSTRUCTIBLE_VALUE will call a user defined constructor

    if you have Q_INVOKABLE MyStruct(int foo) : m_myInt{foo} {}
    then doing property myStruct myStruct1: 42 will call the constructor with 42 as the foo param

    QML_STRUCTURED_VALUE will assign properties depending on the js object you passed in QML.

    property myStruct myStruct1: ({myInt: 42}) will create a default constructed MyStruct and assign its myInt property to 42.

    Note that the type should always be default constructible.

    EDIT: Note that you don't have to use QML_ELEMENT, Q_DECLARE_METATYPE or qmlRegisterType if you use Q_GADGET and QML_VALUE_TYPE.

    mzimmersM L 2 Replies Last reply
    3
    • GrecKoG GrecKo

      You can now instantiate Gadgets from QML with undocumented macros (so maybe don't use it).

      Use QML_VALUE_TYPE(typeName) with a lower case name like you currently do.
      Then you can add QML_CONSTRUCTIBLE_VALUE or QML_STRUCTURED_VALUE (even both).

      QML_CONSTRUCTIBLE_VALUE will call a user defined constructor

      if you have Q_INVOKABLE MyStruct(int foo) : m_myInt{foo} {}
      then doing property myStruct myStruct1: 42 will call the constructor with 42 as the foo param

      QML_STRUCTURED_VALUE will assign properties depending on the js object you passed in QML.

      property myStruct myStruct1: ({myInt: 42}) will create a default constructed MyStruct and assign its myInt property to 42.

      Note that the type should always be default constructible.

      EDIT: Note that you don't have to use QML_ELEMENT, Q_DECLARE_METATYPE or qmlRegisterType if you use Q_GADGET and QML_VALUE_TYPE.

      mzimmersM Offline
      mzimmersM Offline
      mzimmers
      wrote on last edited by
      #20

      @GrecKo curiouser and curiouser.

      My modified struct:

      struct MyStruct {
          QML_STRUCTURED_VALUE
          QML_VALUE_TYPE(myStruct)
          Q_PROPERTY(int myInt MEMBER m_myInt)
          int m_myInt = 55;
          MyStruct() {}
      };
      

      my registration (in main.cpp):

          qmlRegisterType<MyStruct>("myStruct", 1, 0, "MyStruct");
      

      and my QML:

      property myStruct myStruct1: myStruct ({myInt: 100})
      

      produces a runtime error: "myStruct is not a type."

      Isn't using QML_VALUE_TYPE intended to allow me to use "myStruct" in the QML?

      GrecKoG 1 Reply Last reply
      0
      • mzimmersM mzimmers

        @GrecKo curiouser and curiouser.

        My modified struct:

        struct MyStruct {
            QML_STRUCTURED_VALUE
            QML_VALUE_TYPE(myStruct)
            Q_PROPERTY(int myInt MEMBER m_myInt)
            int m_myInt = 55;
            MyStruct() {}
        };
        

        my registration (in main.cpp):

            qmlRegisterType<MyStruct>("myStruct", 1, 0, "MyStruct");
        

        and my QML:

        property myStruct myStruct1: myStruct ({myInt: 100})
        

        produces a runtime error: "myStruct is not a type."

        Isn't using QML_VALUE_TYPE intended to allow me to use "myStruct" in the QML?

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

        As I said : you don't have to use qmlRegisterType. You do have to use Q_GADGET though.

        And Q_GADGET adds a private: so you need to add back public:

        struct MyStruct {
          Q_GADGET
          QML_VALUE_TYPE(myStruct)
          QML_STRUCTURED_VALUE
        
          Q_PROPERTY(int myInt MEMBER m_myInt)
        
        public:
          int m_myInt = 55;
          MyStruct() {};
        };
        

        and my QML:
        property myStruct myStruct1: myStruct ({myInt: 100})

        Did I write that? nope. The syntax for structured values is :

        property myStruct myStruct1: ({myInt: 100})
        

        Ditch the myStruct on the right-hand side.

        mzimmersM 1 Reply Last reply
        1
        • GrecKoG GrecKo

          As I said : you don't have to use qmlRegisterType. You do have to use Q_GADGET though.

          And Q_GADGET adds a private: so you need to add back public:

          struct MyStruct {
            Q_GADGET
            QML_VALUE_TYPE(myStruct)
            QML_STRUCTURED_VALUE
          
            Q_PROPERTY(int myInt MEMBER m_myInt)
          
          public:
            int m_myInt = 55;
            MyStruct() {};
          };
          

          and my QML:
          property myStruct myStruct1: myStruct ({myInt: 100})

          Did I write that? nope. The syntax for structured values is :

          property myStruct myStruct1: ({myInt: 100})
          

          Ditch the myStruct on the right-hand side.

          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by mzimmers
          #22

          @GrecKo oh, that is a thing of beauty.

          Now...about QML_STRUCTURED_VALUE being an undocumented macro, as you said...is it safe to use? I did notice mention of it in a bug report, so maybe it's OK.

          Thanks for the help.

          EDIT: everything above works, but if possible, I'd like to directly access enums defined in the struct (actually, this was the original point behind this entire thread).

          struct MyStruct {
              Q_GADGET
              QML_STRUCTURED_VALUE
              QML_VALUE_TYPE(myStruct)
              Q_PROPERTY(int myInt MEMBER m_myInt)
          public:
              enum MyEnums {
                  Enum0,
                  Enum1,
                  Enum2,
                  Enum3
              } m_myEnums;
              Q_ENUM(MyEnums)
              int m_myInt = 55;
              MyStruct() {}
          };
          

          This attempt doesn't work:

          Label { text: "myStruct.Enum3: " + myStruct.Enum3 }
          

          (it doesn't work with "MyStruct" either.)

          Can this be made to work? Thanks...

          EDIT 2:

          I have a workaround, which is to define my enums in a separate class and expose them to QML using the guidelines here, but if possible I'd prefer to avoid this level of indirection, and keep the enums in the struct.

          GrecKoG 1 Reply Last reply
          0
          • mzimmersM mzimmers

            @GrecKo oh, that is a thing of beauty.

            Now...about QML_STRUCTURED_VALUE being an undocumented macro, as you said...is it safe to use? I did notice mention of it in a bug report, so maybe it's OK.

            Thanks for the help.

            EDIT: everything above works, but if possible, I'd like to directly access enums defined in the struct (actually, this was the original point behind this entire thread).

            struct MyStruct {
                Q_GADGET
                QML_STRUCTURED_VALUE
                QML_VALUE_TYPE(myStruct)
                Q_PROPERTY(int myInt MEMBER m_myInt)
            public:
                enum MyEnums {
                    Enum0,
                    Enum1,
                    Enum2,
                    Enum3
                } m_myEnums;
                Q_ENUM(MyEnums)
                int m_myInt = 55;
                MyStruct() {}
            };
            

            This attempt doesn't work:

            Label { text: "myStruct.Enum3: " + myStruct.Enum3 }
            

            (it doesn't work with "MyStruct" either.)

            Can this be made to work? Thanks...

            EDIT 2:

            I have a workaround, which is to define my enums in a separate class and expose them to QML using the guidelines here, but if possible I'd prefer to avoid this level of indirection, and keep the enums in the struct.

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

            @mzimmers I don't believe it is possible no. Instead of defining your enums in a separate class I would do it in a namespace with Q_ENUM_NS instead.

            GrecKoG mzimmersM 2 Replies Last reply
            0
            • GrecKoG GrecKo

              You can now instantiate Gadgets from QML with undocumented macros (so maybe don't use it).

              Use QML_VALUE_TYPE(typeName) with a lower case name like you currently do.
              Then you can add QML_CONSTRUCTIBLE_VALUE or QML_STRUCTURED_VALUE (even both).

              QML_CONSTRUCTIBLE_VALUE will call a user defined constructor

              if you have Q_INVOKABLE MyStruct(int foo) : m_myInt{foo} {}
              then doing property myStruct myStruct1: 42 will call the constructor with 42 as the foo param

              QML_STRUCTURED_VALUE will assign properties depending on the js object you passed in QML.

              property myStruct myStruct1: ({myInt: 42}) will create a default constructed MyStruct and assign its myInt property to 42.

              Note that the type should always be default constructible.

              EDIT: Note that you don't have to use QML_ELEMENT, Q_DECLARE_METATYPE or qmlRegisterType if you use Q_GADGET and QML_VALUE_TYPE.

              L Offline
              L Offline
              lemons
              wrote on last edited by lemons
              #24

              @GrecKo said in using C++ classes and structs in QML:

              You can now instantiate Gadgets from QML with undocumented macros (so maybe don't use it).

              Use QML_VALUE_TYPE(typeName) with a lower case name like you currently do.
              Then you can add QML_CONSTRUCTIBLE_VALUE or QML_STRUCTURED_VALUE (even both).

              QML_CONSTRUCTIBLE_VALUE will call a user defined constructor

              if you have Q_INVOKABLE MyStruct(int foo) : m_myInt{foo} {}
              then doing property myStruct myStruct1: 42 will call the constructor with 42 as the foo param

              QML_STRUCTURED_VALUE will assign properties depending on the js object you passed in QML.

              property myStruct myStruct1: ({myInt: 42}) will create a default constructed MyStruct and assign its myInt property to 42.

              Note that the type should always be default constructible.

              EDIT: Note that you don't have to use QML_ELEMENT, Q_DECLARE_METATYPE or qmlRegisterType if you use Q_GADGET and QML_VALUE_TYPE.

              This is amazing !!
              Gonna have to explore the possibilities...

              1 Reply Last reply
              0
              • GrecKoG GrecKo

                @mzimmers I don't believe it is possible no. Instead of defining your enums in a separate class I would do it in a namespace with Q_ENUM_NS instead.

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

                Coming back on what I said:

                It is possible to expose an enum from a Q_GADGET.

                If you add pragma ValueTypeBehavior: Addressable at the top of your QML file you can use the lower case gadget type name in QML and then do property int enumValue: myStruct.TestEnum.D

                Alternatively you could do it very verbosely with QML_FOREIGN_NAMESPACE like explained here : https://codereview.qt-project.org/c/qt/qtdeclarative/+/510832 (fresh out of the oven)

                1 Reply Last reply
                0
                • GrecKoG GrecKo

                  @mzimmers I don't believe it is possible no. Instead of defining your enums in a separate class I would do it in a namespace with Q_ENUM_NS instead.

                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #26

                  @GrecKo said in using C++ classes and structs in QML:

                  Instead of defining your enums in a separate class I would do it in a namespace with Q_ENUM_NS instead.

                  namespace scheduleNS {
                  Q_NAMESPACE
                  enum StartAction {
                      START_ACTION_TURN_ON,
                      START_ACTION_TURN_OFF,
                      START_ACTION_BE_READY,
                      START_ACTION_SUSPEND
                  };
                  Q_ENUM_NS(StartAction)
                  } // namespace
                  

                  but "scheduleNS" isn't recognized in my QML. How do I export a C++ namespace to QML?

                  mzimmersM kshegunovK GrecKoG 3 Replies Last reply
                  0
                  • mzimmersM mzimmers

                    @GrecKo said in using C++ classes and structs in QML:

                    Instead of defining your enums in a separate class I would do it in a namespace with Q_ENUM_NS instead.

                    namespace scheduleNS {
                    Q_NAMESPACE
                    enum StartAction {
                        START_ACTION_TURN_ON,
                        START_ACTION_TURN_OFF,
                        START_ACTION_BE_READY,
                        START_ACTION_SUSPEND
                    };
                    Q_ENUM_NS(StartAction)
                    } // namespace
                    

                    but "scheduleNS" isn't recognized in my QML. How do I export a C++ namespace to QML?

                    mzimmersM Offline
                    mzimmersM Offline
                    mzimmers
                    wrote on last edited by
                    #27

                    @mzimmers said in using C++ classes and structs in QML:

                    How do I export a C++ namespace to QML?

                    I should have asked, is there a newer alternative to the old method of manually registering it like this:

                       qmlRegisterUncreatableMetaObject(scheduleNS::staticMetaObject, // static meta object
                                                        "schedule.enums",          // import statement
                                                        1, 0,                         // major and minor version of the import
                                                        "ScheduleNS",                 // name in QML
                                                        "Error: only enums");          // error in case someone tries to create a MyNamespace object
                    

                    This works fine, but given that we no longer need to use qmlRegisterType(), I was wondering whether there was a more modern way of doing the qmlRegisterUncreatableMetaObject() call.

                    1 Reply Last reply
                    0
                    • mzimmersM mzimmers

                      @GrecKo said in using C++ classes and structs in QML:

                      Instead of defining your enums in a separate class I would do it in a namespace with Q_ENUM_NS instead.

                      namespace scheduleNS {
                      Q_NAMESPACE
                      enum StartAction {
                          START_ACTION_TURN_ON,
                          START_ACTION_TURN_OFF,
                          START_ACTION_BE_READY,
                          START_ACTION_SUSPEND
                      };
                      Q_ENUM_NS(StartAction)
                      } // namespace
                      

                      but "scheduleNS" isn't recognized in my QML. How do I export a C++ namespace to QML?

                      kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by
                      #28

                      @mzimmers said in using C++ classes and structs in QML:

                      but "scheduleNS" isn't recognized in my QML. How do I export a C++ namespace to QML?

                      Have you tried naming the namespace with a capital letter?
                      As far as I recall only value types are supposed to be lower case. QML is somewhat picky on the namings.

                      Read and abide by the Qt Code of Conduct

                      mzimmersM 1 Reply Last reply
                      0
                      • kshegunovK kshegunov

                        @mzimmers said in using C++ classes and structs in QML:

                        but "scheduleNS" isn't recognized in my QML. How do I export a C++ namespace to QML?

                        Have you tried naming the namespace with a capital letter?
                        As far as I recall only value types are supposed to be lower case. QML is somewhat picky on the namings.

                        mzimmersM Offline
                        mzimmersM Offline
                        mzimmers
                        wrote on last edited by
                        #29

                        @kshegunov I did try that - I still have to register the uncreatable, and add an import statement to any QML wishing to use it.

                        Still a small price to pay...

                        1 Reply Last reply
                        0
                        • mzimmersM mzimmers

                          @GrecKo said in using C++ classes and structs in QML:

                          Instead of defining your enums in a separate class I would do it in a namespace with Q_ENUM_NS instead.

                          namespace scheduleNS {
                          Q_NAMESPACE
                          enum StartAction {
                              START_ACTION_TURN_ON,
                              START_ACTION_TURN_OFF,
                              START_ACTION_BE_READY,
                              START_ACTION_SUSPEND
                          };
                          Q_ENUM_NS(StartAction)
                          } // namespace
                          

                          but "scheduleNS" isn't recognized in my QML. How do I export a C++ namespace to QML?

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

                          @mzimmers said in using C++ classes and structs in QML:

                          but "scheduleNS" isn't recognized in my QML. How do I export a C++ namespace to QML?

                          With QML_ELEMENT or QML_NAMED_ELEMENT.

                          1 Reply Last reply
                          1
                          • mzimmersM mzimmers has marked this topic as solved on

                          • Login

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