Center a QCheckBox or Decoration in an Itemview: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(Initial version)
 
mNo edit summary
 
(One intermediate revision by the same user not shown)
Line 5: Line 5:


== Overview ==
== Overview ==
Currently Qt does not support centering a QCheckBox or the itemview decoration out-of-the box. There are two possibilities to achieve this behavior. If no user interaction is needed (e.g. the checkbox is should not be user-checkable) the easiest solution is to provide a custom item delegate derived from [https://doc.qt.io/qt-5/qstyleditemdelegate.html QStyledItemDelegate]. If you need user interaction a custom [https://doc.qt.io/qt-5/qproxystyle.html QProxyStyle] is needed.
Currently Qt does not support centering a QCheckBox or the itemview decoration out-of-the box. There are two possibilities to achieve this behaviour: a custom item delegate derived from [https://doc.qt.io/qt-5/qstyleditemdelegate.html QStyledItemDelegate] or a custom [https://doc.qt.io/qt-5/qproxystyle.html QProxyStyle].


== Derive from QStyledItemDelegate ==
== Derive from QStyledItemDelegate ==
When deriving from QStyledItemDelegate no user-interaction is needed since the hittest area for the checkbox can not be modified with an item delegate.
The proposed solution works when the checkbox or decoration should be aligned. As alignment indicator the Qt::TextAlignmentRole is 'misused' since no text is drawn for the cell.
The proposed solution works when the checkbox or decoration should be aligned. As alignment indicator the Qt::TextAlignmentRole is 'misused' since no text is drawn for the cell.


  <nowiki>
  <nowiki>
class MyStyle : public QStyledItemDelegate
class MyDelegate : public QStyledItemDelegate
{
{
public:
public:
  using QStyledItemDelegate::QStyledItemDelegate;
    using QStyledItemDelegate::QStyledItemDelegate;
 
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
  void paint(QPainter *painter,
    {
            const QStyleOptionViewItem &option, const QModelIndex &index) const override
        QStyleOptionViewItem opt = option;
  {
        const QWidget *widget = option.widget;
    QStyleOptionViewItem opt = option;
        initStyleOption(&opt, index);
    const QWidget *widget = option.widget;
        QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
    initStyleOption(&opt, index);
        style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, widget);
 
        if (opt.features & QStyleOptionViewItem::HasCheckIndicator) {
    QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
            switch (opt.checkState) {
    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, widget);
            case Qt::Unchecked:
    if (opt.features & QStyleOptionViewItem::HasCheckIndicator) {
                opt.state |= QStyle::State_Off;
      switch (opt.checkState) {
                break;
      case Qt::Unchecked:
            case Qt::PartiallyChecked:
        opt.state |= QStyle::State_Off;
                opt.state |= QStyle::State_NoChange;
        break;
                break;
      case Qt::PartiallyChecked:
            case Qt::Checked:
        opt.state |= QStyle::State_NoChange;
                opt.state |= QStyle::State_On;
        break;
                break;
      case Qt::Checked:
            }
        opt.state |= QStyle::State_On;
            auto rect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, widget);
        break;
            opt.rect = QStyle::alignedRect(opt.direction, index.data(Qt::TextAlignmentRole).value<Qt::Alignment>(), rect.size(), opt.rect);
      }
            opt.state = opt.state & ~QStyle::State_HasFocus;
      auto rect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, widget);
            style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &opt, painter, widget);
      opt.rect = QStyle::alignedRect(opt.direction, Qt::AlignVCenter | Qt::AlignHCenter, rect.size(), opt.rect);
        } else if (!opt.icon.isNull()) {
      opt.state = opt.state & ~QStyle::State_HasFocus;
            // draw the icon
 
            QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, widget);
      style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &opt, painter, widget);
            iconRect = QStyle::alignedRect(opt.direction, index.data(Qt::TextAlignmentRole).value<Qt::Alignment>(), iconRect.size(), opt.rect);
    } else if (!opt.icon.isNull()) {
            QIcon::Mode mode = QIcon::Normal;
      // draw the icon
            if (!(opt.state & QStyle::State_Enabled))
      QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, widget);
                mode = QIcon::Disabled;
      iconRect = QStyle::alignedRect(opt.direction, Qt::AlignVCenter | Qt::AlignHCenter, iconRect.size(), opt.rect);
            else if (opt.state & QStyle::State_Selected)
      QIcon::Mode mode = QIcon::Normal;
                mode = QIcon::Selected;
      if (!(opt.state & QStyle::State_Enabled))
            QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
        mode = QIcon::Disabled;
            opt.icon.paint(painter, iconRect, opt.decorationAlignment, mode, state);
      else if (opt.state & QStyle::State_Selected)
        } else {
        mode = QIcon::Selected;
            QStyledItemDelegate::paint(painter, option, index);
      QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
        }
      opt.icon.paint(painter, iconRect, opt.decorationAlignment, mode, state);
    }
    } else {
protected:
      QStyledItemDelegate::paint(painter, option, index);
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
    {
        Q_ASSERT(event);
        Q_ASSERT(model);
        // make sure that the item is checkable
        Qt::ItemFlags flags = model->flags(index);
        if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled) || !(flags & Qt::ItemIsEnabled))
            return false;
        // make sure that we have a check state
        QVariant value = index.data(Qt::CheckStateRole);
        if (!value.isValid())
            return false;
        const QWidget *widget = option.widget;
        QStyle *style = option.widget ? widget->style() : QApplication::style();
        // make sure that we have the right event type
        if ((event->type() == QEvent::MouseButtonRelease) || (event->type() == QEvent::MouseButtonDblClick) || (event->type() == QEvent::MouseButtonPress)) {
            QStyleOptionViewItem viewOpt(option);
            initStyleOption(&viewOpt, index);
            QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, widget);
            checkRect = QStyle::alignedRect(viewOpt.direction, index.data(Qt::TextAlignmentRole).value<Qt::Alignment>(), checkRect.size(), viewOpt.rect);
            QMouseEvent *me = static_cast<QMouseEvent *>(event);
            if (me->button() != Qt::LeftButton || !checkRect.contains(me->pos()))
                return false;
            if ((event->type() == QEvent::MouseButtonPress) || (event->type() == QEvent::MouseButtonDblClick))
                return true;
        } else if (event->type() == QEvent::KeyPress) {
            if (static_cast<QKeyEvent *>(event)->key() != Qt::Key_Space && static_cast<QKeyEvent *>(event)->key() != Qt::Key_Select)
                return false;
        } else {
            return false;
        }
        Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
        if (flags & Qt::ItemIsUserTristate)
            state = ((Qt::CheckState)((state + 1) % 3));
        else
            state = (state == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
        return model->setData(index, state, Qt::CheckStateRole);
     }
     }
  }
};
};
</nowiki>
</nowiki>


The delegate can be added directly to the desired view:
The delegate can be added directly to the desired view:
  <nowiki>
  <nowiki>
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{
{
  QApplication a(argc, argv);
    QApplication a(argc, argv);
 
    QStandardItemModel model;
    model.setColumnCount(1);
    model.setRowCount(2);


  QStandardItemModel model;
    QPixmap pix(20, 20);
  model.setColumnCount(1);
    pix.fill(Qt::blue);
  model.setRowCount(2);


  auto checkableItem = new QStandardItem;
    auto checkableItem = new QStandardItem;
  checkableItem->setCheckState(Qt::Checked);
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
  checkableItem->setTextAlignment(Qt::AlignHCenter);
    checkableItem->setTextAlignment(Qt::AlignCenter);
  model.setItem(0, 0, checkableItem);
    checkableItem->setCheckState(Qt::Checked);
    model.setItem(0, 0, checkableItem);


  checkableItem = new QStandardItem;
    checkableItem = new QStandardItem;
  checkableItem->setIcon(QPixmap("qticon64.png"));
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
  checkableItem->setTextAlignment(Qt::AlignHCenter);
    checkableItem->setTextAlignment(Qt::AlignCenter);
  model.setItem(1, 0, checkableItem);
    checkableItem->setIcon(pix);
    model.setItem(1, 0, checkableItem);


  QTableView tv;
    QTableView tv;
  tv.setModel(&model);
    tv.setModel(&model);
  tv.setItemDelegate(new MyStyle);
    tv.setItemDelegate(new MyDelegate);
  // tv.setItemDelegateForColumn(0, new MyStyle); // when only a single column should use the style
    // tv.setItemDelegateForColumn(0, new MyDelegate); // when only a single column should use the delegate
  tv.show();
    tv.show();
  return a.exec();
    return a.exec();
}
}
</nowiki>
</nowiki>


== Use a custom style derived from QProxyStyle ==
== Use a custom style derived from QProxyStyle ==
If you need user interaction for your QCheckBox you need to create a custom QProxyStyle so the hittest for the checkbox is done correct.
Another alternative is to create a custom QProxyStyle.
The alignment of the QCheckBox is provided through a custom role (CheckAlignmentRole) in this case to not get in conflict with the text alignment and to have an indicator which cell should have the special checkbox handling.
The alignment of the checkbox and decoration are handled by custom roles (CheckAlignmentRole, DecorationAlignmentRole) in this case to not get in conflict with the text alignment and to have an indicator which cell should have the special checkbox handling.
The style does not work for the decoration but it should be easy to implement it (replace SE_ItemViewItemCheckIndicator with SE_ItemViewItemDecoration and paint the return the decoration rect instead)
  <nowiki>
  <nowiki>
enum {
enum {  
  CheckAlignmentRole = Qt::UserRole + Qt::CheckStateRole + Qt::TextAlignmentRole
    CheckAlignmentRole = Qt::UserRole + Qt::CheckStateRole + Qt::TextAlignmentRole,
    DecorationAlignmentRole = Qt::UserRole + Qt::DecorationRole + Qt::TextAlignmentRole  
};
};


class CenteredBoxProxyStyle : public QProxyStyle {
class CenteredBoxProxyStyle : public QProxyStyle
{
public:
public:
  using QProxyStyle::QProxyStyle;
    using QProxyStyle::QProxyStyle;
  QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const override {
    QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const override
    const QRect baseRes = QProxyStyle::subElementRect(element, option, widget);
    {
    if (element == SE_ItemViewItemCheckIndicator) {
        const QRect baseRes = QProxyStyle::subElementRect(element, option, widget);
      const QStyleOptionViewItem* const itemOpt = qstyleoption_cast<const QStyleOptionViewItem*>(option);
        switch (element) {
      const QVariant alignData = itemOpt ? itemOpt->index.data(CheckAlignmentRole) : QVariant();
        case SE_ItemViewItemCheckIndicator: {
      if (alignData.isNull())
            const QStyleOptionViewItem *const itemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
            const QVariant alignData = itemOpt ? itemOpt->index.data(CheckAlignmentRole) : QVariant();
            if (!alignData.isNull())
                return QStyle::alignedRect(itemOpt->direction, alignData.value<Qt::Alignment>(), baseRes.size(), itemOpt->rect);
            break;
        }
        case SE_ItemViewItemDecoration: {
            const QStyleOptionViewItem *const itemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
            const QVariant alignData = itemOpt ? itemOpt->index.data(DecorationAlignmentRole) : QVariant();
            if (!alignData.isNull())
                return QStyle::alignedRect(itemOpt->direction, alignData.value<Qt::Alignment>(), baseRes.size(), itemOpt->rect);
            break;
        }
        case SE_ItemViewItemFocusRect: {
            const QStyleOptionViewItem *const itemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
            const QVariant checkAlignData = itemOpt ? itemOpt->index.data(CheckAlignmentRole) : QVariant();
            const QVariant decorationAlignData = itemOpt ? itemOpt->index.data(DecorationAlignmentRole) : QVariant();
            if (!checkAlignData.isNull() || !decorationAlignData.isNull()) // when it is not null, then the focus rect should be drawn over the complete cell
                return option->rect;
            break;
        }
        default:
            break;
        }
         return baseRes;
         return baseRes;
      const QRect itemRect = option->rect;
      Q_ASSERT(itemRect.width() > baseRes.width() && itemRect.height() > baseRes.height());
      const int alignFlag = alignData.toInt();
      int x = 0;
      if (alignFlag & Qt::AlignLeft)
        x = baseRes.x();
      else if (alignFlag & Qt::AlignRight)
        x = itemRect.x() + itemRect.width() - (baseRes.x() - itemRect.x())- baseRes.width();
      else if (alignFlag & Qt::AlignHCenter)
        x = itemRect.x() + (itemRect.width() / 2) - (baseRes.width() / 2);
      return QRect(QPoint(x, baseRes.y()), baseRes.size());
    } else if (element == SE_ItemViewItemFocusRect) {
      const QStyleOptionViewItem* const itemOpt = qstyleoption_cast<const QStyleOptionViewItem*>(option);
      const QVariant alignData = itemOpt ? itemOpt->index.data(CheckAlignmentRole) : QVariant();
      if (!alignData.isNull()) // when it is no null, then it's a checkbox cell and the focus rect should be drawn over the complete cell
        return option->rect;
     }
     }
    return baseRes;
  }
};
};
</nowiki>
</nowiki>


The proxy style can either set for the complete application or directly for the desired view:
The proxy style can either set for the complete application or directly for the desired view:
Line 136: Line 181:
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{
{
  QApplication a(argc, argv);
    QApplication a(argc, argv);
  // a.setStyle(new CenteredBoxProxyStyle); // when it should be set for the complete application
    CenteredBoxProxyStyle style;
    // a.setStyle(&style); // when it should be set for the complete application
 
    QStandardItemModel model;
    model.setColumnCount(1);
    model.setRowCount(2);
 
    QPixmap pix(20, 20);
    pix.fill(Qt::blue);


  QStandardItemModel model;
    auto checkableItem = new QStandardItem;
  model.setColumnCount(1);
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
  model.setRowCount(2);
    checkableItem->setCheckState(Qt::Checked);
    checkableItem->setData(Qt::AlignCenter, CheckAlignmentRole);
    model.setItem(0, 0, checkableItem);


  auto checkableItem = new QStandardItem;
    checkableItem = new QStandardItem;
  checkableItem->setCheckState(Qt::Checked);
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
  checkableItem->setData(Qt::AlignHCenter, CheckAlignmentRole);
    checkableItem->setData(Qt::AlignCenter, DecorationAlignmentRole);
  model.setItem(0, 0, checkableItem);
    checkableItem->setIcon(pix);
    model.setItem(1, 0, checkableItem);


  QTableView tv;
    QTableView tv;
  tv.setModel(&model);
    tv.setModel(&model);
  tv.setStyle(new CenteredBoxProxyStyle);
    tv.setStyle(&style);
  tv.show();
    tv.show();
  return a.exec();
    return a.exec();
}
}
</nowiki>
</nowiki>

Latest revision as of 14:59, 10 November 2021

En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh

Overview

Currently Qt does not support centering a QCheckBox or the itemview decoration out-of-the box. There are two possibilities to achieve this behaviour: a custom item delegate derived from QStyledItemDelegate or a custom QProxyStyle.

Derive from QStyledItemDelegate

The proposed solution works when the checkbox or decoration should be aligned. As alignment indicator the Qt::TextAlignmentRole is 'misused' since no text is drawn for the cell.

class MyDelegate : public QStyledItemDelegate
{
public:
    using QStyledItemDelegate::QStyledItemDelegate;
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        QStyleOptionViewItem opt = option;
        const QWidget *widget = option.widget;
        initStyleOption(&opt, index);
        QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
        style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, widget);
        if (opt.features & QStyleOptionViewItem::HasCheckIndicator) {
            switch (opt.checkState) {
            case Qt::Unchecked:
                opt.state |= QStyle::State_Off;
                break;
            case Qt::PartiallyChecked:
                opt.state |= QStyle::State_NoChange;
                break;
            case Qt::Checked:
                opt.state |= QStyle::State_On;
                break;
            }
            auto rect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, widget);
            opt.rect = QStyle::alignedRect(opt.direction, index.data(Qt::TextAlignmentRole).value<Qt::Alignment>(), rect.size(), opt.rect);
            opt.state = opt.state & ~QStyle::State_HasFocus;
            style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &opt, painter, widget);
        } else if (!opt.icon.isNull()) {
            // draw the icon
            QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, widget);
            iconRect = QStyle::alignedRect(opt.direction, index.data(Qt::TextAlignmentRole).value<Qt::Alignment>(), iconRect.size(), opt.rect);
            QIcon::Mode mode = QIcon::Normal;
            if (!(opt.state & QStyle::State_Enabled))
                mode = QIcon::Disabled;
            else if (opt.state & QStyle::State_Selected)
                mode = QIcon::Selected;
            QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
            opt.icon.paint(painter, iconRect, opt.decorationAlignment, mode, state);
        } else {
            QStyledItemDelegate::paint(painter, option, index);
        }
    }
protected:
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
    {
        Q_ASSERT(event);
        Q_ASSERT(model);
        // make sure that the item is checkable
        Qt::ItemFlags flags = model->flags(index);
        if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled) || !(flags & Qt::ItemIsEnabled))
            return false;
        // make sure that we have a check state
        QVariant value = index.data(Qt::CheckStateRole);
        if (!value.isValid())
            return false;
        const QWidget *widget = option.widget;
        QStyle *style = option.widget ? widget->style() : QApplication::style();
        // make sure that we have the right event type
        if ((event->type() == QEvent::MouseButtonRelease) || (event->type() == QEvent::MouseButtonDblClick) || (event->type() == QEvent::MouseButtonPress)) {
            QStyleOptionViewItem viewOpt(option);
            initStyleOption(&viewOpt, index);
            QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, widget);
            checkRect = QStyle::alignedRect(viewOpt.direction, index.data(Qt::TextAlignmentRole).value<Qt::Alignment>(), checkRect.size(), viewOpt.rect);
            QMouseEvent *me = static_cast<QMouseEvent *>(event);
            if (me->button() != Qt::LeftButton || !checkRect.contains(me->pos()))
                return false;
            if ((event->type() == QEvent::MouseButtonPress) || (event->type() == QEvent::MouseButtonDblClick))
                return true;
        } else if (event->type() == QEvent::KeyPress) {
            if (static_cast<QKeyEvent *>(event)->key() != Qt::Key_Space && static_cast<QKeyEvent *>(event)->key() != Qt::Key_Select)
                return false;
        } else {
            return false;
        }
        Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
        if (flags & Qt::ItemIsUserTristate)
            state = ((Qt::CheckState)((state + 1) % 3));
        else
            state = (state == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
        return model->setData(index, state, Qt::CheckStateRole);
    }
};
 

The delegate can be added directly to the desired view:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QStandardItemModel model;
    model.setColumnCount(1);
    model.setRowCount(2);

    QPixmap pix(20, 20);
    pix.fill(Qt::blue);

    auto checkableItem = new QStandardItem;
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
    checkableItem->setTextAlignment(Qt::AlignCenter);
    checkableItem->setCheckState(Qt::Checked);
    model.setItem(0, 0, checkableItem);

    checkableItem = new QStandardItem;
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
    checkableItem->setTextAlignment(Qt::AlignCenter);
    checkableItem->setIcon(pix);
    model.setItem(1, 0, checkableItem);

    QTableView tv;
    tv.setModel(&model);
    tv.setItemDelegate(new MyDelegate);
    // tv.setItemDelegateForColumn(0, new MyDelegate); // when only a single column should use the delegate
    tv.show();
    return a.exec();
}
 

Use a custom style derived from QProxyStyle

Another alternative is to create a custom QProxyStyle. The alignment of the checkbox and decoration are handled by custom roles (CheckAlignmentRole, DecorationAlignmentRole) in this case to not get in conflict with the text alignment and to have an indicator which cell should have the special checkbox handling.

enum { 
    CheckAlignmentRole = Qt::UserRole + Qt::CheckStateRole + Qt::TextAlignmentRole, 
    DecorationAlignmentRole = Qt::UserRole + Qt::DecorationRole + Qt::TextAlignmentRole 
};

class CenteredBoxProxyStyle : public QProxyStyle
{
public:
    using QProxyStyle::QProxyStyle;
    QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const override
    {
        const QRect baseRes = QProxyStyle::subElementRect(element, option, widget);
        switch (element) {
        case SE_ItemViewItemCheckIndicator: {
            const QStyleOptionViewItem *const itemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
            const QVariant alignData = itemOpt ? itemOpt->index.data(CheckAlignmentRole) : QVariant();
            if (!alignData.isNull())
                return QStyle::alignedRect(itemOpt->direction, alignData.value<Qt::Alignment>(), baseRes.size(), itemOpt->rect);
            break;
        }
        case SE_ItemViewItemDecoration: {
            const QStyleOptionViewItem *const itemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
            const QVariant alignData = itemOpt ? itemOpt->index.data(DecorationAlignmentRole) : QVariant();
            if (!alignData.isNull())
                return QStyle::alignedRect(itemOpt->direction, alignData.value<Qt::Alignment>(), baseRes.size(), itemOpt->rect);
            break;
        }
        case SE_ItemViewItemFocusRect: {
            const QStyleOptionViewItem *const itemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
            const QVariant checkAlignData = itemOpt ? itemOpt->index.data(CheckAlignmentRole) : QVariant();
            const QVariant decorationAlignData = itemOpt ? itemOpt->index.data(DecorationAlignmentRole) : QVariant();
            if (!checkAlignData.isNull() || !decorationAlignData.isNull()) // when it is not null, then the focus rect should be drawn over the complete cell
                return option->rect;
            break;
        }
        default:
            break;
        }
        return baseRes;
    }
};
 

The proxy style can either set for the complete application or directly for the desired view:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CenteredBoxProxyStyle style;
    // a.setStyle(&style); // when it should be set for the complete application

    QStandardItemModel model;
    model.setColumnCount(1);
    model.setRowCount(2);

    QPixmap pix(20, 20);
    pix.fill(Qt::blue);

    auto checkableItem = new QStandardItem;
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
    checkableItem->setCheckState(Qt::Checked);
    checkableItem->setData(Qt::AlignCenter, CheckAlignmentRole);
    model.setItem(0, 0, checkableItem);

    checkableItem = new QStandardItem;
    checkableItem->setFlags(checkableItem->flags() | Qt::ItemIsUserCheckable);
    checkableItem->setData(Qt::AlignCenter, DecorationAlignmentRole);
    checkableItem->setIcon(pix);
    model.setItem(1, 0, checkableItem);

    QTableView tv;
    tv.setModel(&model);
    tv.setStyle(&style);
    tv.show();
    return a.exec();
}