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

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

    @timday QStringList is directly supported by QML, no need to go through QVariant.

    P Offline
    P Offline
    Praveen_2017
    wrote on last edited by Praveen_2017
    #5
    This post is deleted!
    1 Reply Last reply
    0
    • ? 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