View Full Version : QSqlTableModel::SetData on different column
silmaril
30th January 2014, 20:43
I have a QSqlTableModel that works well and all the slots are firing, but I need to update a different column when an check box is clicked.
The code I have right now is below and I just can't get the model to update a different column in the index
#include <QtSql>
#include <QTextCharFormat>
#include <QtDebug>
#include <QCheckBox>
#include "includes/selectionsetmodel.h"
selectionsetSqlModel::selectionsetSqlModel(QObject *parent) : QSqlTableModel(parent)
{
}
//! [0]
QVariant selectionsetSqlModel::data(const QModelIndex &index, int role) const
{
QVariant value = QSqlQueryModel::data(index, role);
int col = index.column();
switch(role){
case Qt::DisplayRole:
if (col == 6)
{
if (value.toInt()<1024)
{
return QString(QString::number(value.toInt()) + "B");
}
else
{
return QString(QString::number(value.toInt()/1024) + "KB");
}
}
else
{
return QString(value.toString());
}
case Qt::FontRole:
// QFont boldFont;
// boldFont.setBold(true);
// return boldFont;
case Qt::BackgroundRole:
case Qt::TextAlignmentRole:
if (col == 5 or col == 6)
{
return Qt::AlignRight + Qt::AlignVCenter;
}
if (col == 2)
{
return Qt::AlignVCenter;
}
case Qt::CheckStateRole:
int selected = index.model()->data(index.model()->index(index.row(), 1), Qt::DisplayRole).toInt();
if (col == 2 )
{
if(selected==1)
{
return Qt::Checked;
}
else
{
return Qt::Unchecked;
}
}
}
return QVariant();
}
Qt::ItemFlags selectionsetSqlModel::flags ( const QModelIndex & index ) const
{
if (index.column() == 2)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable ;
else
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
bool selectionsetSqlModel::setData(const QModelIndex& index,const QVariant& value,int role)
{
bool v;
if(role == Qt::CheckStateRole && index.column() == 2)
{
bool selected = index.model()->data(index.model()->index(index.row(), 1), Qt::DisplayRole).toBool();
v = selected ? false : true;
}
//QModelIndex idx = QModelIndex(index.row(), 1, index);
//bool r = this->setData(idx,v,role);
QModelIndex top = createIndex(index.row(), 0);
QModelIndex bottom = createIndex(index.row(), 3);
emit dataChanged(top, bottom); // emit layoutChanged() if headers changed
//qDebug() << "Now Checkable Column: " << r << " = " << v;
return true;
}
ChrisW67
31st January 2014, 00:15
Nothing in your code tries to set the value of any column. As it stands I cannot see how you could update anything at all in the table as you never call the base implementation.
I think you want column 1 of the model to hold the state of the checkbox displayed against column 2.
You want something like this (untested code):
QVariant selectionsetSqlModel::data(const QModelIndex &index, int role) const
{
...
case Qt::CheckStateRole:
if (index.column() == 2) {
const QModelIndex sibling = index.sibling(index.row(), 1);
return sibling.data(Qt::EditRole);
}
...
}
bool selectionsetSqlModel::setData(const QModelIndex& index,const QVariant& value,int role)
{
if (role == Qt::CheckStateRole && index.column() == 2) {
const QModelIndex sibling = index.sibling(index.row(), 1);
bool ret = setData(sibling, value, Qt::EditRole);
if (ret) emit dataChanged(index, index);
return ret;
}
else
return QSqlTableModel::setData(index, value, role);
}
silmaril
31st January 2014, 00:24
Thank you for the reply.
I tried the code but it still does not update the view:
bool selectionsetSqlModel::setData(const QModelIndex& index,const QVariant& value,int role)
{
{
if (role == Qt::CheckStateRole && index.column() == 2) {
bool selected = index.model()->data(index.model()->index(index.row(), 1), Qt::DisplayRole).toBool();
QVariant v = selected ? false : true;
qDebug() << v;
const QModelIndex sibling = index.sibling(index.row(), 1);
QModelIndex top = createIndex(index.row(), 0);
QModelIndex bottom = createIndex(index.row(), 3);
emit dataChanged(top, bottom); // emit layoutChanged() if headers changed
return setData(sibling, v, Qt::EditRole);
}
else
return QSqlTableModel::setData(index, value, role);
}
silmaril
31st January 2014, 04:55
Ok, looking at your code I've tried multiple options but it seems to has the same outcome.
I first tried the code you provided as is and the following code:
bool selectionsetSqlModel::setData(const QModelIndex& index,const QVariant& value,int role)
{
{
if (role == Qt::CheckStateRole && index.column() == 2) {
const QModelIndex sibling = index.sibling(index.row(), 1);
bool ret = setData(sibling, value, Qt::EditRole);
if (ret) emit dataChanged(index, index);
qDebug() << "Success: "<<ret << " = " << value;
return ret;
}
else
return QSqlTableModel::setData(index, value, role);
}
When the checkbox is checked, the value it tries to set the value to is:
QVariant(int, 0) "Success: false = QVariant(int, 0) "
When the checkbox is unchecked, the value it tried to set the value to is
QVariant(int, 2) "Success: false = QVariant(int, 2)"
In both instances the setData returns a "false".
If I change the code to the following:
bool selectionsetSqlModel::setData(const QModelIndex& index,const QVariant& value,int role)
{
{
if (role == Qt::CheckStateRole && index.column() == 2) {
//bool selected = index.model()->data(index.model()->index(index.row(), 1), Qt::DisplayRole).toBool();
const QModelIndex sibling = index.sibling(index.row(), 1);
QVariant v;
v = value.toInt() == Qt::Checked ? true : false;
bool ret = setData(sibling, v, Qt::EditRole);
if (ret) emit dataChanged(index, index);
qDebug() << "Success: "<<ret << " = " << value;
return ret;
}
else
return QSqlTableModel::setData(index, value, role);
}
The set values changes to bool with true and false, but it still fails:
Success: false = QVariant(bool, false)
Success: false = QVariant(bool, true)
Any suggestions around why setData refuses to set the SQL record?
ChrisW67
31st January 2014, 07:05
What data type is the column underlying column 1?
A complete example:
#include <QtGui>
#include <QtSql>
#include <QDebug>
class MyModel: public QSqlTableModel {
Q_OBJECT
public:
explicit MyModel(QObject *p = 0): QSqlTableModel(p) {
}
Qt::ItemFlags flags ( const QModelIndex & index ) const {
if (index.column() == 2)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable ;
else
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant data(const QModelIndex &index, int role) const {
if (role == Qt::CheckStateRole && index.column() == 2) {
const QModelIndex sibling = index.sibling(index.row(), 1);
return sibling.data(Qt::EditRole);
}
else
return QSqlTableModel::data(index, role);
}
bool setData(const QModelIndex& index,const QVariant& value,int role) {
if (role == Qt::CheckStateRole && index.column() == 2) {
const QModelIndex sibling = index.sibling(index.row(), 1);
bool ret = setData(sibling, value, Qt::EditRole);
if (ret) emit dataChanged(index, index);
qDebug() << "Success:"<< ret << "Value:" << value;
return ret;
}
else
return QSqlTableModel::setData(index, value, role);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
db.open();
QSqlQuery query;
query.exec("create table test ( col0 int, col1 int, col2 text )");
query.exec("insert into test values(101, 2, 'Row 0')");
query.exec("insert into test values(102, 2, 'Row 1')");
query.exec("insert into test values(103, 0, 'Row 2')");
query.exec("insert into test values(104, 0, 'Row 3')");
query.exec("insert into test values(105, 2, 'Row 4')");
MyModel model;
model.setTable("test");
model.select();
QTableView view;
view.setModel(&model);
view.show();
return app.exec();
}
#include "main.moc"
I am choosing to store that actual Qt::CheckState value, but you could convert to/from Y/N character or 0/1 integer etc.
silmaril
31st January 2014, 16:31
Thanks again for the reply...
I took your code and it seems to be doing the same as my code. It renders the checkbox, but it does not allow you to change the checkbox:
#include <QtGui>
#include <QtSql>
#include <QDebug>
#include <QTableView>
#include <QApplication>
class MyModel: public QSqlTableModel {
Q_OBJECT
public:
explicit MyModel(QObject *p = 0): QSqlTableModel(p) {
}
Qt::ItemFlags flags ( const QModelIndex & index ) const {
if (index.column() == 2)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable ;
else
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant data(const QModelIndex &index, int role) const {
if (role == Qt::CheckStateRole && index.column() == 2) {
const QModelIndex sibling = index.sibling(index.row(), 1);
return sibling.data(Qt::EditRole);
}
else
return QSqlTableModel::data(index, role);
}
bool setData(const QModelIndex& index,const QVariant& value,int role) {
if (role == Qt::CheckStateRole && index.column() == 2) {
const QModelIndex sibling = index.sibling(index.row(), 1);
bool ret = setData(sibling, value, Qt::EditRole);
if (ret) emit dataChanged(index, index);
qDebug() << "Success:"<< ret << "Value:" << value;
return ret;
}
else
return QSqlTableModel::setData(index, value, role);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
db.open();
QSqlQuery query;
query.exec("create table test ( col0 int, col1 int, col2 text )");
query.exec("insert into test values(101, 2, 'Row 0')");
query.exec("insert into test values(102, 2, 'Row 1')");
query.exec("insert into test values(103, 0, 'Row 2')");
query.exec("insert into test values(104, 0, 'Row 3')");
query.exec("insert into test values(105, 2, 'Row 4')");
MyModel model;
model.setTable("test");
model.select();
QTableView view;
view.setModel(&model);
view.show();
return app.exec();
}
#include "main.moc"
Debugging output is:
Success: false Value: QVariant(int, 2)
Success: false Value: QVariant(int, 2)
Success: false Value: QVariant(int, 2)
Success: false Value: QVariant(int, 2)
Success: false Value: QVariant(int, 0)
Success: false Value: QVariant(int, 0)
Success: false Value: QVariant(int, 0)
Success: false Value: QVariant(int, 0)
Success: false Value: QVariant(int, 0)
Success: false Value: QVariant(int, 0)
Success: false Value: QVariant(int, 0)
silmaril
31st January 2014, 21:19
Seems after many hours one will eventually figure stuff out. It seems the "Qt::DisplayRole" slot was causing me the problems.
I changed:
case Qt::DisplayRole:
if (col == 6)
{
if (value.toInt()<1024)
{
return QString(QString::number(value.toInt()) + "B");
}
else
{
return QString(QString::number(value.toInt()/1024) + "KB");
}
}
return value;
to
case Qt::DisplayRole:
if (col == 6)
{
if (value.toInt()<1024)
{
return QString(QString::number(value.toInt()) + "B");
}
else
{
return QString(QString::number(value.toInt()/1024) + "KB");
}
}
return QSqlTableModel::data(index, Qt::DisplayRole).toString();
ChrisW67
31st January 2014, 22:24
I took your code and it seems to be doing the same as my code. It renders the checkbox, but it does not allow you to change the checkbox:
My code was built and tested as working on Qt 4.8.5. I just built it with 5.2 to get the same result as you: Qt5 interprets the flags slightly differently and will not let the code update a column that is not editable. This version of flags() works with both Qt versions:
Qt::ItemFlags flags ( const QModelIndex & index ) const {
Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
if (index.column() == 2)
f |= Qt::ItemIsUserCheckable;
return f;
}
Seems after many hours one will eventually figure stuff out. It seems the "Qt::DisplayRole" slot was causing me the problems.
AFAICT this has nothing to do with the column containing the checkbox state, the one displaying the checkbox, or the topic of the thread.
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.