I am using QTableView\'s checkbox flag of Qt::ItemIsUserCheckable to display a checkbox in a table cell.
After reading some things on alignment in an attempt to
This is the solution I came up with. This is assuming that you want the checkbox to be the only thing in the cell.
class CenteredCheckboxDelegate final : public QStyledItemDelegate
{
public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter * painter, const QStyleOptionViewItem & o, const QModelIndex & index ) const override
{
auto option2 = o;
initStyleOption(&option2, index);
auto * widget = option2.widget;
auto * style = widget ? widget->style() : QApplication::style();
// Turn off all features and just draw the background
option2.state.setFlag(QStyle::State_HasFocus, false);
option2.features.setFlag(QStyleOptionViewItem::HasDisplay, false);
option2.features.setFlag(QStyleOptionViewItem::HasDecoration, false);
option2.features.setFlag(QStyleOptionViewItem::HasCheckIndicator, false);
style->drawControl(QStyle::CE_ItemViewItem, &option2, painter, widget);
// Then just draw the a checkbox centred in the cell
option2.rect = getCheckboxRect(option2);
auto stateFlag = option2.checkState == Qt::Checked ? QStyle::State_On : QStyle::State_Off;
option2.state.setFlag(stateFlag, true);
style->drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &option2, painter, widget);
}
bool editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index) override
{
auto flags = index.flags();
if (!flags.testFlag(Qt::ItemIsUserCheckable) || !flags.testFlag(Qt::ItemIsEnabled))
{
return false;
}
if(event->type() == QEvent::MouseButtonRelease)
{
auto * mouseEvent = static_cast(event);
bool mouseOverCheckbox = getCheckboxRect(option).contains(mouseEvent->pos());
if(!mouseOverCheckbox) return false;
}
else if(event->type() == QEvent::KeyPress)
{
auto * keyEvent = static_cast(event);
if(keyEvent->key() != Qt::Key_Space) return false;
}
else
{
return false;
}
auto checkState = index.data(Qt::CheckStateRole).value();
auto toggledCheckState = checkState == Qt::Checked ? Qt::Unchecked : Qt::Checked;
return model->setData(index, toggledCheckState, Qt::CheckStateRole);
}
private:
QRect getCheckboxRect(const QStyleOptionViewItem & option) const
{
auto * widget = option.widget;
auto * style = widget ? widget->style() : QApplication::style();
auto checkboxSize = style->subElementRect(QStyle::SE_CheckBoxIndicator, &option, widget).size();
return QStyle::alignedRect(option.direction, Qt::AlignCenter, checkboxSize, option.rect);
}
};