首页 > 解决方案 > QTableWidget 仅加载少量项目(< 10 个项目)时速度极慢

问题描述

语境:

对于应用程序,我正在创建一个缩小的“文件浏览器”,它显示文件图标、文件名、相对位置(特定目录)、日期和大小,包括文件夹。

问题:

我使用“方便”QTableWidget来显示文件条目,但是在测试几个文件(<10 个文件夹/文件)时,显示内容需要大约 3 秒。

在为每一列调用QTableWidget::setItem(int, int, QTableWidgetItem*)之后,我希望 UI 能够更新并显示该项目。

实际发生的是所有项目都被处理(setItem(int, int, QTableWidgetItem*)在任意时间〜3s(取决于项目的数量)之后调用然后它最终显示。这是一个问题!

我尝试了什么/建议:

使用自定义表模型

最后,建议(和这里)宁愿使用带有QTableView的自定义表格模型,这里有一个示例

我对采用这种方法(这似乎是理想的方法)犹豫不决,因为等待约 3 秒才能在QTableWidget中显示一些项目是绝对荒谬的。

任何提高性能的建议将不胜感激!

我注意到QFuture与简单循环相比,使用 a 会显着降低性能foreach,后者要快 2-5 倍,但是延迟QTableWidget仍然是主要问题

实施细节:

用户界面设置

QTableWidget Settings (UI)

    QObject
     - mouseTracking enabled
     - contextMenuPolicy: Custom
     - custom stylesheet
    
    QAbstractScrollArea:
     - horizontalScrollBar: AlwaysOff
    
    QAbstractItemView:
     - No triggers
     - No drag drop overwrite
     - Alternating row colours
     - selection mode: single
     - selection behaviour: select rows
     - icon size: 64x64
    
    QTableWidget:
     - show grid: no
     - gridStyle: nopen
     - sortingEnabled: true
    
    QTableWidget:
     - columnCount: 5
    
    Header:
     - horizontalHeaderShowSortIndicator: true
     - verticalHeaderVisible: false
     - verticalHeaderSectionSize: 64

自定义模型结构

struct Model {
     int index = -1;
     QIcon* icon;
     QString* name;
     QString* location;
     QString* dateModified;
     QString* size;
     bool isDir = false;
}; Q_DECLARE_METATYPE(Model);

准备添加条目

      //QFileInfoList list;  - all QFileInfo entries in the current directory
      ui->customTableWidget->setSortingEnabled(false);
      ui->customTableWidget->setRowCount(list.size());

      connect(&futureWatcherLoadDirectory, &QFutureWatcher<QPair<QFileInfo, Model>>::finished, this, [this]() {
           loadDirectoryWaitCondition.wakeAll();
           futureWatcherLoadDirectory.disconnect();
           ui->customTableWidget->setEnabled(true);
           ui->customTableWidget->setSortingEnabled(true);

      });
      connect(&futureWatcherLoadDirectory, &QFutureWatcher<QPair<QFileInfo, Model>>::resultReadyAt, this, [&](int index) {
           if (ui->customTableWidget->rowCount() == 0) {
                Global::clearAndDeleteTableListWidget(ui->customTableWidget);
           }
           QPair<QFileInfo, Model> result = futureWatcherLoadDirectory.resultAt(index);
           currentDirectoryModel.append(&result.second);
           addTableEntry(&result.second);
           //publish to table
      });

      std::function<QPair<QFileInfo, Model>(const QFileInfo)> processFileInfoItem = [this](const QFileInfo fi) {
           return processFileInfoEntry(fi);
      };
      futureLoadDirectory = QtConcurrent::mapped(list, processFileInfoItem);

      futureWatcherLoadDirectory.setFuture(futureLoadDirectory);

添加条目

void ExplorerDialog::addTableEntry(Model* model)
{
     bool hasIcon = (model->icon != nullptr);
     QTableWidgetItem* iconItem = new QTableWidgetItem(hasIcon ? *model->icon : QIcon(), QString());
     QTableWidgetItem* nameItem = new QTableWidgetItem(*model->name);
     QTableWidgetItem* locationItem = new QTableWidgetItem(*model->location);
     QTableWidgetItem* dateModifiedItem = new QTableWidgetItem(*model->dateModified);
     QTableWidgetItem* sizeItem = new QTableWidgetItem(*model->size);

     if (hasIcon) {
          iconItem->setTextAlignment(Qt::AlignVCenter);
     }
     nameItem->setTextAlignment(Qt::AlignVCenter);
     locationItem->setTextAlignment(Qt::AlignVCenter);
     dateModifiedItem->setTextAlignment(Qt::AlignCenter);
     sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);

     if (!model->isDir && hasIcon) {
          QString base64 = ImageHelper::getIconBase64(*model->icon);
          QString html = QString("<img src='data:image/%1;base64, %2'>").arg(ImageHelper::getCacheImageFormat().toUpper(), base64);
          if (hasIcon) {
               iconItem->setToolTip(html);
          }
          nameItem->setToolTip(html);
          locationItem->setToolTip(html);
          dateModifiedItem->setToolTip(html);
          sizeItem->setToolTip(html);
     }

     int index = model->index;
     ui->customTableWidget->setItem(index, 0, iconItem);
     ui->customTableWidget->setItem(index, 1, nameItem);
     ui->customTableWidget->setItem(index, 2, locationItem);
     ui->customTableWidget->setItem(index, 3, dateModifiedItem);
     ui->customTableWidget->setItem(index, 4, sizeItem);

     // with or without QTableWidget::update being called, it has no effect. The item is not added to the table immediately (or almost immediately)
}

标签: c++qtqwidgetqtableviewqtablewidget

解决方案


推荐阅读