How to update QAbstractItemModel view when a Data is updated
-
I use the
Qt example for QAbstractItemModel
and I try to update anItem
to a givenindex
.I tried to use
emit DataChanged
but 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 ! -
Hi,
Just a quick thought, try adding the role parameter to your dataChanged call and put the type role in it.
-
- remove
void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight);
from model.h - in
AnimalModel::rowCount
replaceQ_UNUSED(parent);
withif(parent.isValid()) return 0;
- in
AnimalModel::data
addif(!index.isValid()) return QVariant(); Q_ASSERT(index.model()==this);
before anything else AnimalModel::test
should be:
m_animals[0].setType("Lion"); const QModelIndex idx = index(0); emit dataChanged(idx ,idx );
createIndex
should only be called inside theindex
method- for efficiency you might want to store the role names as a private member
const QHash<int, QByteArray> roles = {std::pair<int,QByteArray>(TypeRole,"type"),std::pair<int,QByteArray>(SizeRole,"size")};
andAnimalModel::roleNames
becomes justQHash<int, QByteArray> AnimalModel::roleNames() const {return roles;}
For cases like this one, implementing a custom model is more a waste of time than anything else,
QStandardItemModel
could have done the trick effortlessly
@SGaist said in How to update QAbstractItemModel view when a Data is updated:
try adding the role parameter to your dataChanged call and put the type role in it.
Unfortunately that parameter has been forgotten in the darkness. even built in Qt models do not use it
- remove