PDA

View Full Version : QSqlDataWidgetMapper + QSqlTableModel +Sqlite = No Changes Written



ChrisW67
3rd May 2009, 04:47
G'day,

This could be a newbie mistake or a bug. Either way, I have been banging my head against this for a while. Help me work out which.

I have a small test program that creates an Sqlite database on disk, puts some values in a table, and creates a simple form to edit these using QSqlDataWidgetMapper. The form navigation of the records works. I can edit a record, move away then back and the value has stayed on the model. Pressing Save on an edited row executes submit() on the mapper and prints the return (true) and lastError().text() (empty). AFAICT this should have written the changes to disk. However, If I change a record or two, Save, then exit and look at the content of the database it has not changed. What am I missing?

Fails for me on Qt 4.5.1 Open source on Linux (Gentoo) or Qt 4.5.1 + MingW on Win XP using the all-in-one SDK download. Operative part of the code below, and whole program attached.

Regards,
Chris W


#include "window.h"

Window::Window(QWidget *parent)
: QWidget(parent)
{
setupModel();

nameEdit = new QLineEdit();
nextButton = new QPushButton(tr("&Next"));
previousButton = new QPushButton(tr("&Previous"));
saveButton = new QPushButton(tr("&Save"));

mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
mapper->addMapping(nameEdit, model->fieldIndex("name"));

connect(saveButton, SIGNAL(clicked()), this, SLOT(submitMe()));
connect(previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious()));
connect(nextButton, SIGNAL(clicked()), mapper, SLOT(toNext()));
connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(updateButtons(int)));

QGridLayout *layout = new QGridLayout();
layout->addWidget(nameEdit, 0, 0, 1, 1);
layout->addWidget(previousButton, 0, 1, 1, 1);
layout->addWidget(nextButton, 1, 1, 1, 1);
layout->addWidget(saveButton, 2, 1, 1, 1);
setLayout(layout);

setWindowTitle(tr("SQL Widget Mapper"));
mapper->toFirst();
}

void Window::setupModel()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("test.db");
if (!db.open()) {
QMessageBox::critical(0, tr("Cannot open database"),
tr("Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information how "
"to build it."), QMessageBox::Cancel);
return;
}

QSqlQuery query;
query.exec("create table superhero (id int primary key, name varchar(20))");
query.exec("insert into superhero values(1, 'Superman')");
query.exec("insert into superhero values(2, 'Batman')");
query.exec("insert into superhero values(3, 'Spiderman')");
query.exec("insert into superhero values(4, 'Green Lantern')");
query.exec("insert into superhero values(5, 'Phantom')");

model = new QSqlTableModel(this);
model->setTable("superhero");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();
}

void Window::updateButtons(int row)
{
previousButton->setEnabled(row > 0);
nextButton->setEnabled(row < model->rowCount() - 1);
}

void Window::submitMe()
{
bool ok = mapper->submit();
qDebug() << "Window::submitMe()" << ok << model->lastError().text();
}

ChrisW67
3rd May 2009, 10:23
Newbie mistake. :o

The underlying model is in EditStrategy::OnManualSubmit mode and the only way to commit to disc is the QSqlTableModel::submitAll() method. The mapper's submit() method only calls the model's submit() method, which does not commit to disc for models in manual mode. For my application I think EditStrategy::OnFieldChange will get me what I need although explicitly calling submitAll() would also work.