资讯动态

QTableWidget 使用时太耗时

发布时间:2026/8/23 7:25:23 来源:尧图企业网站定制
我有4个表格每个都是32行22列。每个单元格里装填的都是自定义QWidget我使用QTableWidget来显示表格。效果为了显示该窗体感觉花费了很多的时间。不符合我的预期。核心原因在于setCellWidget()会为每个单元格创建一个真实的、独立的窗口对象。你一共有4 * 32 * 22 2816个单元格这意味着要创建近3000个独立的QWidget及其子控件。每个控件都拥有自己的窗口句柄、事件循环和绘制上下文内存占用和绘制开销极其庞大最终导致你感受到的严重耗时和卡顿。要解决这个问题最根本的方法是从“重量级的控件”转向“轻量级的绘制”。核心解决方案拥抱 Model/View 框架这是Qt官方推荐的、也是解决此类性能问题的标准做法。迁移到QTableViewQStandardItemModel放弃QTableWidget改用QTableView配合QStandardItemModel来存储数据。QTableWidget本身是QTableView的便捷子类但其“一单元格一对象”的设计在数据量大时是性能瓶颈。使用QStyledItemDelegate进行绘制这是最关键的一步。不要用setCellWidget()而是为QTableView设置一个自定义的QStyledItemDelegate。原理委托不会为每个单元格创建真正的控件而是根据数据模型中的内容在单元格需要被绘制时“画”出你想要的界面。优势这种方式极大地减少了内存占用和对象数量绘制效率极高滚动和刷新会变得非常流畅。如果需要有按钮的交互效果可以在委托的paint()方法中绘制按钮的样式并在editorEvent()中处理点击事件。快速缓解技巧治标不治本如果短期内无法重构可以尝试以下方法可能会有轻微改善但无法解决根本问题。暂停界面更新在批量设置单元格控件时使用setUpdatesEnabled(false)暂停绘制完成后再恢复。tableWidget-setUpdatesEnabled(false); // ... 你的 setCellWidget 循环 ... tableWidget-setUpdatesEnabled(true);阻止信号触发在批量操作前调用blockSignals(true)阻止表格因每个单元格变化而触发不必要的信号和重绘。固定行高如果行高都相同可以开启setUniformRowHeights(true)来加速布局计算。固定列宽将列宽模式设为Fixed避免在插入数据时频繁重新计算列宽。总结与建议根本问题在于选错了工具。setCellWidget()是为少量、交互复杂的单元格设计的便捷方法。对于你这种包含近3000个自定义控件的场景它已经不堪重负。因此最推荐、也最彻底的解决方案是重构代码采用QTableViewQStandardItemModelQStyledItemDelegate的经典 MVC 模式。虽然这需要一些学习和重构工作但这是一次投入、长期受益的优化能让你的表格应用在面对更多数据时依然保持流畅。采用QTableViewQStandardItemModelQStyledItemDelegate#include QApplication #include QWidget // 改为 QWidget #include QVBoxLayout // 新增布局头文件 #include QTableView #include QStandardItemModel #include QStyledItemDelegate #include QPainter #include QPen #include QColor #include QHeaderView class DotDelegate : public QStyledItemDelegate { public: using QStyledItemDelegate::QStyledItemDelegate; void paint(QPainter *painter, const QStyleOptionViewItem option, const QModelIndex index) const override { painter-save(); painter-setRenderHint(QPainter::Antialiasing, true); painter-setRenderHint(QPainter::TextAntialiasing, true); // 1. 填充深蓝色背景 painter-fillRect(option.rect, QColor(#214a6b)); // 2. 绘制浅蓝色网格线 painter-setPen(QPen(QColor(#4d6a8f), 1)); painter-drawRect(option.rect); // 3. 计算左侧圆圈的尺寸和位置 qreal h option.rect.height(); qreal diameter h * 0.6; qreal leftMargin h * 0.1; QRectF circleRect(option.rect.left() leftMargin, option.rect.center().y() - diameter / 2.0, diameter, diameter); // 4. 绘制左侧圆圈 painter-setPen(Qt::NoPen); painter-setBrush(QColor(#8b8b8b)); painter-drawEllipse(circleRect); // 5. 绘制右侧文本 QString text index.data(Qt::DisplayRole).toString(); if (!text.isEmpty()) { painter-setPen(QColor(Qt::white)); QFont font option.font; painter-setFont(font); qreal textSpacing h * 0.1; QRectF textRect(option.rect.left() leftMargin diameter textSpacing, option.rect.top(), option.rect.width() - (leftMargin diameter textSpacing), option.rect.height()); painter-drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, text); } painter-restore(); } }; // 这里将 MainWindow 改为了 externalMonitorWidget 并继承 QWidget class externalMonitorWidget : public QWidget { public: // 添加了标准的 parent 参数 explicit externalMonitorWidget(QWidget *parent nullptr) : QWidget(parent) { setWindowTitle(圆点表格效果 (Qt5 C)); resize(1000, 600); // 1. 创建视图和模型 QTableView *tableView new QTableView(this); int row 32; int col 22; QStandardItemModel *model new QStandardItemModel(row, col, this); // 2. 设置表头文字 QStringList horizontalHeaders; QStringList verticalHeaders; for (int i 1; i col; i) horizontalHeaders QString::number(i); for (int i 1; i row; i) verticalHeaders QString::number(i); model-setHorizontalHeaderLabels(horizontalHeaders); model-setVerticalHeaderLabels(verticalHeaders); for (int i 1; i row; i) { for (int j 1; j col; j) { QStandardItem *item new QStandardItem(-179.1); model-setItem(i - 1, j - 1, item); } } // 3. 设置视图属性 tableView-setModel(model); tableView-setShowGrid(false); tableView-setSelectionMode(QAbstractItemView::NoSelection); tableView-setEditTriggers(QAbstractItemView::NoEditTriggers); // 设置表头样式 QString headerStyle R( QHeaderView::section { background-color: #214a6b; color: white; border: 1px solid #4d6a8f; } ); tableView-horizontalHeader()-setStyleSheet(headerStyle); tableView-verticalHeader()-setStyleSheet(headerStyle); // 调整行高和列宽 tableView-horizontalHeader()-setDefaultSectionSize(65); tableView-verticalHeader()-setDefaultSectionSize(30); // 4. 应用自定义代理 tableView-setItemDelegate(new DotDelegate(tableView)); // 5. 使用布局将 tableView 放入 QWidget 中替代 setCentralWidget QVBoxLayout *layout new QVBoxLayout(this); layout-setContentsMargins(0, 0, 0, 0); // 让表格完全填满 Widget不留边距 layout-addWidget(tableView); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); // 将原来的 MainWindow 改为 externalMonitorWidget externalMonitorWidget w; w.show(); return a.exec(); }进一步优化封装函数接口#include QApplication #include QWidget #include QVBoxLayout #include QTableView #include QStandardItemModel #include QStyledItemDelegate #include QPainter #include QPen #include QColor #include QHeaderView class DotDelegate : public QStyledItemDelegate { public: using QStyledItemDelegate::QStyledItemDelegate; void paint(QPainter *painter, const QStyleOptionViewItem option, const QModelIndex index) const override { painter-save(); painter-setRenderHint(QPainter::Antialiasing, true); painter-setRenderHint(QPainter::TextAntialiasing, true); // 1. 填充深蓝色背景 painter-fillRect(option.rect, QColor(#214a6b)); // 2. 绘制浅蓝色网格线 painter-setPen(QPen(QColor(#4d6a8f), 1)); painter-drawRect(option.rect); // 3. 计算左侧圆圈的尺寸和位置 qreal h option.rect.height(); qreal diameter h * 0.6; qreal leftMargin h * 0.1; QRectF circleRect(option.rect.left() leftMargin, option.rect.center().y() - diameter / 2.0, diameter, diameter); // 4. 获取动态颜色并绘制左侧圆圈 QColor circleColor QColor(#8b8b8b); // 默认灰色 // 读取我们存在 UserRole 里的颜色 QVariant colorVariant index.data(Qt::UserRole); if (colorVariant.isValid() colorVariant.canConvertQColor()) { circleColor colorVariant.valueQColor(); } painter-setPen(Qt::NoPen); painter-setBrush(circleColor); painter-drawEllipse(circleRect); // 5. 绘制右侧文本 QString text index.data(Qt::DisplayRole).toString(); if (!text.isEmpty()) { painter-setPen(QColor(Qt::white)); QFont font option.font; painter-setFont(font); qreal textSpacing h * 0.1; QRectF textRect(option.rect.left() leftMargin diameter textSpacing, option.rect.top(), option.rect.width() - (leftMargin diameter textSpacing), option.rect.height()); painter-drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, text); } painter-restore(); } }; class externalMonitorWidget : public QWidget { public: explicit externalMonitorWidget(QWidget *parent nullptr) : QWidget(parent) { setWindowTitle(圆点表格效果 (Qt5 C)); resize(1000, 600); // 1. 创建视图和模型 tableView new QTableView(this); int row 32; int col 22; model new QStandardItemModel(row, col, this); // 2. 设置表头文字 QStringList horizontalHeaders; QStringList verticalHeaders; for (int i 1; i col; i) horizontalHeaders QString::number(i); for (int i 1; i row; i) verticalHeaders QString::number(i); model-setHorizontalHeaderLabels(horizontalHeaders); model-setVerticalHeaderLabels(verticalHeaders); // 初始化填充数据默认为灰色和 -179.1 for (int i 1; i row; i) { for (int j 1; j col; j) { QStandardItem *item new QStandardItem(-179.1); model-setItem(i - 1, j - 1, item); } } // 3. 设置视图属性 tableView-setModel(model); tableView-setShowGrid(false); tableView-setSelectionMode(QAbstractItemView::NoSelection); tableView-setEditTriggers(QAbstractItemView::NoEditTriggers); // 设置表头样式 QString headerStyle R( QHeaderView::section { background-color: #214a6b; color: white; border: 1px solid #4d6a8f; } ); tableView-horizontalHeader()-setStyleSheet(headerStyle); tableView-verticalHeader()-setStyleSheet(headerStyle); tableView-horizontalHeader()-setDefaultSectionSize(65); tableView-verticalHeader()-setDefaultSectionSize(30); // 4. 应用自定义代理 tableView-setItemDelegate(new DotDelegate(tableView)); // 5. 布局 QVBoxLayout *layout new QVBoxLayout(this); layout-setContentsMargins(0, 0, 0, 0); layout-addWidget(tableView); // // 展示如何调用接口测试代码实际使用时可删除 // 将第一列设置为绿色第二列红色第三列灰色 for (int i 0; i row; i) { setItemGreen(i, 0); // 第一列变绿 setItemRed(i, 1); // 第二列变红 setItemGray(i, 2); // 第三列变灰 setItemText(i, 3, OK); // 第四列修改文字 setItemText(i, 4, ERR); // 第五列修改文字 } // } // 封装的接口 // 通用接口修改指定行、列的圆圈颜色 // 注意row 和 col 都是从 0 开始计数的 void setItemColor(int row, int col, const QColor color) { QModelIndex index model-index(row, col); if (index.isValid()) { model-setData(index, color, Qt::UserRole); } } // 变绿 void setItemGreen(int row, int col) { setItemColor(row, col, QColor(#00FF00)); // 或者 QColor(Qt::green) } // 变红 void setItemRed(int row, int col) { setItemColor(row, col, QColor(#FF0000)); // 或者 QColor(Qt::red) } // 变灰 void setItemGray(int row, int col) { setItemColor(row, col, QColor(#8b8b8b)); // 之前的默认灰色 } // 修改显示的数字 void setItemText(int row, int col, const QString text) { QModelIndex index model-index(row, col); if (index.isValid()) { model-setData(index, text, Qt::DisplayRole); } } // 获取当前TableView的指针如果需要外部彻底接管可以开放这个 QTableView* getTableView() { return tableView; } private: QTableView *tableView; QStandardItemModel *model; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); externalMonitorWidget w; w.show(); return a.exec(); }再进一步拆分把类以.h,.cpp的形式来写。#ifndef DOTDELEGATE_H #define DOTDELEGATE_H #include QStyledItemDelegate class DotDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit DotDelegate(QObject *parent nullptr); void paint(QPainter *painter, const QStyleOptionViewItem option, const QModelIndex index) const override; }; #endif // DOTDELEGATE_H#include dotdelegate.h #include QPainter #include QPen #include QColor #include QVariant DotDelegate::DotDelegate(QObject *parent) : QStyledItemDelegate(parent) {} void DotDelegate::paint(QPainter *painter, const QStyleOptionViewItem option, const QModelIndex index) const { painter-save(); painter-setRenderHint(QPainter::Antialiasing, true); painter-setRenderHint(QPainter::TextAntialiasing, true); // 1. 填充深蓝色背景 painter-fillRect(option.rect, QColor(#214a6b)); // 2. 绘制浅蓝色网格线 painter-setPen(QPen(QColor(#4d6a8f), 1)); painter-drawRect(option.rect); // 3. 计算左侧圆圈的尺寸和位置 qreal h option.rect.height(); qreal diameter h * 0.6; qreal leftMargin h * 0.1; QRectF circleRect(option.rect.left() leftMargin, option.rect.center().y() - diameter / 2.0, diameter, diameter); // 4. 获取动态颜色并绘制左侧圆圈 QColor circleColor QColor(#8b8b8b); // 默认灰色 QVariant colorVariant index.data(Qt::UserRole); if (colorVariant.isValid() colorVariant.canConvertQColor()) { circleColor colorVariant.valueQColor(); } painter-setPen(Qt::NoPen); painter-setBrush(circleColor); painter-drawEllipse(circleRect); // 5. 绘制右侧文本 QString text index.data(Qt::DisplayRole).toString(); if (!text.isEmpty()) { painter-setPen(QColor(Qt::white)); QFont font option.font; painter-setFont(font); qreal textSpacing h * 0.1; QRectF textRect(option.rect.left() leftMargin diameter textSpacing, option.rect.top(), option.rect.width() - (leftMargin diameter textSpacing), option.rect.height()); painter-drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, text); } painter-restore(); }#ifndef EXTERNALMONITORWIDGET_H #define EXTERNALMONITORWIDGET_H #include QWidget #include QColor #include QString class QTableView; class QStandardItemModel; class externalMonitorWidget : public QWidget { Q_OBJECT public: explicit externalMonitorWidget(QWidget *parent nullptr); // 封装的接口 void setItemColor(int row, int col, const QColor color); void setItemGreen(int row, int col); void setItemRed(int row, int col); void setItemGray(int row, int col); void setItemText(int row, int col, const QString text); QTableView* getTableView() const; private: QTableView *tableView; QStandardItemModel *model; }; #endif // EXTERNALMONITORWIDGET_H#include externalmonitorwidget.h #include dotdelegate.h #include QTableView #include QStandardItemModel #include QHeaderView #include QVBoxLayout externalMonitorWidget::externalMonitorWidget(QWidget *parent) : QWidget(parent) { setWindowTitle(圆点表格效果 (Qt5 C)); resize(1000, 600); // 1. 创建视图和模型 tableView new QTableView(this); int row 32; int col 22; model new QStandardItemModel(row, col, this); // 2. 设置表头文字 QStringList horizontalHeaders; QStringList verticalHeaders; for (int i 1; i col; i) horizontalHeaders QString::number(i); for (int i 1; i row; i) verticalHeaders QString::number(i); model-setHorizontalHeaderLabels(horizontalHeaders); model-setVerticalHeaderLabels(verticalHeaders); // 初始化填充数据默认为灰色和 -179.1 for (int i 0; i row; i) { for (int j 0; j col; j) { QStandardItem *item new QStandardItem(-179.1); model-setItem(i, j, item); } } // 3. 设置视图属性 tableView-setModel(model); tableView-setShowGrid(false); tableView-setSelectionMode(QAbstractItemView::NoSelection); tableView-setEditTriggers(QAbstractItemView::NoEditTriggers); // 设置表头样式 QString headerStyle R( QHeaderView::section { background-color: #214a6b; color: white; border: 1px solid #4d6a8f; } ); tableView-horizontalHeader()-setStyleSheet(headerStyle); tableView-verticalHeader()-setStyleSheet(headerStyle); tableView-horizontalHeader()-setDefaultSectionSize(65); tableView-verticalHeader()-setDefaultSectionSize(30); // 4. 应用自定义代理 tableView-setItemDelegate(new DotDelegate(tableView)); // 5. 布局 QVBoxLayout *layout new QVBoxLayout(this); layout-setContentsMargins(0, 0, 0, 0); layout-addWidget(tableView); } // 封装的接口实现 void externalMonitorWidget::setItemColor(int row, int col, const QColor color) { QModelIndex index model-index(row, col); if (index.isValid()) { model-setData(index, color, Qt::UserRole); } } void externalMonitorWidget::setItemGreen(int row, int col) { setItemColor(row, col, QColor(#00FF00)); } void externalMonitorWidget::setItemRed(int row, int col) { setItemColor(row, col, QColor(#FF0000)); } void externalMonitorWidget::setItemGray(int row, int col) { setItemColor(row, col, QColor(#8b8b8b)); } void externalMonitorWidget::setItemText(int row, int col, const QString text) { QModelIndex index model-index(row, col); if (index.isValid()) { model-setData(index, text, Qt::DisplayRole); } } QTableView* externalMonitorWidget::getTableView() const { return tableView; }#include QApplication #include externalmonitorwidget.h int main(int argc, char *argv[]) { QApplication a(argc, argv); externalMonitorWidget w; w.show(); // 演示接口调用 // 将第1列变绿第2列变红第3列变灰第4列修改文字 for (int i 0; i 32; i) { w.setItemGreen(i, 0); w.setItemRed(i, 1); w.setItemGray(i, 2); w.setItemText(i, 3, OK); w.setItemText(i, 4, ERR); } return a.exec(); }

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价