Important: Please read the Qt Code of Conduct -

How to change QML GridView model at run time

  • Greetings,

    I have a QAbstractListModel based class defined in QT and in QML I have set this model to a GridView. It works perfect. If I change data in the model I call the reset function and GridView shows the updated data. But at time I change the complete model data (i.e Not just the data changes but also its count changes). In this case when I reset the data the GridView does not show the updated model. I have also tried to create a new object of my model and changed the GridView model but still no effect.

    Here are the basic code snippet.

    @// DataEngine.h
    class DataEngine : public QAbstractListModel
    public: // Overrides
    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    // main.c
    DataEngine *data = new DataEngine();
    view.rootContext()->setContextProperty("DataModel", data)

    // QML File
    GridView {
    id: view
    model: DataModel

    // After completely changing data (i.e earlier it has 256 rows, now it has say 0 row)
    // I tried
    view.rootContext()->setContextProperty("NewDataModel", data)
    // QML Code
    view.model = NewDataModel // No effect.

    It seems to me the data is changing but GridView is not updating with the new data.

    Any help is appreciated

    Farrukh Arshad.

  • I think that your QAbstractListModel subclass should emit "dataChanged": signal whenever you modify the model

  • Thanks marco. dataChanged only works when you data values are changed. But if your data count is increased or decreased your view should invoke rowCount where you can return the changed count of data. For this the model subclass has to provide the implementation of removeRows / insertRows. With these functions the view knows the data count is changed when you call beginRemoveRows / endRemoveRows & beginInsertRows / endInsertRows and view will call your rowCount function where you can provide updated count and view fetches new data again. Expanding the code mentioned in the question.

    // When changing the data, following two lines are being called on a
    // button press from the QML.
    // Invokable method

    delete this->data; // As mentioned in question data is DataEngine object.
    this->data = NULL;

    // DataEngine destructor
    // Remove all rows from the data model so that
    // the model view knows the data is changed
    void DataEngine::removeAllRows()
    removeRows(0, this->getBufferSize(), this->index(0,0));
    bool DataEngine::removeRows(int row, int count, const QModelIndex &parent)
    beginRemoveRows(QModelIndex(), row, (row+count));
    // You can delete your actual data here as well, I was deleting it in the
    // destructor of DataEngine.
    return true;

    Farrukh Arshad.

  • Yes, you right about dataChanged. Looking at something similar I made, I found that I used also the clear() function. In qml ListView, for example you use clear() to empty the list, so I think you should implement it and also call it in the QAbstractListModel subclass destructor, something like:

    @DataEngine::~DataEngine() {

    void DataEngine::clear()

    I am not sure about this, but I have already made something similar, you can see the source "here":
    Hope this helps.


  • If your model can remove or insert data than you must explicitly call the beginInsertRow endInsertRow between the code that alter the model data.
    Taken from the QAbstractListModel "doc":

    An insertRows() implementation must call beginInsertRows() before inserting new rows into the data structure, and it must call endInsertRows() immediately afterwards.
    A removeRows() implementation must call beginRemoveRows() before the rows are removed from the data structure, and it must call endRemoveRows() immediately afterwards.

    In the worst case you can use the beginResetModel and endResetModel
    like this:

    otherwise the view is not notified of the change in the datamodel

Log in to reply