PDA

View Full Version : QSqlRelationalTableModel -> Updating model's data



toma
8th July 2014, 00:17
Hi everybody.

I'm trying to re-implement the setData() function of the QSqlRelationalTableModel class but, as you already guessed it, I'm unsuccessful...
Already developed an app which uses delegates, overloads functions flags(), data(), rowCount(), columCount()... but as I can't figure out what I'm doing wrong in the setData() function, I made another app with the less code as I could in an attempt to debug it and to share it with you.
So... here it is (the buggy part is in databasemodel.cpp):


main.cpp :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.setWindowState(Qt::WindowMaximized);

w.show();

return a.exec();
}


mainwindow.cpp :
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
myTableView = new QTableView(this);
setCentralWidget(myTableView);

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("../mydb.db");
db.open();

modelConducteurs = new DataBaseModel(this, db);
modelConducteurs->setTable("conducteurs");
modelConducteurs->select();
myTableView->setModel(modelConducteurs);
}

MainWindow::~MainWindow()
{
delete myTableView;
delete modelConducteurs;
}


databasemodel.h :
class DataBaseModel : public QSqlRelationalTableModel
{
Q_OBJECT
public:
DataBaseModel(QObject * parent = 0, QSqlDatabase db = QSqlDatabase());
bool setData(const QModelIndex &item, const QVariant &value, int role = Qt::EditRole);
private:
};


databasemodel.cpp :
EditDataBaseModel::EditDataBaseModel(QObject *parent, QSqlDatabase db)
: QSqlRelationalTableModel(parent, db)
{
}

bool EditDataBaseModel::setData(const QModelIndex &item, const QVariant &value, int role)
{
this->query().seek(item.row());
switch (role) {
case Qt::EditRole:
qDebug() << value;
this->query().record().setValue(item.column(), value);
qDebug() << this->query().lastError();
qDebug() << this->query().record().value(item.column());
emit dataChanged(item, item);
return true;
break;
default:
break;
}
return false;
}


The problem is the following : the setValue() function seems to be ineffective :
- The value of value is correct (displayed thanks to qDebug).
- qDebug() << this->query().lastError(); returns QSqlError(-1, "", "") (no error).
- qDebug() << this->query().record().value(item.column()); gives me the unchanged content of the record. As if I had never used setValue() two lines before.


Did I misunderstood the way I'm supposed to update the model data ?
Is there another function than setValue that I should be using (using setRecord in setData only leads me to a crashing app) ?


Thanks in advance for you answers.

See you.



Thomas.

anda_skoa
8th July 2014, 08:34
query() returns a copy of the QSqlQuery object used by the model. Modifying the copy does not affect the original. The same applies to QSqlQuery::record()

Since QSqlRelationalTableModel already has an implementation for setData(), I would suggest that you do whatever you want to do different and then call the base class implementation.

Cheers,
_

toma
8th July 2014, 20:33
Hi,

first of all, thanks a lot for your answer.

You said :
query() returns a copy of the QSqlQuery object used by the model. Modifying the copy does not affect the original. The same applies to QSqlQuery::record()
Thanks for this, it makes some thinks clearer for me (should have better reed the doc : The QSqlQueryModel class provides a read-only data model for SQL result sets).
But there is no doubt that there is still something I haven't understood.
If I want to change the way the data is displayed I need to re-implement the data() function.
Based on this doc (http://qt-project.org/doc/qt-4.8/model-view-programming.html#making-the-model-editable), all I'm able to "create" is that :

QVariant EditDataBaseModel::data(const QModelIndex &item, int role) const
{
if (!item.isValid())
return QVariant();
this->query().last();
if (item.row() >= this->query().at())
return QVariant();

if (role == Qt::DisplayRole || role == Qt::EditRole)
{
this->query().seek(item.row());
return this->query().record().value(item.column());
}
else
return QVariant();
}
The problem is that the view isn't updated if the user changes a value (in this project, I'm using the model's default functions for everything except for data()). View isn't updated but model is. If I exit my app and launch it again, I'm then able to view the change I previously made and which have been saved in the DB.
I probably am totally wrong in the way I want to reach my model's data but I can't figure out how to do it differently.
I'm using MVCs for the very first time (like a virgin...). I successfully implemented a view, a model and some delegates. Now I want to re-implement some model's functions because I'd like to personalize the way the data is displayed (using the flags, the data and the paint functions). Am I, at least, right on this point ?

toma
8th July 2014, 23:09
Working code :

QVariant MyClassName::data(const QModelIndex &item, int role) const
{
if (!item.isValid())
return QVariant();
this->query().last();
if (item.row() >= this->query().at())
return QVariant();

if (role == Qt::DisplayRole)
return this->record(item.row()).value(item.column());
else
return QSqlRelationalTableModel::data(item, role);
}

anda_skoa
9th July 2014, 09:37
Thanks for this, it makes some thinks clearer for me (should have better reed the doc : The QSqlQueryModel class provides a read-only data model for SQL result sets).

Yes, but you are using a QSqlRelationalTableModel, which is a QSqlTableModel, which is a read/write model.
See QSqlTableMode::setEditStrategy().



If I want to change the way the data is displayed I need to re-implement the data() function.

Right. Or using a proxy model.

Cheers,
_

toma
9th July 2014, 22:25
Hi. Once again, thanks for your answer. I'll continue to work on my project.


See you later.