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 Updated to NodeBB v4.3 + New Features

using C++ classes and structs in QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
30 Posts 9 Posters 5.6k Views 3 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.
  • L lemons
    10 Oct 2023, 14:22

    @mzimmers
    I thought the Q_GADGET macro is used for meta-types only, which can't be instantiated from QML.
    To be used e.g. if the struct is a property of an QObject derived class, which is somehow accessible in QML (either passed through C++ or created in QML).
    Allows you to use e.g. Q_PROPERTY macros, without the QObject overhead.

    To be creatable from QML you need a derived class from QObject, so the Q_GADGET macro is not sufficient, as it is missing e.g. the signals and slots of the QObject class.

    Note: I can be totally wrong / outdated, but this is how I was thinking and using it all the time :D

    J Offline
    J Offline
    JoeCFD
    wrote on 10 Oct 2023, 14:36 last edited by JoeCFD 10 Oct 2023, 14:39
    #18

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

    Q_GADGET macro

    Lemons seems right.

    In QML (Qt Meta-Object Language), the Q_GADGET macro is typically used with C++ classes to create non-instantiable classes that can be registered with the Qt meta-object system. These classes are similar to Q_OBJECT classes but cannot have signals, slots, or properties. They are often used for data-only structures that need to be exposed to QML.

    I use upper case for my class registration in qmlRegisterType without issues. I guess lower case is needed in app_engine->rootContext()->setContextProperty( ... );

    1 Reply Last reply
    0
    • G Offline
      G Offline
      GrecKo
      Qt Champions 2018
      wrote on 10 Oct 2023, 14:45 last edited by GrecKo 10 Oct 2023, 14:58
      #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.

      M L 2 Replies Last reply 10 Oct 2023, 15:23
      3
      • G GrecKo
        10 Oct 2023, 14:45

        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.

        M Offline
        M Offline
        mzimmers
        wrote on 10 Oct 2023, 15:23 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?

        G 1 Reply Last reply 10 Oct 2023, 16:14
        0
        • M mzimmers
          10 Oct 2023, 15:23

          @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?

          G Offline
          G Offline
          GrecKo
          Qt Champions 2018
          wrote on 10 Oct 2023, 16:14 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.

          M 1 Reply Last reply 10 Oct 2023, 16:24
          1
          • G GrecKo
            10 Oct 2023, 16:14

            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.

            M Offline
            M Offline
            mzimmers
            wrote on 10 Oct 2023, 16:24 last edited by mzimmers 10 Oct 2023, 18:52
            #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.

            G 1 Reply Last reply 11 Oct 2023, 07:55
            0
            • M mzimmers
              10 Oct 2023, 16:24

              @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.

              G Offline
              G Offline
              GrecKo
              Qt Champions 2018
              wrote on 11 Oct 2023, 07:55 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.

              G M 2 Replies Last reply 11 Oct 2023, 13:45
              0
              • G GrecKo
                10 Oct 2023, 14:45

                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 11 Oct 2023, 13:18 last edited by lemons 10 Nov 2023, 13:19
                #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
                • G GrecKo
                  11 Oct 2023, 07:55

                  @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.

                  G Offline
                  G Offline
                  GrecKo
                  Qt Champions 2018
                  wrote on 11 Oct 2023, 13:45 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
                  • G GrecKo
                    11 Oct 2023, 07:55

                    @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.

                    M Offline
                    M Offline
                    mzimmers
                    wrote on 11 Oct 2023, 16:22 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?

                    M K G 3 Replies Last reply 12 Oct 2023, 15:39
                    0
                    • M mzimmers
                      11 Oct 2023, 16:22

                      @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?

                      M Offline
                      M Offline
                      mzimmers
                      wrote on 12 Oct 2023, 15:39 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
                      • M mzimmers
                        11 Oct 2023, 16:22

                        @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?

                        K Offline
                        K Offline
                        kshegunov
                        Moderators
                        wrote on 12 Oct 2023, 22:03 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

                        M 1 Reply Last reply 12 Oct 2023, 22:12
                        0
                        • K kshegunov
                          12 Oct 2023, 22:03

                          @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.

                          M Offline
                          M Offline
                          mzimmers
                          wrote on 12 Oct 2023, 22:12 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
                          • M mzimmers
                            11 Oct 2023, 16:22

                            @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?

                            G Offline
                            G Offline
                            GrecKo
                            Qt Champions 2018
                            wrote on 13 Oct 2023, 08:11 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
                            • M mzimmers has marked this topic as solved on 13 Oct 2023, 18:44

                            27/30

                            12 Oct 2023, 15:39

                            • Login

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