PDA

View Full Version : Need help with checkbox in tableview



vieraci
18th June 2009, 15:11
I'm trying to get my table to display a QCheckBox for a column that is boolean (actually int) from a QSqlQueryModel.

I've implemented a delegate so when the field is clicked a check box appears and this works fine, but I can't work out what code to implement to get the column to display a check box instead of a 0 or 1.

I've read in another post:


You can reimplement QAbstractItemModel::flags() to return Qt::ItemIsUserCheckable together with other flags for the checkable column. But notice that you must also handle Qt::CheckStateRole in data() and setData().

With this in mind, I reimplemented flags() which seems to work


Qt::ItemFlags PurchaseOrdersRequests::flags(
const QModelIndex &index) const
{
Qt::ItemFlags flags = QSqlQueryModel::flags(index);
flags |= Qt::ItemIsEditable;
if (index.column() == 6)
{
flags |= Qt::ItemIsUserCheckable;
}
return flags;
}


...but data() is totally wrong.


QVariant PurchaseOrdersRequests::data ( const QModelIndex & index, int role ) const
{
if (!index.isValid())
return QVariant();

// if (role == Qt::ItemIsUserCheckable) // NEVER happens !
// qDebug() << " ItemIsUserCheckable";

if (role == Qt::DisplayRole)
{
QSqlRecord rec = record(index.row());
QString val = rec.value(index.column()).toString();
return val; // ALWAYS returns an empty string :-(
}
else
return QVariant();
}


Problems are:
1) record() is returning empty values.
2) ItemIsUserCheckable returns false, I thought flags() would be called here where I set it (?)
3) I don't know what to do with CheckStateRole so there's nothing in my code to return a checkbox for display.

shentian
18th June 2009, 20:00
The role you need to use in QAbstractItemModel::data is Qt::CheckStateRole. I think the method should look like this:


QVariant PurchaseOrdersRequests::data ( const QModelIndex & index, int role ) const
{
if (!index.isValid())
{
return QVariant();
}
QSqlRecord rec = record(index.row());
QVariant val = rec.value(index.column());

switch (role)
{
case Qt::CheckStateRole:
if (index.column() != 6)
return QVariant();
else if (val.toInt() == 0) // or whatever
return Qt::Unchecked;
else
return Qt::Checked;
case Qt::DisplayRole:
return val;
default:
return QVariant();
}
}


Depending on the type stored in val, QVariant::toString() may well return an empty string. Use QVariant::typeName() to check what type it is. I think it's best to just pass on the QVariant value.

No guarantees, I did not check the code above, but I hope it gives you an idea.

vieraci
19th June 2009, 01:54
Thanks, case Qt::CheckStateRole is what I was missing.

Now the program crashes at
QSqlRecord rec = this->record(index.row());
It appears to continually recurse the function.

If I change the line to:
QSqlRecord rec = this->record();
it doesn't crash, but I get no data. typeName() is blank (one space).

This function is re-entering like over 100 times and I only have 9 columns and one row of data. that's strange ?

vieraci
19th June 2009, 08:08
It turns out the required code is:

QVariant value = QSqlQueryModel::data(index, role);
Now data() seems to be called once for DisplayRole and again for CheckStateRole.
What I end up with is a unchecked checkbox and in the same column, 0 or 1.


switch (role)
{
case Qt::CheckStateRole:
if (index.column() != 6)
return value;
else if (value.toInt() == 0) // or whatever
return Qt::Unchecked;
else
return Qt::Checked;
case Qt::DisplayRole:
return value;
default:
return QVariant();
}

vieraci
19th June 2009, 18:19
Can anyone help me out here ? This is acting strange.

When role is Qt::CheckStateRole the data returned from the model seems to be empty, in contrast to when role is DisplayRole, data is valid.

Still, I don't know why the column shows a checkbox (ALWAYS not checked because of what I just stated) and 0 or 1 next to it in the same column which seems to be getting into the column during role == DisplayRole.

This is the whole code:

QVariant PurchaseOrdersRequests::data ( const QModelIndex & index, int role ) const
{
if (!index.isValid())
return QVariant();
QVariant value = QSqlQueryModel::data(index, role);

if (role == Qt::CheckStateRole && index.column() == 6)
return (value.toInt() != 0) ? Qt::Checked : Qt::Unchecked;
else if (role == Qt::DisplayRole)
return value;
return QVariant();
}

This code I'm sure is correct, if not, can someone correct me or suggest what else could be the problem ?

vieraci
21st June 2009, 14:13
OK I worked out what was happening.
data() was returning a checkbox AND a value. To stop it, I had to modify it:


QVariant PurchaseOrdersRequests::data ( const QModelIndex & index, int role ) const
{
QVariant value = QStandardItemModel::data(index, role);
if (index.column() == 6)
{
if (role == Qt::CheckStateRole)
return (QStandardItemModel::data(index).toInt() != 0) ? Qt::Checked : Qt::Unchecked;
else if (role == Qt::DisplayRole)
return QVariant(); // Don't show value !!
}
return value;
}