代码:
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 表,而不会出现所有这些问题?如果没有,有办法解决这些问题吗?
的 文档明确指出该小部件拥有该项目的所有权,我并不觉得奇怪!Qt 关于 QTableWidget 的文档表明,填充 QTableWidget 的正确方法是在堆上分配 QTableWidgetItem,然后使用 setItem() 将其设置在表格单元格上,就像我在上面的代码中呈现的那样,我觉得这很奇怪......
您可以创建自己的 QTableWidgetItem 子类,而不是猜测它是否泄漏,并将代码放入其析构函数中,以便您有一个地方可以放置断点并确定。另外,Qt 源代码非常清晰。
setRowCount
调用removeRows
,这确实删除了QTableWidgetItems:
但这再次与QTableWidget::setRowCount
将此模型中的行数设置为 rows。如果小于 rowCount(),则不需要的行中的数据将被丢弃。
您真的不应该看到
clearContents()
和 setRowCount(0)
之间有太大区别。您是否生成了一个可重现的小示例,而不是与任何较大的程序交织在一起,来演示这种现象?
我注意到,不仅在重新填充 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.