I wanted to have a checkbox in one of the columns in my Table view. To be specific - in one of the rows, because the view is using a transposing proxy model. I did it using a QItemDelegate derivate class, as described in the doc, and here:
.h
class checkBoxDelegate : public QItemDelegate
{
Q_OBJECT
public:
checkBoxDelegate(QAbstractItemView* parentView = NULL, QObject *parent = NULL);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
//QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
~checkBoxDelegate();
private:
QAbstractItemView* parentView;
};
.cpp
checkBoxDelegate::checkBoxDelegate(QAbstractItemView* parentView, QObject *parent)
: QItemDelegate(parent), parentView(parentView)
{
}
checkBoxDelegate::~checkBoxDelegate()
{
}
QWidget *checkBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QCheckBox *editor = new QCheckBox(parent);
editor->setTristate(false);
return editor;
}
void checkBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
bool value = index.model()->data(index, Qt::EditRole).toBool();
QCheckBox *locEdit = static_cast<QCheckBox*>(editor);
locEdit->setChecked(value);
}
void checkBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
QCheckBox *locEdit = static_cast<QCheckBox*>(editor);
bool value = locEdit->isChecked();
model->setData(index, value, Qt::EditRole);
}
void checkBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
editor->setGeometry(option.rect);
}
void checkBoxDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const {
QPalette::ColorGroup cg;
if (option.state & QStyle::State_Enabled) {
cg = (option.state & QStyle::State_Active) ? QPalette::Normal : QPalette::Inactive;
}
else
cg = QPalette::Disabled;
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.color(cg, QPalette::Highlight));
//if (! (parentView->editTriggers() > QAbstractItemView::NoEditTriggers && option.state & QStyle::State_Selected) )
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
drawFocus(painter, option, option.rect);
}
//QSize checkBoxDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const {
// return QItemDelegate::sizeHint ( option, index );
//}
The delegete is bound to a row in my view
checkBoxDelegate* cBD = new checkBoxDelegate(ui.personalData);
ui.personalData->setItemDelegateForRow(4, cBD);
It "kind of" works, the check box appears - centered:
But when I edit that cell, the control returned by createEditor(...) is drawn next to original checkbox:
,
I achieved what I wanted by adding this line:
if (! (parentView->editTriggers() > QAbstractItemView::NoEditTriggers && option.state & QStyle::State_Selected) ) //this one
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
in the paint(...) method .
I ended up with something like that:
if (! (option.state & QStyle::State_Selected) || option.state & QStyle::State_HasFocus)
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
May seem strange, but I could't make it better. It appears, that Qt behaves kind of strange in this piece of code. When the table cell is selected (not in edit mode), it has option.state = State( "Active | Enabled | HasFocus | Selected" )
. And when in edit mode, it has State( "Enabled | Selected" )
. Why no longer "Active" ? Why no longer HasFocus ? Ok, focus is probably passed to the QCheckBox. I expected, to have QStyle::State_Editing state - but it didn't
I'm still not sure if this is the best way to do it?