如何修复自定义QItemDelegate中drawCheck的复选框渲染异常?
QTableView自定义Boolean代理复选框渲染异常问题
我给QTableView的第一列添加了自定义代理BooleanItemDelegate,当前遇到复选框渲染异常:当所有可见复选框均勾选时渲染正常,但当两个及以上复选框未勾选时,复选框的白色勾选标记会闪烁,仿佛仅被部分重绘而非完整绘制。相关代码如下:
头文件 BooleanItemDelegate.h
#ifndef BOOLEANITEMDELEGATE_H #define BOOLEANITEMDELEGATE_H #include <QItemDelegate> #include <QSqlTableModel> class BooleanItemDelegate : public QItemDelegate { public: BooleanItemDelegate(QSqlTableModel* model, QObject* parent); ~BooleanItemDelegate(); public: void paint(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex& index) const; bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index); }; #endif // BOOLEANITEMDELEGATE_H
源文件 BooleanItemDelegate.cpp
#include "BooleanItemDelegate.h" #include <qcoreevent.h> BooleanItemDelegate::BooleanItemDelegate(QSqlTableModel* model, QObject* parent) : QItemDelegate(parent) {} BooleanItemDelegate::~BooleanItemDelegate() {} void BooleanItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { drawBackground(painter, option, index); drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked); drawFocus(painter, option, option.rect); } bool BooleanItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) { if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick ) { model->setData(index, !model->data(index).toBool()); event->accept(); } return QItemDelegate::editorEvent(event, model, option, index); }
解决思路
- 修复复选框绘制区域:当前直接把整个item的
option.rect传给drawCheck,导致复选框占满整个单元格,重绘时容易出现区域重叠引发闪烁。应该通过样式获取复选框的正确绘制区域:void BooleanItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { painter->save(); // 先绘制背景 drawBackground(painter, option, index); // 获取复选框的正确位置 QStyleOptionButton checkOpt; checkOpt.rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option, nullptr); checkOpt.state = option.state | (index.data().toBool() ? QStyle::State_On : QStyle::State_Off); // 绘制复选框 style()->drawControl(QStyle::CE_CheckBox, &checkOpt, painter); // 绘制焦点框 drawFocus(painter, option, option.rect); painter->restore(); } - 避免重复事件处理:在
editorEvent中,处理完鼠标事件后仍调用父类的editorEvent,会导致同一事件被重复处理,触发多次数据变更和重绘,进而引发闪烁。处理完自定义逻辑后直接返回true即可:bool BooleanItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) { if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick ) { model->setData(index, !model->data(index).toBool()); event->accept(); return true; // 不再让父类处理该事件 } return QItemDelegate::editorEvent(event, model, option, index); } - 确保重绘区域精准:如果上述修改后仍有闪烁,可在调用
setData时明确指定数据角色,确保模型正确触发dataChanged信号,让视图精准重绘目标单元格:model->setData(index, !model->data(index).toBool(), Qt::EditRole);
内容的提问来源于stack exchange,提问作者Joseph
相关产品推荐
相关产品推荐

