代码:
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表而没有所有这些问题?如果没有,有没有办法解决这些问题?
答案 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.