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

时间:2012-04-17 13:51:24

标签: c++ qt qtablewidget qtablewidgetitem

代码:

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,它似乎只是保留了项目的所有权,因此它会留下内存泄漏。 (或者至少我只是这么认为......)

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

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

摘要:

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

2 个答案:

答案 0 :(得分:5)

“关于QTableWidget的Qt文档表明,填充QTableWidget的正确方法是在堆上分配QTableWidgetItem,然后使用setItem()将其设置在表格单元格上,就像我在上面的代码中看到的那样,我发现太奇怪了......“

我觉得这并不奇怪,因为documentation for 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

但这又与documentation for QTableWidget::setRowCount

一致
  

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

你真的不应该在clearContents()和setRowCount(0)之间看到很多区别。您是否已经生成了一个可重现的小例子,而不是在任何更大的程序中缠绕在一起,证明了这种现象?

答案 1 :(得分:2)

我注意到,不仅在重新填充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.