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

Best way to access a cpp structure in QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlqtquickqtquick2qvariant
19 Posts 6 Posters 19.9k 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.
  • timdayT timday

    If your struct really is just 5 QStrings, personally I'd just use a QStringList (which I believe QVariant supports nicely) to communicate its state into (and from) the QML/Javascript domain.

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

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

    P 1 Reply Last reply
    3
    • ? 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