[qT] Remove items from model and list


Removing items from views can be somewhat troublesome. Not because it is hard, but because the idea behind it is part of more wide subject, with is MVC (Model View Controller). It nutshell Model is something like database, that store all the information that can be later displayed by Views. View is visual representation of model, it can be i.e. ListView, TableView, or ListWidgetView and so on. Nothing stops You from creating you custom view with, for example, progress bar on some table. General idea behind view is that developer don’t concerns self with many “database” or some custom storage space, but reuse same information, changing only the way they are presented to users. Controller it a mechanism, as name suggest, to control displayed views and items.

Of course this is brief explanation and only introduction to the subject, more information are in qt documentation.

The problem that some one can stumble upon is a way of removing selected items (by items I mean almost anything, from images,  text,  to progress bars and so one) from views. Depending on the implementation sometimes items are removed on wrong order or simply skipped. Below is a code example how to handle that situation.

Example scenario:
0. Application use

1. On parent widget are placed two views, ListView and TableView. They are  suppose to display some information, in my case thumbnails of images.
2. User can select items and delete them. (Main problem is that rows shifts inside model and removing i.e. rows 1,2 not necessarily remove them)
3. In this example I keep track of file paths in QStringList. I also want to delete appropriate entries from that list.

ListView and TableView looks something like this:

ListView

ListView

TableView

TableView

So deletion of the items can be done using QPersistentModelIndex, that guarantee valid reference to the rows, like this:

QModelIndexList selIndeModel;
QList<QPersistentModelIndex> selPersistIndeModel;

//check  visibility of particular view and load select
//index accordingly
if( listView->isVisible()){
   selIndeModel.append(  smodelList->selectedIndexes() );
}else{
   selIndeModel =  smodelTable->selectedRows();
}

//populate persistant  indexes
 for( int i = 0; i < selIndeModel.count(); ++i)
 selPersistIndeModel.append( selIndeModel.at(i) );

//remove item  from model correctly
//remove of the item in QStringList fails or remove invalid rows
for( int i =  selPersistIndeModel.size()-1; i >= 0; --i )
{
   model.removeRow( selPersistIndeModel[i].row() );
   fileNames.removeAt( selIndeModel[i].row() );

   //fileNames.removeAt(  selPersistIndeModel[i].row() );

}

Solution above is good only for model, QStringList deletes invalid indexes or none if used with commented code. So what alternative there is for this? Using QList<int> and sorting indexes accordingly, then removing them in descending order is way to go, like this:

QModelIndexList selIndeModel;

//load selection indexes from tavle/list views
if( listView->isVisible()){
   selIndeModel = smodelList->selectedIndexes();
}else{
   selIndeModel = smodelTable->selectedRows();
}

QList<int> lint;
//populate lint
for( int i = 0; i < selIndeModel.count(); ++i)
   lint.append( selIndeModel[i].row() );

//sort lint list
qSort( lint.begin(), lint.end() );
//remove items in descending order, so records don't shifts
for( int i = lint.size()-1; i >= 0; --i )
{
   model.removeRow( lint[i] );
   fileNames.removeAt( lint[i] );
}
//clear selection, not really necessary, for precaution reason
smodelList->clearSelection();
smodelTable->clearSelection();

At this point when user wants to remove selected items, they are removed not only from the model itself but also from QStringList. Of course this is simple demonstration and depending on actual implementation You would want to choose solution best fitting Your needs.

, , , ,

Comments are closed.