jeudi 15 janvier 2015

qt - clickable checkbox for boolean column in QTableView

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 file 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 file



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:


checkBox in normal mode


But when I edit that cell, the control returned by createEditor(...) is drawn next to original checkbox:


check box in edit mode (before change) , check box in edit mode (after change)


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 . But I'm not sure if this is the best way to do it?





Aucun commentaire:

Enregistrer un commentaire