4

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:

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 .

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?

Community
  • 1
  • 1
murison
  • 3,640
  • 2
  • 23
  • 36

0 Answers0