PDA

View Full Version : Deleting selected row from a QTableView



Ferric
13th January 2010, 22:41
Hi,

I have successfully made a table where I can add two columns of user specified data, one row at a time. (Please see attachment)

What I am trying to do now is allow the user to delete a row in case they want to change things,

I currently have it so that the same row is deleted every time the "Remove Channel" button is clicked by using the following code


void Loader::removeChannelFromTable()
{
model->removeRows ( 1, 1);
row = row - 1;
}


What I would like to do now is let the user select a row (so its highlighted), and then if the "Remove Channel" button is clicked the selected row will removed.


I have made the following connection so that when my table (channelsView) is clicked, a signal gets emitted



QObject::connect(channelsView, SIGNAL(clicked(QModelIndex)),
this, SLOT(clicked(QModelIndex)));



from here I find I'm not sure what to do next, (or if I am on the right track even?)

wysota
13th January 2010, 23:03
That's wrong. You are interested not in reacting on clicking a row but on clicking the button. Only then you want to access selected rows (and remember you can select rows without clicking on them too). So do exactly this. There is QItemSelectionModel object associated with every QAbstractItemView, you can ask it for items currently selected.

Ferric
14th January 2010, 00:00
Okay, I know what you mean by only needing to react when the user clicks "remove channel" button.

I have tried to write the following code



void Loader::removeChannelFromTable()
{
QMessageBox::information(this,tr(""),tr("Slot working?") ); // to make sure slot is being run.
QItemSelectionModel *selected = new QItemSelectionModel(model); // selects my QStandardItemModel()
selected->clearSelection(); // clears the selected index
}


But this simply does nothing, it compiles and runs, but when I select a row and click remove, nothing happens (apart from the message box).



Also I don't really know how to do this:
(and remember you can select rows without clicking on them too)

ChrisW67
14th January 2010, 03:48
Line 4 creates a new selection model rather than fetching the model that is already associated with the view. Line 5 does not do what you think it does: it deselects everything, it does not delete selected data. You want something like this (I haven't tested it so please forgive minor glitches):
void Loader::removeChannelFromTable()
{
QMessageBox::information(this,tr(""),tr("Slot working?") ); // to make sure slot is being run.

// code to get list of selected rows
QItemSelectionModel *selected = channelsView->selectionModel();
QModelIndexList rowList = selected->selectedRows();

// code to delete these model indexes from the model
foreach(QModelIndex rowIndex, rowList) {
model->removeRow(roxIndex.row(), rowIndex.parent());
}
}
You might also consider using QAbstractItemView::setSelectionBehavior() and QAbstractItemView::setSelectionMode() on the view so the user selects whole rows etc.

Ferric
14th January 2010, 04:40
You might also consider using QAbstractItemView::setSelectionBehavior() and QAbstractItemView::setSelectionMode() on the view so the user selects whole rows etc.

Thanks, yeah I will try and set it up so that if the user clicks anywhere in a row, the entire row is selected.

The basic function of the remove button is working now, Thanks for the example.

wysota
14th January 2010, 05:26
// code to delete these model indexes from the model
foreach(QModelIndex rowIndex, rowList) {
model->removeRow(roxIndex.row(), rowIndex.parent());
}

This has a chance of not-working. It would probably be better to remove the rows from the end to the beginning to retain validity of model indexes or to call removeRows() if the selection forms a range without gaps.

ChrisW67
14th January 2010, 09:38
Good point Wysota

feverzsj
14th January 2010, 15:45
This has a chance of not-working. It would probably be better to remove the rows from the end to the beginning to retain validity of model indexes or to call removeRows() if the selection forms a range without gaps.

yes, it's inconvenient to remove selected rows. You have to sort them by the row index and then remove them, while in QListWidget, you only need to delete the QListWidgetItem.

Ferric
14th January 2010, 22:58
This has a chance of not-working.
Yes, I have noticed some glitches as it is currently set up:



void Loader::removeChannelFromTable()

{

// code to get list of selected rows
QItemSelectionModel *selected = channelsView->selectionModel();
QModelIndexList rowList = selected->selectedRows();
//qDebug() << rowList;

//code to delete these model indexes from the model
foreach(QModelIndex rowIndex, rowList) {
//qDebug() << rowIndex.row();
model->removeRow(rowIndex.row(), rowIndex.parent());
row = row - 1; // so that I know where the next channel should be added, i.e at the first empty row.
}
}



It would probably be better to remove the rows from the end to the beginning to retain validity of model indexes

From using QDebug, I can see when I select multiple rows they are removed from beginning to the end, what is the easiest was to reverse this? ( all I can propose is putting the rows into a list, then reversing the list, then removing the rows, but this is probably not the most efficient way).

Thanks

numbat
15th January 2010, 08:32
You already have a list. Just use a for loop and go backwards through the list.


for (int i = rowList.count(); i >= 0; i--)
{
qDebug() << rowList.at(i).row();
}