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. Unable to update Listview using QAbstractItemModel class

Unable to update Listview using QAbstractItemModel class

Scheduled Pinned Locked Moved Solved QML and Qt Quick
9 Posts 2 Posters 681 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.
  • J Offline
    J Offline
    James A
    wrote on last edited by
    #1

    I am trying to update the Listview from c++ data model which is the subclass of QAbstractItemModel. When the run the program the listview is empty
    During debugging I observed that the following functions are not called which I think it is required for displaying the model data to the view

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QHash<int, QByteArray> roleNames() const;

    I have added the required snippets of the code below

    ================testmodel.h=================================

    #include <QAbstractItemModel>

    class Data {
    QString name ;
    int strength;

    public:

    Data(QString name ,int strength);
    int getStrength() const;
    void setStrength(int value);
    QString getName() const;
    void setName(const QString &value);
    

    };

    class TestModel : public QAbstractItemModel
    {
    Q_OBJECT

    public:

    enum Roles {
        nameRole = Qt::UserRole + 1,
        strengthRole
    };
    
    explicit TestModel(QObject *parent = nullptr);
    
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    
    void addRows(Data data);
    

    protected:
    QHash<int, QByteArray> roleNames() const;

    private:
    QList<Data> list;

    };

    ================testmodel.cpp=================================

    QVariant TestModel::data(const QModelIndex &index, int role) const
    {
    if (index.row() < 0 || index.row() >= list.count())
    return QVariant();

    const Data &animal = list[index.row()];
    if (role == nameRole)
        return animal.getName();
    else if (role == strengthRole)
        return animal.getStrength();
    
    return QVariant();
    

    }

    void TestModel::addRows(Data data)
    {
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    list << data;
    endInsertRows();
    }

    QHash<int, QByteArray> TestModel::roleNames() const
    {
    QHash<int, QByteArray> roles;
    roles[nameRole] = "name";
    roles[strengthRole] = "strength";
    return roles;

    }

    ==============main.cpp========================================

    int main(int argc, char ** argv)
    {
    QGuiApplication app(argc, argv);

    TestModel testmodel;
    
    testmodel.addRows(Data("name1",5));
    testmodel.addRows(Data("name2",10));
    
    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    
    QQmlContext *ctxt = view.rootContext();
    ctxt->setContextProperty("myModel", &testmodel);
    
    view.setSource(QUrl("qrc:view.qml"));
    view.show();
    
    return app.exec();
    

    }

    ==================view.qml====================================

    import QtQuick 2.0

    Item {
    width: 200; height: 250

    ListView {
        width: 200; height: 250
    
        anchors.fill: parent
        model: myModel
        delegate: Text {  text: "mydata" + name + ", " + strength }
    }
    

    }

    raven-worxR 1 Reply Last reply
    0
    • J James A

      I am trying to update the Listview from c++ data model which is the subclass of QAbstractItemModel. When the run the program the listview is empty
      During debugging I observed that the following functions are not called which I think it is required for displaying the model data to the view

      QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
      QHash<int, QByteArray> roleNames() const;

      I have added the required snippets of the code below

      ================testmodel.h=================================

      #include <QAbstractItemModel>

      class Data {
      QString name ;
      int strength;

      public:

      Data(QString name ,int strength);
      int getStrength() const;
      void setStrength(int value);
      QString getName() const;
      void setName(const QString &value);
      

      };

      class TestModel : public QAbstractItemModel
      {
      Q_OBJECT

      public:

      enum Roles {
          nameRole = Qt::UserRole + 1,
          strengthRole
      };
      
      explicit TestModel(QObject *parent = nullptr);
      
      int rowCount(const QModelIndex &parent = QModelIndex()) const override;
      
      QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
      
      void addRows(Data data);
      

      protected:
      QHash<int, QByteArray> roleNames() const;

      private:
      QList<Data> list;

      };

      ================testmodel.cpp=================================

      QVariant TestModel::data(const QModelIndex &index, int role) const
      {
      if (index.row() < 0 || index.row() >= list.count())
      return QVariant();

      const Data &animal = list[index.row()];
      if (role == nameRole)
          return animal.getName();
      else if (role == strengthRole)
          return animal.getStrength();
      
      return QVariant();
      

      }

      void TestModel::addRows(Data data)
      {
      beginInsertRows(QModelIndex(), rowCount(), rowCount());
      list << data;
      endInsertRows();
      }

      QHash<int, QByteArray> TestModel::roleNames() const
      {
      QHash<int, QByteArray> roles;
      roles[nameRole] = "name";
      roles[strengthRole] = "strength";
      return roles;

      }

      ==============main.cpp========================================

      int main(int argc, char ** argv)
      {
      QGuiApplication app(argc, argv);

      TestModel testmodel;
      
      testmodel.addRows(Data("name1",5));
      testmodel.addRows(Data("name2",10));
      
      QQuickView view;
      view.setResizeMode(QQuickView::SizeRootObjectToView);
      
      QQmlContext *ctxt = view.rootContext();
      ctxt->setContextProperty("myModel", &testmodel);
      
      view.setSource(QUrl("qrc:view.qml"));
      view.show();
      
      return app.exec();
      

      }

      ==================view.qml====================================

      import QtQuick 2.0

      Item {
      width: 200; height: 250

      ListView {
          width: 200; height: 250
      
          anchors.fill: parent
          model: myModel
          delegate: Text {  text: "mydata" + name + ", " + strength }
      }
      

      }

      raven-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by raven-worx
      #2

      @James-A
      since you inherit from QAbstractItemModel you should also implement columnCount() - and return at least 1 column.
      Maybe inheriting from QAbstractListModel is more suited for you? It implements a few methods for lists already.

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      1 Reply Last reply
      0
      • J Offline
        J Offline
        James A
        wrote on last edited by
        #3

        @raven-worx
        I tried inheriting from the QAbstractListModel class and implemented columnCount() function and returned columnCount as 2 , sines there are 2 roles , but the listview is not updating after this change

        raven-worxR 1 Reply Last reply
        0
        • J James A

          @raven-worx
          I tried inheriting from the QAbstractListModel class and implemented columnCount() function and returned columnCount as 2 , sines there are 2 roles , but the listview is not updating after this change

          raven-worxR Offline
          raven-worxR Offline
          raven-worx
          Moderators
          wrote on last edited by raven-worx
          #4

          @James-A

          1. either implement columnCount() OR inherit from QAbstractListModel
          2. no need to return a column count of 2, since a list always has 1 column
          3. each model index can return multiple roles

          Does the count property in the listview change?

          ListView {
              onCountChanged: console.log("count changed: " + count)
          }
          

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          1 Reply Last reply
          0
          • J Offline
            J Offline
            James A
            wrote on last edited by
            #5

            @raven-worx

            Now I tried inheriting from QAbstractListModel class and the count property shows :
            qml: count changed: 0

            raven-worxR 1 Reply Last reply
            0
            • J James A

              @raven-worx

              Now I tried inheriting from QAbstractListModel class and the count property shows :
              qml: count changed: 0

              raven-worxR Offline
              raven-worxR Offline
              raven-worx
              Moderators
              wrote on last edited by
              #6

              @James-A
              i dont see any issue in your code. The last thing that could be wrong is the rowCount() implementation?

              --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
              If you have a question please use the forum so others can benefit from the solution in the future

              1 Reply Last reply
              0
              • J Offline
                J Offline
                James A
                wrote on last edited by
                #7

                @raven-worx

                Thanks for pointing it out. It was the issue with rowCount() implementation.
                I commented the old code and updated as shown below , Now the Listview is updating

                int TestModel::rowCount(const QModelIndex &parent) const
                {
                // if (!parent.isValid())
                // return 0;
                // return list.count();

                Q_UNUSED(parent);
                return list.count();
                

                }

                And while going through the documentation , I found the below virtual function for inserting rows into the model. But how to pass the "Data" Object to this function ?

                bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;

                I want to replace this user defined function testmodel.addRows(Data ) with the insertRows virtual function

                raven-worxR 1 Reply Last reply
                0
                • J James A

                  @raven-worx

                  Thanks for pointing it out. It was the issue with rowCount() implementation.
                  I commented the old code and updated as shown below , Now the Listview is updating

                  int TestModel::rowCount(const QModelIndex &parent) const
                  {
                  // if (!parent.isValid())
                  // return 0;
                  // return list.count();

                  Q_UNUSED(parent);
                  return list.count();
                  

                  }

                  And while going through the documentation , I found the below virtual function for inserting rows into the model. But how to pass the "Data" Object to this function ?

                  bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;

                  I want to replace this user defined function testmodel.addRows(Data ) with the insertRows virtual function

                  raven-worxR Offline
                  raven-worxR Offline
                  raven-worx
                  Moderators
                  wrote on last edited by raven-worx
                  #8

                  @James-A
                  actually the following would be more accurate:

                  int TestModel::rowCount(const QModelIndex &parent) const
                  {
                      if (parent.isValid())
                          return 0;
                      return list.count();
                  }
                  

                  The insertRow() method is used by other Qt classes (drag-n-drop, etc.) for example.
                  Going this route means calling insertRow() to add a (default) item at the given position and call setData() on that newly inserted item.

                  So the way you are currently using is way more efficient and ok.

                  --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                  If you have a question please use the forum so others can benefit from the solution in the future

                  1 Reply Last reply
                  0
                  • J Offline
                    J Offline
                    James A
                    wrote on last edited by
                    #9

                    @raven-worx

                    Thanks for the Update

                    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