c++ - QTableWidget 仅加载少量项目(< 10 个项目)时速度极慢
问题描述
语境:
对于应用程序,我正在创建一个缩小的“文件浏览器”,它显示文件图标、文件名、相对位置(特定目录)、日期和大小,包括文件夹。
问题:
我使用“方便”QTableWidget
来显示文件条目,但是在测试几个文件(<10 个文件夹/文件)时,显示内容需要大约 3 秒。
在为每一列调用QTableWidget::setItem(int, int, QTableWidgetItem*)之后,我希望 UI 能够更新并显示该项目。
实际发生的是所有项目都被处理(setItem(int, int, QTableWidgetItem*)
在任意时间〜3s(取决于项目的数量)之后调用然后它最终显示。这是一个问题!
我尝试了什么/建议:
根据许多帖子(例如这里),调整
QHeaderView
每个插入的大小是一个很大的性能杀手。我不这样做,而是在QDialog::showEvent(QShowEvent*)中预定义启动时的列宽另一个建议(此处和此处)是使用QTableWidget::setRowCount(int)预定义您将使用的行数。我默认这样做了。
使用自定义表模型
最后,建议(和这里)宁愿使用带有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)
}
解决方案
推荐阅读
- python - unittest - 如何测试函数中的内部参数?
- php - 在 xampp 中安装 composer 时出现以下 dll 错误怎么办
- javascript - Firebase 使用 Javascript 使用 REST API 调用创建动态链接,给出 400
- javascript - 读取 csv 文件会引发错误 fs.readFileSync) 不是函数
- javascript - 使用 HTML 和 JavaScript 创建 Linux 终端主题网站
- python - 删除逗号或撇号前面的空格 - Python
- javascript - 附加选项以选择框取决于从数组中提取的部分
- python - 使用 Python 更新 SQL - 绑定数量不正确
- python - 如何找到整数变量的长度
- google-chrome-devtools - Chrome 开发者工具中缺少“安全”标签