Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Unable to update Listview using QAbstractItemModel class



  • 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 }
    }
    

    }


  • Moderators

    @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.



  • @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


  • Moderators

    @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)
    }
    


  • @raven-worx

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


  • Moderators

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



  • @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


  • Moderators

    @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.



  • @raven-worx

    Thanks for the Update


Log in to reply