PDA

View Full Version : multiple QDataWidgetMapper's tied to one model causes index to be reset



darkadept
31st March 2008, 18:07
I'm struggling with getting two QDataWidgetMapper's that are tied to a single model to work properly.

This is the code I have:


MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
setupUi(this);

//Create the model
_myModel = new QSqlTableModel(this);
_myModel->setTable("mytable");
_myModel->setEditStrategy(QSqlTableModel::OnRowChange);
_myModel->select();

//Create the first mapper
_myFirstMapper = new QDataWidgetMapper(this);
_myFirstMapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
_myFirstMapper->setModel(_myModel);
_myFirstMapper->addMapping(myFirstEdit, 0);
connect(_myFirstMapper->itemDelegate(), SIGNAL(commitData(QWidget*)),
this, SLOT(saveMyFirstData()));

//Create the second mapper
_mySecondMapper = new QDataWidgetMapper(this);
_mySecondMapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
_mySecondMapper->setModel(_myModel);
_mySecondMapper->addMapping(mySecondEdit, 0);
connect(_mySecondMapper->itemDelegate(), SIGNAL(commitData(QWidget*)),
this, SLOT(saveMySecondData()));

//Jump to the same row for each mapper
_myFirstMapper->toFirst();
_mySecondMapper->toFirst();
}

void saveMyFirstData() {
int current = _myFirstMapper->currentIndex();
_myFirstMapper->submit();
_myFirstMapper->setCurrentIndex(current);
}

void saveMySecondData() {
int current = _mySecondMapper->currentIndex();
_mySecondMapper->submit();
_mySecondMapper->setCurrentIndex(current);
}


Now, I connect the itemDelegate's signal to those slots because it was the only way I could use the QDataWidgetMapper with the ManualSubmit policy. The AutoSubmit policy did not work at all no matter what I tried.

What happens is when I change the value in "myFirstEdit" the second mapper gets it's currentIndex reset to -1. The reason is because the call to _myFirstMapper->submit() actually calls myModel->submit() which has the effect of resetting all QDataWidgetMappers attached to that model to -1. Why, I don't know.

Now the obvious correction to my code above is to have only one save slot like this:


void saveMyData() {
int currentFirst = _myFirstMapper->currentIndex();
int currentSecond = _mySecondMapper->currentIndex();
_myFirstMapper->submit();
_mySecondMapper->submit();
_myFirstMapper->setCurrentIndex(currentFirst);
_mySecondMapper->setCurrentIndex(currentSecond);
}


Now here's my problem, what happens if the two different QDataWidgetMapper's are on separate forms that have no idea about each other, but they still use the same model. If I save data on the second form the first form's mapper's index gets set to -1.

Is this a bug in Qt or am I misunderstanding how to use QDataWidgetMapper?

And yes, I'd love for the AutoSubmit policy to work but it just plain doesn't work. At least not for me and the other people that had the same problem and suggested doing that signal slot connection.

Thanks, Mike

wysota
31st March 2008, 18:26
Is this a bug in Qt or am I misunderstanding how to use QDataWidgetMapper?
No, it's a feature of the SQL model. When you submit changes to the SQL model, it gets reset and all views (including all data mappers) along with it. It's just the way it is - the model has to refresh itself completely. You mustn't use OnRowChange edit strategy, because that will trigger a submit upon every change. Use OnManualSubmit and submit the data manually once just before the model dies.

darkadept
31st March 2008, 19:55
Ok. That makes sense.

Now you say "just before the model dies". I'm wondering, what is a good lifetime for a model to "live"? Are models meant to be short lived or long? The QSqlTableModel's I'm using are loaded at first use and then kept alive until the program quits. Is that bad practice?

For long lived models I can pass the row (or index) around as long as I don't store it (I'd use persistant indexes for that). That seems very efficient to me. For short lived models I'd have to pass an Id value and use a filter to select my data each time. Is that just as good?

I'd also run into sync problems if I have two QSqlTableModels that select the same data being used in different parts of the program. Or am I wrong?

wysota
31st March 2008, 21:23
Is that bad practice?

It's fine. You may even subclass the model and reimplement its destructor to submit the data.


I'd also run into sync problems if I have two QSqlTableModels that select the same data being used in different parts of the program. Or am I wrong?
Use the same model.