Qt表格入门(优化篇)
·
为提升大数据量下的渲染性能,本文通过 QStyledItemDelegate 直接绘制单选按钮(使用 QStyleOptionButton 和 drawControl),并在 editorEvent 中处理点击逻辑,避免创建真实控件,显著优化了加载与显示效率。
关键词:
QStyledItemDelegate、QStyleOptionButton、drawControl、editorEvent、优化、渲染
版本:Qt5.14.2
问题描述:
在上一篇文章中,使用样式代理类QStyledItemDelegate和基础组件(QRadioButton、QWidget)的组合比较简易地实现了功能,但是在后续使用中发现,大量数据导致视图渲染卡顿,需要对代码进一步优化。
代码如下:
点击折叠或展开代码
// 优化代理类 |
class RadioDelegateV2 : public QStyledItemDelegate |
{ |
Q_OBJECT |
public: |
RadioDelegateV2(QObject *parent = nullptr); |
~RadioDelegateV2(); |
protected: |
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; |
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; |
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; |
}; |
RadioDelegateV2::RadioDelegateV2(QObject *parent) : QStyledItemDelegate(parent) |
{ |
} |
RadioDelegateV2::~RadioDelegateV2() |
{ |
} |
void RadioDelegateV2::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const |
{ |
int state = index.data(Qt::DisplayRole).toInt(); // 0=女, 1=男 |
// 分割矩形为左右两半 |
QRect rect = option.rect; |
QRect leftRect(rect.left(), rect.top(), rect.width() / 2, rect.height()); |
QRect rightRect(rect.left() + rect.width() / 2, rect.top(), rect.width() / 2, rect.height()); |
// 绘制“男”按钮(左) |
QStyleOptionButton btnOn; |
btnOn.rect = leftRect; |
btnOn.text = "男"; |
btnOn.state |= QStyle::State_Enabled; |
if (state == 1) { |
btnOn.state |= QStyle::State_Sunken | QStyle::State_On; |
} else { |
btnOn.state |= QStyle::State_Raised; |
} |
// 绘制“女”按钮(右) |
QStyleOptionButton btnOff; |
btnOff.rect = rightRect; |
btnOff.text = "女"; |
btnOff.state |= QStyle::State_Enabled; |
if (state == 0) { |
btnOff.state |= QStyle::State_Sunken | QStyle::State_On; |
} else { |
btnOff.state |= QStyle::State_Raised; |
} |
QApplication::style()->drawControl(QStyle::CE_RadioButton, &btnOn, painter); |
QApplication::style()->drawControl(QStyle::CE_RadioButton, &btnOff, painter); |
} |
QSize RadioDelegateV2::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const |
{ |
Q_UNUSED(index); |
// 返回足够宽以容纳两个按钮 |
QFontMetrics fm(option.font); |
int width = fm.horizontalAdvance("男") + fm.horizontalAdvance("女") + 40; // 加 padding |
int height = qMax(fm.height() + 8, 24); |
return QSize(width, height); |
} |
bool RadioDelegateV2::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) |
{ |
if (event->type() == QEvent::MouseButtonPress) { |
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); |
QPoint pos = mouseEvent->pos(); |
QRect rect = option.rect; |
int half = rect.width() / 2; |
int newState; |
if (pos.x() < rect.left() + half) { |
newState = 1; // 点击左侧 → 男 |
} else { |
newState = 0; // 点击右侧 → 女 |
} |
// 更新模型 |
model->setData(index, newState, Qt::DisplayRole); |
return true; |
} |
return false; |
} |
代码说明:
- 在
paint()函数中,创建两个QStyleOptionButton并设置属性;两个按钮根据数据(性别)设置不同的状态;然后使用drawControl()函数绘制按钮; - 在
sizeHint()函数中,计算可以容纳下两个按钮的宽度; - 在
editorEvent()函数中,对编辑事件进行操作,判断点击区域,然后更新数据。
其他说明:
更多推荐

所有评论(0)