第一次填充 QTableWidget 时,一切都很好,但是当我重新填充它时,它明显变慢了

The first time a QTableWidget is populated, everything is fine, but when i repopulate it, it's significantly slower

本文关键字:填充 新填充 QTableWidget 很好 第一次      更新时间:2023-10-16

代码:

populateTable()
{
  tableWidget->clearContents();
  tableWidget->setRowCount(stringList.size());
  for(int i = 0; i < stringList.size(); ++i)
  {
    tableWidget->setItem(i, 0, new QTableWidgetItem(stringList.at(i)));
  }
}

问题:

第一次运行 populateTable() 时,一切都很好。但接下来的时间,它的运行速度比以前慢得多。

讨论:

经过仔细测试,我怀疑clearContent()是问题所在。因为只需将代码从

tableWidget->clearContents();

自:

tableWidget->setRowCount(0);

解决了问题,但现在它又出现了另一个问题;将行计数设置为"0"似乎不会删除分配的堆 QTableWidgetItems,它似乎只是保留了项目的所有权,因此会留下内存泄漏。(或者至少我只是这么认为...

Qt在QTableWidget中的文档相当模糊,所以我并不完全知道clearContent()实际上做了什么。在文档中,它说"从视图中删除不在标题中的所有项目",这让我不禁要问,表格的内容只是隐藏吗?它被删除了吗?我不太确定。我的理论是 clearContent() 只隐藏项目,任何下一次填充表的尝试实际上都会删除并删除每个项目,然后分配一个新项目以在表上设置,这反过来又是一项昂贵的操作。

另一个有趣的事情是,Qt关于QTableWidget的文档表明,填充QTableWidget的正确方法是在堆上分配一个QTableWidgetItem,然后使用setItem()将其设置在表单元格上,就像我在上面的代码中介绍的那样,我觉得这很奇怪......

总结:

有没有另一种方法来填充和重新填充Qt表而不会遇到所有这些问题? 如果没有,有没有办法解决这些问题?

"Qt 关于 QTableWidget 的文档表明,填充 QTableWidget 的正确方法是在堆上分配一个 QTableWidgetItem,然后使用 setItem() 将其设置在表单元格上,就像我在上面的代码中介绍的那样,我觉得这很奇怪..."

我不觉得奇怪,考虑到 QTableWidget::setItem 的文档明确指出小部件拥有该项目的所有权!

"将行计数设置为'0'似乎不会删除堆分配的QTableWidgetItems,它似乎只是留下了项目的所有权,因此会留下内存泄漏。(或者至少我是这么认为的...

与其猜测它是否泄漏,不如创建自己的QTableWidgetItem子类...并将代码放在其析构函数中,以便您有一个放置断点的地方并确定。 或者,Qt源非常清晰。 setRowCount调用removeRows,这确实删除了QTableWidgetItems:

http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/itemviews/qtablewidget.cpp#line370

http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/itemviews/qtablewidget.cpp#line100

但这再次与QTableWidget的文档一致::setRowCount

将此模型中的行数设置为行。如果此值小于 rowCount(),则丢弃不需要的行中的数据。

你真的不应该看到clearContent()和setRowCount(0)之间的太大区别。 您是否生成了一个可重现的小示例,该示例未与任何大型程序纠缠在一起,以证明这种现象?

我注意到不仅在重新填充 QTableWidget 时普遍缓慢,而且在进行任何更改时也是如此。

例如,我有一个大约 1000 个单元格,通过 setCheckState() 在其上显示复选框。第一次通过检查/取消选中它们,它们很快。第二次通过,需要~15s,这是完全不能接受的。我在桌子上尝试了块信号(真/假),但没有任何效果。

诀窍是阻止模型上的信号,而不是桌子上的信号。该模型正在消耗CPU。

auto table = ui.tableWidget;
auto rows = table->rowCount();
auto cols = table->columnCount();
table->model()->blockSignals(true);
for (auto row = 0; row < rows; row++)
    for (auto col = 0; col < cols; col++)
        if (auto cb = table->item(row, col))
            cb->setCheckState(Qt::CheckState::Checked);
table->model()->blockSignals(false);
table->model()->layoutChanged();//Required, or else you won't see your changes immediately.