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 center the checkbox within the cell, I am returning the Qt::AlignCenter as the TextAlignmentRole from the models data() function.
QVariant ExampleModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
return QVariant();
if (role == Qt::TextAlignmentRole)
return Qt::AlignCenter | Qt::AlignVCenter;
}
This however is not aligning my checkbox.
Does anyone know how to align checkboxes is this mode?
Solution for Python (PySide, PyQt) to center the checkbox and with editable allowed:
class BooleanDelegate(QItemDelegate):
def __init__(self, *args, **kwargs):
super(BooleanDelegate, self).__init__(*args, **kwargs)
def paint(self, painter, option, index):
# Depends on how the data function of your table model is implemented
# 'value' should recive a bool indicate if the checked value.
value = index.data(Qt.CheckStateRole)
self.drawCheck(painter, option, option.rect, value)
self.drawFocus(painter, option, option.rect)
def editorEvent(self, event, model, option, index):
if event.type() == QEvent.MouseButtonRelease:
value = bool(model.data(index, Qt.CheckStateRole))
model.setData(index, not value)
event.accept()
return super(BooleanDelegate, self).editorEvent(event, model, option, index)
In your table model, make sure that the flags allow the user to check/uncheck the cell.
class MyTableModel(QAbstractTableModel):
...
def flags(self, index):
if not index.isValid():
return Qt.ItemIsEnabled
if index.column() in self.columns_boolean:
return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable
return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
Finally, set the BooleanDelagate
in your table
self.boolean_delegate = BooleanDelegate()
self.input_gui.setItemDelegateForColumn(5, self.boolean_delegate)
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<QMouseEvent*>(event);
bool mouseOverCheckbox = getCheckboxRect(option).contains(mouseEvent->pos());
if(!mouseOverCheckbox) return false;
}
else if(event->type() == QEvent::KeyPress)
{
auto * keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() != Qt::Key_Space) return false;
}
else
{
return false;
}
auto checkState = index.data(Qt::CheckStateRole).value<Qt::CheckState>();
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);
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With