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

Unable to update Listview using QAbstractItemModel class

Scheduled Pinned Locked Moved Solved QML and Qt Quick
9 Posts 2 Posters 584 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