找回密码
 立即注册
首页 业界区 业界 Qt表格入门(优化篇)

Qt表格入门(优化篇)

何玲 昨天 21:40
摘要:
    为提升大数据量下的渲染性能,本文通过 QStyledItemDelegate 直接绘制单选按钮(使用 QStyleOptionButton 和 drawControl),并在 editorEvent 中处理点击逻辑,避免创建真实控件,显著优化了加载与显示效率。


关键词:
    QStyledItemDelegate、QStyleOptionButton、drawControl、editorEvent、优化、渲染


版本:Qt5.14.2


问题描述:

    在上一篇文章中,使用样式代理类QStyledItemDelegate和基础组件(QRadioButton、QWidget)的组合比较简易地实现了功能,但是在后续使用中发现,大量数据导致视图渲染卡顿,需要对代码进一步优化。


代码如下:
  1. // 优化代理类
  2. class RadioDelegateV2 : public QStyledItemDelegate
  3. {
  4.     Q_OBJECT
  5. public:
  6.     RadioDelegateV2(QObject *parent = nullptr);
  7.     ~RadioDelegateV2();
  8. protected:
  9.     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
  10.     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
  11.     bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
  12. };
  13. RadioDelegateV2::RadioDelegateV2(QObject *parent) : QStyledItemDelegate(parent)
  14. {
  15. }
  16. RadioDelegateV2::~RadioDelegateV2()
  17. {
  18. }
  19. void RadioDelegateV2::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
  20. {
  21.     int state = index.data(Qt::DisplayRole).toInt(); // 0=女, 1=男
  22.     // 分割矩形为左右两半
  23.     QRect rect = option.rect;
  24.     QRect leftRect(rect.left(), rect.top(), rect.width() / 2, rect.height());
  25.     QRect rightRect(rect.left() + rect.width() / 2, rect.top(), rect.width() / 2, rect.height());
  26.     // 绘制“男”按钮(左)
  27.     QStyleOptionButton btnOn;
  28.     btnOn.rect = leftRect;
  29.     btnOn.text = "男";
  30.     btnOn.state |= QStyle::State_Enabled;
  31.     if (state == 1) {
  32.         btnOn.state |= QStyle::State_Sunken | QStyle::State_On;
  33.     } else {
  34.         btnOn.state |= QStyle::State_Raised;
  35.     }
  36.     // 绘制“女”按钮(右)
  37.     QStyleOptionButton btnOff;
  38.     btnOff.rect = rightRect;
  39.     btnOff.text = "女";
  40.     btnOff.state |= QStyle::State_Enabled;
  41.     if (state == 0) {
  42.         btnOff.state |= QStyle::State_Sunken | QStyle::State_On;
  43.     } else {
  44.         btnOff.state |= QStyle::State_Raised;
  45.     }
  46.     QApplication::style()->drawControl(QStyle::CE_RadioButton, &btnOn,  painter);
  47.     QApplication::style()->drawControl(QStyle::CE_RadioButton, &btnOff, painter);
  48. }
  49. QSize RadioDelegateV2::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
  50. {
  51.     Q_UNUSED(index);
  52.     // 返回足够宽以容纳两个按钮
  53.     QFontMetrics fm(option.font);
  54.     int width = fm.horizontalAdvance("男") + fm.horizontalAdvance("女") + 40; // 加 padding
  55.     int height = qMax(fm.height() + 8, 24);
  56.     return QSize(width, height);
  57. }
  58. bool RadioDelegateV2::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
  59. {
  60.     if (event->type() == QEvent::MouseButtonPress) {
  61.         QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
  62.         QPoint pos = mouseEvent->pos();
  63.         QRect rect = option.rect;
  64.         int half = rect.width() / 2;
  65.         int newState;
  66.         if (pos.x() < rect.left() + half) {
  67.             newState = 1; // 点击左侧 → 男
  68.         } else {
  69.             newState = 0; // 点击右侧 → 女
  70.         }
  71.         // 更新模型
  72.         model->setData(index, newState, Qt::DisplayRole);
  73.         return true;
  74.     }
  75.     return false;
  76. }
复制代码
代码说明:

  • 在paint()函数中,创建两个QStyleOptionButton并设置属性;两个按钮根据数据(性别)设置不同的状态;然后使用drawControl()函数绘制按钮;
  • 在sizeHint()函数中,计算可以容纳下两个按钮的宽度;
  • 在editorEvent()函数中,对编辑事件进行操作,判断点击区域,然后更新数据。
其他说明:


  • openPersistentEditor()函数调用可以全部优化掉 ;
  • 如果数据变化有连接的信号,可以使用QStandardItemModel的 void itemChanged(QStandardItem *item)信号修改。
参考文献:


  • QTableView 一列添加两个按钮


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册