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
Servers for Qt installer are currently down

using C++ classes and structs in QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
30 Posts 9 Posters 5.4k 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.
  • 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

                          28/30

                          12 Oct 2023, 22:03

                          • Login

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