PDA

View Full Version : Prevent QTableview from changing row



Pit
11th September 2012, 11:15
Hi guys!

I have a QTableview with a model that displays data in a form. When user changes data and changes the row, I display a message asking if he wants to leave the record without saving it, set the current index to the previous one and return. Like this:




connect(cardsTableView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) , this, SLOT(changingCard(QModelIndex, QModelIndex)));

void MainWindow::changingCard(const QModelIndex &current, const QModelIndex &previous)
{
if (cardChanged)
{
if (QMessageBox::question(this, qApp->applicationName(), "Do you want to leave without saving?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
{
cardChanged = false;
cardsTableView->setCurrentIndex(previous);
cardChanged = true;
return;
}
}
}
}



Problem is that it doesn't work. The form doesn't change but the row does. It appears that the mouse click it's executed after the setCurrentIndex(previous), so it changes anyway.

Ideas?

Thanks!

pkj
11th September 2012, 14:05
Clicking on QTableView/QAbstractItemView cell causes it's delegate to be opened up. After having edited the data, while the foucus is going out, QItemDelegate::setData() function is called and data is set in the model you have written. To read more about it, consult Model/View framework documentation.
From what you have written, it appears, that you carry a notion that merely changing selection model indexes is going to reset the data. No, it is not. It is only the model which sets data and calls dataChanged() signal which causes attached models, views to refresh themselves.

Pit
12th September 2012, 10:49
No, no, I don't think that changing selection model indexes is going to reset the data. I can't edit directly on the QTableView. Like I said I have a form with a mapper attached to that model. So when I change the row on the QTableView the form doesn't change unless I'll want it. The real changing function is this (I removed the other code in the other post to make it simple):




void MainWindow::changingCard(const QModelIndex &current, const QModelIndex &previous)
{
if (cardChanged)
{
if (QMessageBox::question(this, qApp->applicationName(), "Do you want to leave without saving?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
{
cardChanged = false;
cardsTableView->setCurrentIndex(previous);
cardChanged = true;
return;
}
}

if (current.row() != -1)
{
mapper->setCurrentModelIndex(current);
setSexRadio();
setStudentRadio();
setPickRadio();
cardChanged = false;
dniWarning = false;
}
}



So like this, when the row changes I change the mapper index and the data on the form, but If the user doesn't want to quit without saving, I put the row back in place and nothing changes. But like I said, it doesn't work and the row changes anyway (but not the data on the form).

d_stranz
13th September 2012, 01:59
I think the problem is that you are directly editing the model from the form (via the mapper), and once the user changes any item on the form it is committed to the model and the old value is lost. So, you need to re-implement your form to use a transaction-based model where the entire content of the form is submitted to the model at one time, rather than item-by-item. In that case, nothing happens to the model until the user takes some action to commit the changes he has made (clicking an Update or Commit button, or closing the form by clicking OK, for example). In the slot that handles that, you update all the fields in the model row at one time. In your cardChanged() slot, if the user says he wants to keep the changes, you call the update routine; if he wants to discard them, then you do nothing and reset the form fields to the new row contents.

Alternatively, each time a new row is loaded into the form, you can make a backup copy of the original contents. You can still do item-by-item model updates, but if the user says he wants to discard the changes, then you simply replace the row (in the model) with the copy you have saved in the backup.

You could also look into re-implementing QAbstractItemModel::submit() and QAbstractItemModel::revert() for your model to handle this, but there is very little in the docs on how or when these slots are used.

Pit
13th September 2012, 09:10
I'm using the mapper just to display the data, not to save it, because I need to change some values before inserting in the database. So I'm saving manually when the user clicks "Save" button. But I can't save if the user wants to keep the data before leaving the row, because some fields are required, some of them has validators, so I have a function that checks all data, and if it fails it displays another message with the error and doesn't save data.

So if I save on leaving the row and the check function fails, a message is displayed with the error but the problem stil the same, the row changes to another one.