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

                        29/30

                        12 Oct 2023, 22:12

                        • Login

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