如何深入优化Qt表格使用技巧与性能?

摘要:为提升大数据量下的渲染性能,本文通过 QStyledItemDelegate 直接绘制单选按钮(使用 QStyleOptionButton 和 drawControl),并在 editorEvent 中处理点击逻辑,避免创建真实控件,显著优
摘要:     为提升大数据量下的渲染性能,本文通过 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()函数中,对编辑事件进行操作,判断点击区域,然后更新数据。 其他说明: openPersistentEditor()函数调用可以全部优化掉 ; 如果数据变化有连接的信号,可以使用QStandardItemModel的 void itemChanged(QStandardItem *item)信号修改。 参考文献: QTableView 一列添加两个按钮