Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Using C++ model in QML
Forum Updated to NodeBB v4.3 + New Features

Using C++ model in QML

Scheduled Pinned Locked Moved Mobile and Embedded
8 Posts 2 Posters 3.2k Views 2 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.
  • imyrvoldI Offline
    imyrvoldI Offline
    imyrvold
    wrote on last edited by imyrvold
    #1

    I have a ListView in my QML file with a model from C++. The model have a QString, a bool and a QList.

    The model works perfect when I don't use the QList:

        QList<QObject*> dataList;
        DataObject *ob = new DataObject("main", false);
        dataList.append(ob);
        dataList.append(new DataObject("Item 2", false));
        dataList.append(new DataObject("Item 3", true));
        dataList.append(new DataObject("Item 4", true));
    
        QQmlContext *ctxt = engine.rootContext();
        ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList));
    

    But the DataObject class contains a QList that contains a list of DataObject classes. Here is where I have problems, as I can't make my project compile.

    I have tried declaring my instance variable as a list of QVariant pointers:

    private:
        QString m_group;
        bool m_checked;
        QList<QVariant*> m_elements;
    

    But my addElement method will not compile, complaining about:
    no matching member function for call to 'append'

    void DataObject::addElement(DataObject *ob)
    {
        m_elements.append(QVariant::fromValue(ob));
    }
    

    What am I doing wrong here?

    p3c0P 1 Reply Last reply
    0
    • imyrvoldI imyrvold

      I have a ListView in my QML file with a model from C++. The model have a QString, a bool and a QList.

      The model works perfect when I don't use the QList:

          QList<QObject*> dataList;
          DataObject *ob = new DataObject("main", false);
          dataList.append(ob);
          dataList.append(new DataObject("Item 2", false));
          dataList.append(new DataObject("Item 3", true));
          dataList.append(new DataObject("Item 4", true));
      
          QQmlContext *ctxt = engine.rootContext();
          ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList));
      

      But the DataObject class contains a QList that contains a list of DataObject classes. Here is where I have problems, as I can't make my project compile.

      I have tried declaring my instance variable as a list of QVariant pointers:

      private:
          QString m_group;
          bool m_checked;
          QList<QVariant*> m_elements;
      

      But my addElement method will not compile, complaining about:
      no matching member function for call to 'append'

      void DataObject::addElement(DataObject *ob)
      {
          m_elements.append(QVariant::fromValue(ob));
      }
      

      What am I doing wrong here?

      p3c0P Offline
      p3c0P Offline
      p3c0
      Moderators
      wrote on last edited by
      #2

      @imyrvold
      So hwo about QList<DataObject*> dataList ? and then the rest as usual i.e appending DataObject directly instead of QVariant

      157

      imyrvoldI 1 Reply Last reply
      0
      • p3c0P p3c0

        @imyrvold
        So hwo about QList<DataObject*> dataList ? and then the rest as usual i.e appending DataObject directly instead of QVariant

        imyrvoldI Offline
        imyrvoldI Offline
        imyrvold
        wrote on last edited by imyrvold
        #3

        @p3c0
        The first thing I tried, was as you suggested, but this doesn't quite work, because I want dataList to function as a ListView model, like this:

        Item {
            width: 200
            height: childView.contentHeight
            visible: mainRow.expanded
        
            ListView {
                id: childView
                anchors.fill: parent
                model: elements
                delegate: groupsDelegate
                focus: true
            }
        }
        
            DataObject *ob = new DataObject("main", false);
            DataObject *ob1 = new DataObject("hr", true);
            DataObject *ob2 = new DataObject("ht", true);
            ob->addElement(ob1);
            ob->addElement(ob2);
            dataList.append(ob);
            dataList.append(new DataObject("Item 2", false));
            dataList.append(new DataObject("Item 3", true));
            dataList.append(new DataObject("Item 4", true));
        
            QQmlContext *ctxt = engine.rootContext();
            ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList));
        

        My addElement is:

        void DataObject::addElement(DataObject *ob)
        {
            m_elements.append(ob);
        }
        

        I get the two elements in the ListView, but QML doesn't recognize them to be a ListModel, because I get a reference error in the log and they shows up without the group name

        qrc:/TreeView.qml:40: ReferenceError: elements is not defined
        qrc:/TreeView.qml:61: ReferenceError: group is not defined
        qrc:/TreeView.qml:73: ReferenceError: elements is not defined
        qrc:/TreeView.qml:40: ReferenceError: elements is not defined
        qrc:/TreeView.qml:61: ReferenceError: group is not defined
        qrc:/TreeView.qml:73: ReferenceError: elements is not defined
        qml: [object Object]
        qml: [DataObject(0x7faceb2958b0),DataObject(0x7faceb295970)]

        and the two console.log lines shows the difference between the checkModel and the elements list (the last with the list of DataObject's).

        The result is this:
        IncompleteCheckBoxes

        1 Reply Last reply
        0
        • imyrvoldI Offline
          imyrvoldI Offline
          imyrvold
          wrote on last edited by
          #4

          Here is an example of how I want the ListModel to be:

                  ListModel {
                      id:listModel
                      ListElement {
                          group: "main"
                          elements: [
                              ListElement {
                                  group: "hr"
                                  elements: [
                                      ListElement {
                                          group: "mainarmA"
                                          elements: []
                                      },
                                      ListElement {
                                          group: "mainarmC"
                                          elements: []
                                      },
                                      ListElement {
                                          group: "mainarmE"
                                          elements: []
                                      }
                                  ]
                              },
                              ListElement {
                                  group: "ht"
                                  elements: [
                                      ListElement {
                                          group: "mainarmD"
                                          elements: []
                                      }
                                  ]
                              }
                          ]
                      }
                      ListElement {
                          group: "aux"
                          elements: [
                              ListElement {
                                  group: "hr"
                                  elements: [
                                      ListElement {
                                          group: "mainarmB"
                                          elements: []
                                      }
                                  ]
                              }
                          ]
                      }
                  }
          

          Then it should look like this:
          IMG

          p3c0P 1 Reply Last reply
          0
          • imyrvoldI imyrvold

            Here is an example of how I want the ListModel to be:

                    ListModel {
                        id:listModel
                        ListElement {
                            group: "main"
                            elements: [
                                ListElement {
                                    group: "hr"
                                    elements: [
                                        ListElement {
                                            group: "mainarmA"
                                            elements: []
                                        },
                                        ListElement {
                                            group: "mainarmC"
                                            elements: []
                                        },
                                        ListElement {
                                            group: "mainarmE"
                                            elements: []
                                        }
                                    ]
                                },
                                ListElement {
                                    group: "ht"
                                    elements: [
                                        ListElement {
                                            group: "mainarmD"
                                            elements: []
                                        }
                                    ]
                                }
                            ]
                        }
                        ListElement {
                            group: "aux"
                            elements: [
                                ListElement {
                                    group: "hr"
                                    elements: [
                                        ListElement {
                                            group: "mainarmB"
                                            elements: []
                                        }
                                    ]
                                }
                            ]
                        }
                    }
            

            Then it should look like this:
            IMG

            p3c0P Offline
            p3c0P Offline
            p3c0
            Moderators
            wrote on last edited by
            #5

            @imyrvold It seems you want to implement TreeView. why don't you use it directly ? Qt 5.5 now has TreeView.

            157

            imyrvoldI 1 Reply Last reply
            0
            • p3c0P p3c0

              @imyrvold It seems you want to implement TreeView. why don't you use it directly ? Qt 5.5 now has TreeView.

              imyrvoldI Offline
              imyrvoldI Offline
              imyrvold
              wrote on last edited by
              #6

              @p3c0
              I didn't know that. I will investigate it, certainly. Thank you for the tip!

              1 Reply Last reply
              0
              • imyrvoldI Offline
                imyrvoldI Offline
                imyrvold
                wrote on last edited by imyrvold
                #7

                To wrap this up, I have concluded that setting the QQmlContext property doesn't work in my case. I found another way to do it, that works perfectly, with the same DataObject, and that is to use QMetaObject to invokeMethod in my ListModel with the DataObject as parameter, and append the DataObject in the invoked function.
                In the following main.cpp listing which shows this, the commented out lines are the ones that for some reason didn't work:

                #include <QApplication>
                #include <QQmlApplicationEngine>
                #include <QQmlComponent>
                //#include <QQmlContext>
                #include <qqml.h>
                #include <QQuickItem>
                #include <QQuickView>
                #include "dataobject.h"
                
                int main(int argc, char *argv[])
                {
                    QApplication app(argc, argv);
                
                    QQmlApplicationEngine engine;
                
                 //    QList<QObject*> dataList;
                
                    DataObject *ob = new DataObject("main", false);
                    DataObject *ob1 = new DataObject("hr", false);
                    DataObject *ob2 = new DataObject("ht", true);
                    DataObject *ob11 = new DataObject("mainarmA", false);
                    DataObject *ob12 = new DataObject("mainarmC", false);
                    DataObject *ob13 = new DataObject("mainarmE", true);
                    DataObject *ob21 = new DataObject("mainarmD", true);
                    ob1->addElement(ob11);
                    ob1->addElement(ob12);
                    ob1->addElement(ob13);
                    ob2->addElement(ob21);
                    ob->addElement(ob1);
                    ob->addElement(ob2);
                
                    QVariant v;
                    v = QVariant::fromValue(ob);
                
                //    dataList.append(ob);
                
                //    QQmlContext *ctxt = engine.rootContext();
                //    ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList));
                
                    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
                
                    QMetaObject::invokeMethod((QObject *)engine.rootObjects().first()->findChild<QObject *>("checklistModel"),  "appendElement", Q_ARG(QVariant, v));
                
                    return app.exec();
                }
                

                and the ListModel with the invoked function:

                        ListModel {
                            id:checklistModel
                            objectName: "checklistModel"
                            function appendElement(ob) {
                                checklistModel.append(ob)
                            }
                        }
                
                p3c0P 1 Reply Last reply
                0
                • imyrvoldI imyrvold

                  To wrap this up, I have concluded that setting the QQmlContext property doesn't work in my case. I found another way to do it, that works perfectly, with the same DataObject, and that is to use QMetaObject to invokeMethod in my ListModel with the DataObject as parameter, and append the DataObject in the invoked function.
                  In the following main.cpp listing which shows this, the commented out lines are the ones that for some reason didn't work:

                  #include <QApplication>
                  #include <QQmlApplicationEngine>
                  #include <QQmlComponent>
                  //#include <QQmlContext>
                  #include <qqml.h>
                  #include <QQuickItem>
                  #include <QQuickView>
                  #include "dataobject.h"
                  
                  int main(int argc, char *argv[])
                  {
                      QApplication app(argc, argv);
                  
                      QQmlApplicationEngine engine;
                  
                   //    QList<QObject*> dataList;
                  
                      DataObject *ob = new DataObject("main", false);
                      DataObject *ob1 = new DataObject("hr", false);
                      DataObject *ob2 = new DataObject("ht", true);
                      DataObject *ob11 = new DataObject("mainarmA", false);
                      DataObject *ob12 = new DataObject("mainarmC", false);
                      DataObject *ob13 = new DataObject("mainarmE", true);
                      DataObject *ob21 = new DataObject("mainarmD", true);
                      ob1->addElement(ob11);
                      ob1->addElement(ob12);
                      ob1->addElement(ob13);
                      ob2->addElement(ob21);
                      ob->addElement(ob1);
                      ob->addElement(ob2);
                  
                      QVariant v;
                      v = QVariant::fromValue(ob);
                  
                  //    dataList.append(ob);
                  
                  //    QQmlContext *ctxt = engine.rootContext();
                  //    ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList));
                  
                      engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
                  
                      QMetaObject::invokeMethod((QObject *)engine.rootObjects().first()->findChild<QObject *>("checklistModel"),  "appendElement", Q_ARG(QVariant, v));
                  
                      return app.exec();
                  }
                  

                  and the ListModel with the invoked function:

                          ListModel {
                              id:checklistModel
                              objectName: "checklistModel"
                              function appendElement(ob) {
                                  checklistModel.append(ob)
                              }
                          }
                  
                  p3c0P Offline
                  p3c0P Offline
                  p3c0
                  Moderators
                  wrote on last edited by
                  #8

                  @imyrvold Glad that you found the solution :) But to be future ready use TreeView as the view and QAbstractItemModel as the model.

                  157

                  1 Reply Last reply
                  0

                  • Login

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