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
{
Q_OBJECT
public:
.....
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
Regards,
Farrukh Arshad. -
I think that your QAbstractListModel subclass should emit "dataChanged":http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#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 methoddelete this->data; // As mentioned in question data is DataEngine object.
this->data = NULL;// DataEngine destructor
DataEngine::~DataEngine()
{
// Remove all rows from the data model so that
// the model view knows the data is changed
removeAllRows();
}
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.
endRemoveRows();
return true;
}
@Regards,
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() {
clear();
}void DataEngine::clear()
{
removeAllRows();
}@I am not sure about this, but I have already made something similar, you can see the source "here":https://code.google.com/p/downloadmanager-qml/source/browse/src/listmodel.cpp#303.
Hope this helps.Regards
-
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":http://doc.qt.nokia.com/4.7-snapshot/qabstractlistmodel.htmlAn 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:
@
beginResetModel();
m_data.clear();
endResetModel();
@otherwise the view is not notified of the change in the datamodel