4

编码:

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() 时,一切都很好。但是接下来的时间,它的运行速度明显比以前慢。

讨论:

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

tableWidget->clearContents();

至:

tableWidget->setRowCount(0);

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

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

另一个有趣的事情是 Qt 在 QTableWidget 上的文档建议填充 QTableWidget 的正确方法是在堆上分配一个 QTableWidgetItem 然后使用 setItem() 将它设置在一个表格单元格上,就像我在上面的代码中呈现的那样,我发现它是奇怪...

总之:

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

4

2 回答 2

5

“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(),则丢弃不需要的行中的数据。

你真的不应该看到 clearContents() 和 setRowCount(0) 之间有太大的区别。您是否生成了一个小的可重现示例,没有与任何更大的程序交织在一起,来证明这种现象?

于 2012-04-17T18:20:54.903 回答
3

我注意到不仅在重新填充 QTableWidget 方面,而且在进行任何更改方面都普遍缓慢。

例如,我有一个包含大约 1000 个单元格的单元格,它们通过 setCheckState() 在其上显示复选框。第一次通过选中/取消选中它们,它们很快。第二次通过,大约需要 15 秒,这是完全不可接受的。我在桌子上尝试了 blockSignals(true/false),但没有任何效果。

诀窍是阻止模型而不是桌子上的信号。该模型正在消耗 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.
于 2015-07-22T00:11:46.773 回答