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. Best way to access a cpp structure in QML
QtWS25 Last Chance

Best way to access a cpp structure in QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlqtquickqtquick2qvariant
19 Posts 6 Posters 19.8k 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.
  • ? A Former User

    Hi! Simple answer is: no. To make the members' names available to QML your object has to derive from QObject and expose the members via Q_PROPERTY. If, for some reason, you need to keep the struct as it is, you'll need to provide a wrapper class as an interface to QML, like:

    #ifndef MYWRAPPER_H
    #define MYWRAPPER_H
    
    #include <QObject>
    
    class MyStruct;
    
    class MyWrapper : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(int val READ val WRITE setVal NOTIFY valChanged)
        // ...
    
    public:
        explicit MyWrapper(QObject *parent = nullptr);
        ~MyWrapper();
    
        int val() const;
        void setVal(int v);
        // ...
    
    signals:
        valChanged(int);
        // ...
    
    private:
        MyStruct *m_myStruct;
    };
    
    #endif // MYWRAPPER_H
    

    A QVariant with a POD inside does not expose its members' names to the QML environment. If you want to go with QVariant and have names you need to use QVariantMap. Here is a class "Car" that exposes your MyStruct as a QVariantMap:

    car.h

    #ifndef CAR_H
    #define CAR_H
    
    #include <QObject>
    #include <QVariantMap>
    #include "mystruct.h"
    
    class Car : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QVariantMap myStruct READ getMyStruct WRITE setMyStruct NOTIFY myStructChanged)
    
    public:
        Car(QObject *parent = nullptr);
    
        QVariantMap getMyStruct() const;
        void setMyStruct(QVariantMap myStruct);
    
    signals:
        void myStructChanged(QVariantMap myStruct);
    
    private:
        MyStruct m_myStruct;
    };
    
    #endif // CAR_H
    

    car.cpp

    #include "car.h"
    #include "myadapter.h"
    
    Car::Car(QObject *parent)
        : QObject(parent)
    {
    }
    
    QVariantMap Car::getMyStruct() const
    {
        return myStructToQVariantMap(m_myStruct);
    }
    
    void Car::setMyStruct(QVariantMap myStruct)
    {
        MyStruct newValue = myStructFromQVariantMap(myStruct);
        if (myStructEqual(m_myStruct, newValue))
            return;
        m_myStruct = newValue;
        emit myStructChanged(myStruct);
    }
    

    It relies on some helper functions:
    myadapter.h

    #ifndef MYADAPTER_H
    #define MYADAPTER_H
    
    #include "mystruct.h"
    #include <QVariantMap>
    
    QVariantMap myStructToQVariantMap(MyStruct const &myStruct);
    MyStruct myStructFromQVariantMap(QVariantMap const &vm);
    bool myStructEqual(MyStruct const &myStruct1, MyStruct const &myStruct2);
    
    #endif // MYADAPTER_H
    

    myadapter.cpp

    #include "myadapter.h"
    
    QVariantMap myStructToQVariantMap(const MyStruct &myStruct)
    {
        QVariantMap res;
        res.insert("val", myStruct.val);
        res.insert("name1", myStruct.name1);
        res.insert("name2", myStruct.name2);
        res.insert("name3", myStruct.name3);
        res.insert("name4", myStruct.name4);
        return res;
    }
    
    MyStruct myStructFromQVariantMap(const QVariantMap &vm)
    {
        MyStruct res;
        res.val = vm.value("val").toInt();
        res.name1 = vm.value("name1").toString();
        res.name2 = vm.value("name2").toString();
        res.name3 = vm.value("name3").toString();
        res.name4 = vm.value("name4").toString();
        return res;
    }
    
    bool myStructEqual(MyStruct const &myStruct1, MyStruct const &myStruct2)
    {
        if (myStruct1.val != myStruct2.val) return false;
        if (myStruct1.name1 != myStruct2.name1) return false;
        if (myStruct1.name2 != myStruct2.name2) return false;
        if (myStruct1.name3 != myStruct2.name3) return false;
        if (myStruct1.name4 != myStruct2.name4) return false;
        return true;
    }
    

    As you can see, this QVariantMap approach is pretty cumbersome and obviously involves a lot of copying. But at least you can now access "the members" by their names in QML and you get the notifications when the MyStruct object changes.

        Forum.Car {
            id: myCar
        }
    
        Row {
            anchors.centerIn: parent
            spacing: 20
    
            Button {
                text: "click me"
                onClicked: {
                    var obj = myCar.myStruct // retrieve a copy of the struct
                    obj.val = 42 // set value in the copy
                    myCar.myStruct = obj // replace old struct with the copy
                }
            }
    
            Label {
                text: myCar.myStruct.val
            }
        }
    
    P Offline
    P Offline
    pra7
    wrote on last edited by
    #6

    @Wieland Thanks!!! for your suggestion after lot of reading and searching I got the answer ,Actually we can use structs or any object which is not derived from QObject by using Q_GADGET :

    struct MyStruct {
        Q_GADGET
        int m_val;
        QString m_name1;
        QString m_name2;
        QString m_name3;
        QString m_name4;
        Q_PROPERTY(int val MEMBER m_val)
        Q_PROPERTY(QString name1 MEMBER m_name1)
        Q_PROPERTY(QString name2 MEMBER m_name2)
        Q_PROPERTY(QString name3 MEMBER m_name3)
        Q_PROPERTY(QString name4 MEMBER m_name4)
    };
    

    Then in my class i just replaced QVariant as below :

    class MyClass:public QObject
    {
        Q_OBJECT
        Q_PROPERTY(MyStruct mystr READ getMyStruct
                    WRITE setMyStruct NOTIFY myStructChanged)
    
    public:
        explicit MyClass(QObject *parent = nullptr);
        MyStruct strObj;
    
         // Edit: changed get function
         MyStruct getMyStruct() const
         {
             return strObj;
         }
    
    // Edit: Added set function
         void setMyStruct(myStruct val)
            {
                mystr = val;
                emit myStructChanged();
            }
    signals:
    void myStructChanged();
    
    }
    

    Now in QML file i can just use classObj.mystr.name1 to access the members and i can just use classObj.mystr.name1 = "abc" to set the values.

    ? S 2 Replies Last reply
    4
    • P pra7

      @Wieland Thanks!!! for your suggestion after lot of reading and searching I got the answer ,Actually we can use structs or any object which is not derived from QObject by using Q_GADGET :

      struct MyStruct {
          Q_GADGET
          int m_val;
          QString m_name1;
          QString m_name2;
          QString m_name3;
          QString m_name4;
          Q_PROPERTY(int val MEMBER m_val)
          Q_PROPERTY(QString name1 MEMBER m_name1)
          Q_PROPERTY(QString name2 MEMBER m_name2)
          Q_PROPERTY(QString name3 MEMBER m_name3)
          Q_PROPERTY(QString name4 MEMBER m_name4)
      };
      

      Then in my class i just replaced QVariant as below :

      class MyClass:public QObject
      {
          Q_OBJECT
          Q_PROPERTY(MyStruct mystr READ getMyStruct
                      WRITE setMyStruct NOTIFY myStructChanged)
      
      public:
          explicit MyClass(QObject *parent = nullptr);
          MyStruct strObj;
      
           // Edit: changed get function
           MyStruct getMyStruct() const
           {
               return strObj;
           }
      
      // Edit: Added set function
           void setMyStruct(myStruct val)
              {
                  mystr = val;
                  emit myStructChanged();
              }
      signals:
      void myStructChanged();
      
      }
      

      Now in QML file i can just use classObj.mystr.name1 to access the members and i can just use classObj.mystr.name1 = "abc" to set the values.

      ? Offline
      ? Offline
      A Former User
      wrote on last edited by
      #7

      @pra7 Yes, that's possible, too. Just note that with that solution, MyStruct won't send notifications when a member changes. This is how basic QML types (e.g. color) are implemented.

      1 Reply Last reply
      3
      • ? Offline
        ? Offline
        A Former User
        wrote on last edited by A Former User
        #8

        One more thing, you did this...

        struct MyStruct {
            Q_GADGET 
            int m_val;
            QString m_name1;
            QString m_name2;
            QString m_name3;
            QString m_name4;
            Q_PROPERTY(int val MEMBER m_val)
            Q_PROPERTY(QString name1 MEMBER m_name1)
            Q_PROPERTY(QString name2 MEMBER m_name2)
            Q_PROPERTY(QString name3 MEMBER m_name3)
            Q_PROPERTY(QString name4 MEMBER m_name4)
        };
        

        ... where you put Q_GADGET in the public section. This has the side effect that all the members that come after Q_GADGET are private now. That's because Q_GADGET is a macro that expands to...

        #define Q_GADGET \
        public: \
            static const QMetaObject staticMetaObject; \
            void qt_check_for_QGADGET_macro(); \
            typedef void QtGadgetHelper; \
        private: \
            QT_WARNING_PUSH \
            Q_OBJECT_NO_ATTRIBUTES_WARNING \
            Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
            QT_WARNING_POP \
            QT_ANNOTATE_CLASS(qt_qgadget, "") \
            /*end*/
        

        ... , see qobjectdefs.h.

        So maybe better follow the usual convention to avoid surprises:

        class MyStruct {
            Q_GADGET 
            Q_PROPERTY(int val MEMBER m_val)
            Q_PROPERTY(QString name1 MEMBER m_name1)
            Q_PROPERTY(QString name2 MEMBER m_name2)
            Q_PROPERTY(QString name3 MEMBER m_name3)
            Q_PROPERTY(QString name4 MEMBER m_name4)
        public:
            int m_val;
            QString m_name1;
            QString m_name2;
            QString m_name3;
            QString m_name4;
        };
        
        P 2 Replies Last reply
        6
        • ? A Former User

          One more thing, you did this...

          struct MyStruct {
              Q_GADGET 
              int m_val;
              QString m_name1;
              QString m_name2;
              QString m_name3;
              QString m_name4;
              Q_PROPERTY(int val MEMBER m_val)
              Q_PROPERTY(QString name1 MEMBER m_name1)
              Q_PROPERTY(QString name2 MEMBER m_name2)
              Q_PROPERTY(QString name3 MEMBER m_name3)
              Q_PROPERTY(QString name4 MEMBER m_name4)
          };
          

          ... where you put Q_GADGET in the public section. This has the side effect that all the members that come after Q_GADGET are private now. That's because Q_GADGET is a macro that expands to...

          #define Q_GADGET \
          public: \
              static const QMetaObject staticMetaObject; \
              void qt_check_for_QGADGET_macro(); \
              typedef void QtGadgetHelper; \
          private: \
              QT_WARNING_PUSH \
              Q_OBJECT_NO_ATTRIBUTES_WARNING \
              Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
              QT_WARNING_POP \
              QT_ANNOTATE_CLASS(qt_qgadget, "") \
              /*end*/
          

          ... , see qobjectdefs.h.

          So maybe better follow the usual convention to avoid surprises:

          class MyStruct {
              Q_GADGET 
              Q_PROPERTY(int val MEMBER m_val)
              Q_PROPERTY(QString name1 MEMBER m_name1)
              Q_PROPERTY(QString name2 MEMBER m_name2)
              Q_PROPERTY(QString name3 MEMBER m_name3)
              Q_PROPERTY(QString name4 MEMBER m_name4)
          public:
              int m_val;
              QString m_name1;
              QString m_name2;
              QString m_name3;
              QString m_name4;
          };
          
          P Offline
          P Offline
          pra7
          wrote on last edited by
          #9

          @Wieland Thanks !! for pointing that .

          1 Reply Last reply
          1
          • ? A Former User

            One more thing, you did this...

            struct MyStruct {
                Q_GADGET 
                int m_val;
                QString m_name1;
                QString m_name2;
                QString m_name3;
                QString m_name4;
                Q_PROPERTY(int val MEMBER m_val)
                Q_PROPERTY(QString name1 MEMBER m_name1)
                Q_PROPERTY(QString name2 MEMBER m_name2)
                Q_PROPERTY(QString name3 MEMBER m_name3)
                Q_PROPERTY(QString name4 MEMBER m_name4)
            };
            

            ... where you put Q_GADGET in the public section. This has the side effect that all the members that come after Q_GADGET are private now. That's because Q_GADGET is a macro that expands to...

            #define Q_GADGET \
            public: \
                static const QMetaObject staticMetaObject; \
                void qt_check_for_QGADGET_macro(); \
                typedef void QtGadgetHelper; \
            private: \
                QT_WARNING_PUSH \
                Q_OBJECT_NO_ATTRIBUTES_WARNING \
                Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
                QT_WARNING_POP \
                QT_ANNOTATE_CLASS(qt_qgadget, "") \
                /*end*/
            

            ... , see qobjectdefs.h.

            So maybe better follow the usual convention to avoid surprises:

            class MyStruct {
                Q_GADGET 
                Q_PROPERTY(int val MEMBER m_val)
                Q_PROPERTY(QString name1 MEMBER m_name1)
                Q_PROPERTY(QString name2 MEMBER m_name2)
                Q_PROPERTY(QString name3 MEMBER m_name3)
                Q_PROPERTY(QString name4 MEMBER m_name4)
            public:
                int m_val;
                QString m_name1;
                QString m_name2;
                QString m_name3;
                QString m_name4;
            };
            
            P Offline
            P Offline
            pra7
            wrote on last edited by
            #10

            @Wieland Is there any possibility that I can access structure inside a structure?

            struct MyStruct {
            Q_GADGET
            int m_val;
            QString m_name1;
            QString m_name2;
            QString m_name3;
            QString m_name4;
            MyNewStruct m_newStr; //** new Struct includes Q_GADGET macro and member definations. 
            
            Q_PROPERTY(int val MEMBER m_val)
            Q_PROPERTY(QString name1 MEMBER m_name1)
            Q_PROPERTY(QString name2 MEMBER m_name2)
            Q_PROPERTY(QString name3 MEMBER m_name3)
            Q_PROPERTY(QString name4 MEMBER m_name4)
            
            Q_PROPERTY(MyNewStruct newStr MEMBER m_newStr) //**Currently getting error 
            };
            
            M 1 Reply Last reply
            0
            • ? Offline
              ? Offline
              A Former User
              wrote on last edited by
              #11

              @pra7 said in Best way to access a cpp structure in QML:

              //**Currently getting error

              What error?

              P P 2 Replies Last reply
              0
              • ? A Former User

                @pra7 said in Best way to access a cpp structure in QML:

                //**Currently getting error

                What error?

                P Offline
                P Offline
                Praveen_2017
                wrote on last edited by
                #12
                This post is deleted!
                1 Reply Last reply
                0
                • ? A Former User

                  @pra7 said in Best way to access a cpp structure in QML:

                  //**Currently getting error

                  What error?

                  P Offline
                  P Offline
                  pra7
                  wrote on last edited by
                  #13

                  @Wieland

                  error: no match for 'operator!=' (operand types are 'myStruct1' and 'myStruct1') if (_t->mynewstr != *reinterpret_cast< myStruct1*>(_v)) {
                  

                  where Mystruct1 is myNewStruct and the error is in MOC ...

                  1 Reply Last reply
                  0
                  • ? Offline
                    ? Offline
                    A Former User
                    wrote on last edited by
                    #14

                    The MOC generates some code for you to implement all the Gadget / Property stuff. Looks like the generated code uses the != operator for MyStruct. So you need to implement that:

                    public:
                        bool operator==(MyStruct const &other) const;
                        bool operator!=(MyStruct const &other) const;
                    
                    bool MyStruct::operator==(const MyStruct &other) const
                    {
                        // compare members 
                        return true;
                    }
                    
                    bool MyStruct::operator!=(MyStruct const &other) const
                    {
                        return !(*this == other);
                    }
                    
                    P 1 Reply Last reply
                    3
                    • ? A Former User

                      The MOC generates some code for you to implement all the Gadget / Property stuff. Looks like the generated code uses the != operator for MyStruct. So you need to implement that:

                      public:
                          bool operator==(MyStruct const &other) const;
                          bool operator!=(MyStruct const &other) const;
                      
                      bool MyStruct::operator==(const MyStruct &other) const
                      {
                          // compare members 
                          return true;
                      }
                      
                      bool MyStruct::operator!=(MyStruct const &other) const
                      {
                          return !(*this == other);
                      }
                      
                      P Offline
                      P Offline
                      pra7
                      wrote on last edited by
                      #15

                      @Wieland That worked !!! Thanks, How to know that which all operators should be overloaded?

                      ? 1 Reply Last reply
                      1
                      • P pra7

                        @Wieland That worked !!! Thanks, How to know that which all operators should be overloaded?

                        ? Offline
                        ? Offline
                        A Former User
                        wrote on last edited by
                        #16

                        @pra7 said in Best way to access a cpp structure in QML:

                        How to know that which all operators should be overloaded?

                        You can't really know. But when the compiler complains about a missing operator, just implement it. In this case we didn't really need the == operator, but I'd say it's common practice to implement the != operator using the == operator.

                        P 1 Reply Last reply
                        3
                        • ? A Former User

                          @pra7 said in Best way to access a cpp structure in QML:

                          How to know that which all operators should be overloaded?

                          You can't really know. But when the compiler complains about a missing operator, just implement it. In this case we didn't really need the == operator, but I'd say it's common practice to implement the != operator using the == operator.

                          P Offline
                          P Offline
                          pra7
                          wrote on last edited by
                          #17

                          @Wieland Thanks for all your suggestions.

                          1 Reply Last reply
                          1
                          • P pra7

                            @Wieland Is there any possibility that I can access structure inside a structure?

                            struct MyStruct {
                            Q_GADGET
                            int m_val;
                            QString m_name1;
                            QString m_name2;
                            QString m_name3;
                            QString m_name4;
                            MyNewStruct m_newStr; //** new Struct includes Q_GADGET macro and member definations. 
                            
                            Q_PROPERTY(int val MEMBER m_val)
                            Q_PROPERTY(QString name1 MEMBER m_name1)
                            Q_PROPERTY(QString name2 MEMBER m_name2)
                            Q_PROPERTY(QString name3 MEMBER m_name3)
                            Q_PROPERTY(QString name4 MEMBER m_name4)
                            
                            Q_PROPERTY(MyNewStruct newStr MEMBER m_newStr) //**Currently getting error 
                            };
                            
                            M Offline
                            M Offline
                            Mammamia
                            wrote on last edited by
                            #18

                            @pra7, @Wieland how can I access a list of Structure inside another Structure.
                            Eg: From the above example, I need to use

                            QList<MyNewStructure> m_StructList;
                            
                            How is that possible? I have tried,
                            QList<MyNewStructure> m_StructList;
                            
                            Q_PROPERTY(QList<MyNewStruct> newStr MEMBER m_newStr) but didnt help.
                            
                            1 Reply Last reply
                            0
                            • P pra7

                              @Wieland Thanks!!! for your suggestion after lot of reading and searching I got the answer ,Actually we can use structs or any object which is not derived from QObject by using Q_GADGET :

                              struct MyStruct {
                                  Q_GADGET
                                  int m_val;
                                  QString m_name1;
                                  QString m_name2;
                                  QString m_name3;
                                  QString m_name4;
                                  Q_PROPERTY(int val MEMBER m_val)
                                  Q_PROPERTY(QString name1 MEMBER m_name1)
                                  Q_PROPERTY(QString name2 MEMBER m_name2)
                                  Q_PROPERTY(QString name3 MEMBER m_name3)
                                  Q_PROPERTY(QString name4 MEMBER m_name4)
                              };
                              

                              Then in my class i just replaced QVariant as below :

                              class MyClass:public QObject
                              {
                                  Q_OBJECT
                                  Q_PROPERTY(MyStruct mystr READ getMyStruct
                                              WRITE setMyStruct NOTIFY myStructChanged)
                              
                              public:
                                  explicit MyClass(QObject *parent = nullptr);
                                  MyStruct strObj;
                              
                                   // Edit: changed get function
                                   MyStruct getMyStruct() const
                                   {
                                       return strObj;
                                   }
                              
                              // Edit: Added set function
                                   void setMyStruct(myStruct val)
                                      {
                                          mystr = val;
                                          emit myStructChanged();
                                      }
                              signals:
                              void myStructChanged();
                              
                              }
                              

                              Now in QML file i can just use classObj.mystr.name1 to access the members and i can just use classObj.mystr.name1 = "abc" to set the values.

                              S Offline
                              S Offline
                              seyed
                              wrote on last edited by
                              #19

                              @pra7 but it does not sufficient! I had to use Q_DECLARE_METATYPE() and qRegisterMetaType<>() to avoid unknown type error. Did I missed something?

                              1 Reply Last reply
                              0
                              • R Rua3n referenced this topic on
                              • R Rua3n referenced this topic on

                              • Login

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