How to update QAbstractItemModel view when a Data is updated

18,308

Don't redefine signals in subclasses.

Remove the following lines (in model.h) and it should work as expected :

signals:
    void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight);

Also this when calling dataChanged() you have to specify a valid QModelIndex. This is correct :

  // I also tried:
  QModelIndex topLeft = createIndex(0,0);
  emit dataChanged(topLeft, topLeft);
Share:
18,308
Ed Nio
Author by

Ed Nio

Updated on June 25, 2022

Comments

  • Ed Nio
    Ed Nio about 2 years

    I use the Qt example for QAbstractItemModel and I try to update an Item to a given index.

    I tried to use emit DataChangedbut it doesn't work, the view is not updated.

    Here is an example:

    What I want: When you click on the button, it will update Data at index 0, the type of the animal will be changed, it will become a Lion.

    #include <QAbstractListModel>
    #include <QStringList>
    #include <qqmlcontext.h>
    //![0]
    class Animal
    {
    public:
        Animal(const QString &type, const QString &size);
    //![0]
    
        QString type() const;
        QString size() const;
    
        void setType(QString q) {
            m_type = q;
        }
    
    private:
        QString m_type;
        QString m_size;
    //![1]
    };
    
    class AnimalModel : public QAbstractListModel
    {
        Q_OBJECT
    public:
    
        Q_INVOKABLE void test() ;
        void setName(const QString &name);
        enum AnimalRoles {
            TypeRole = Qt::UserRole + 1,
            SizeRole
        };
    
        AnimalModel(QObject *parent = 0);
    //![1]
    //!
    //!
        void setContext(QQmlContext *ctx) {
            m_ctx = ctx;
        }
    
        void addAnimal(const Animal &animal);
    
        int rowCount(const QModelIndex & parent = QModelIndex()) const;
    
        QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
        QHash<int, QByteArray> roleNames() const;
    
    protected:
    
    private:
        QList<Animal> m_animals;
        QQmlContext*  m_ctx;
    
    signals:
        void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight);
    //![2]
    };
    //![2]
    

    model.h

    #include "model.h"
    #include "qDebug"
    Animal::Animal(const QString &type, const QString &size)
        : m_type(type), m_size(size)
    {
    }
    
    QString Animal::type() const
    {
        return m_type;
    }
    
    QString Animal::size() const
    {
        return m_size;
    }
    
    
    
    
    AnimalModel::AnimalModel(QObject *parent)
        : QAbstractListModel(parent)
    {
    }
    
    void AnimalModel::addAnimal(const Animal &animal)
    {
        beginInsertRows(QModelIndex(), rowCount(), rowCount());
        m_animals << animal;
        endInsertRows();
    }
    
    void AnimalModel::test() {
    
      m_animals[0].setType("Lion");
      emit dataChanged(QModelIndex(),QModelIndex());
    
      //I also tried:
      QModelIndex topLeft = createIndex(0,0);
      emit dataChanged(topLeft, topLeft);
    
    
     }
    
    int AnimalModel::rowCount(const QModelIndex & parent) const {
        Q_UNUSED(parent);
        return m_animals.count();
    }
    
    QVariant AnimalModel::data(const QModelIndex & index, int role) const {
        if (index.row() < 0 || index.row() >= m_animals.count())
            return QVariant();
    
        const Animal &animal = m_animals[index.row()];
        if (role == TypeRole)
            return animal.type();
        else if (role == SizeRole)
            return animal.size();
        return QVariant();
    }
    
    //![0]
    QHash<int, QByteArray> AnimalModel::roleNames() const {
        QHash<int, QByteArray> roles;
        roles[TypeRole] = "type";
        roles[SizeRole] = "size";
        return roles;
    }
    //![0]
    

    model.cpp

    #include "model.h"
    
    #include <QGuiApplication>
    #include <qqmlengine.h>
    #include <qqmlcontext.h>
    #include <qqml.h>
    #include <QtQuick/qquickitem.h>
    #include <QtQuick/qquickview.h>
    
    //![0]
    int main(int argc, char ** argv)
    {
        QGuiApplication app(argc, argv);
    
        AnimalModel model;
        model.addAnimal(Animal("Wolf", "Medium"));
        model.addAnimal(Animal("Polar bear", "Large"));
        model.addAnimal(Animal("Quoll", "Small"));
    
        QQuickView view;
        view.setResizeMode(QQuickView::SizeRootObjectToView);
        QQmlContext *ctxt = view.rootContext();
        ctxt->setContextProperty("myModel", &model);
    //![0]
    
        view.setSource(QUrl("qrc:view.qml"));
    
    
        view.show();
    
        return app.exec();
    }
    

    main.cpp

    import QtQuick 2.0
    import QtQuick 2.4
    import QtQuick.Controls 1.3
    import QtQuick.Window 2.2
    import QtQuick.Dialogs 1.2
    import QtQuick.Layouts 1.2
    import QtQml.Models 2.1
    import QtQuick.Controls.Styles 1.2
    
    
    //![0]
    ListView {
        width: 200; height: 250
    
        model: myModel
        delegate: Text { text: "Animal: " + type + ", " + size }
    
        MouseArea {
            anchors.fill: parent
            cursorShape: Qt.PointingHandCursor
            onClicked: {
    
            }
        }
        Button {
            anchors.bottom: parent.bottom
            width:50; height:50
            text:"click"
            onClicked: {
                myModel.test()
            }
    
        }
    
    }
    //![0]
    

    View.qml

    Do you have any idea why it doesn't work ? Thanks a lot !

  • derM
    derM about 7 years
    Or emit QAbstractListModel::dataChanged(index(0), index(0));
  • Andrew
    Andrew about 3 years
    beginResetModel(); endResetModel(); can help you