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

问题描述 投票:0回答:2

代码:

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 表,而不会出现所有这些问题?如果没有,有办法解决这些问题吗?

c++ qt qtablewidget qtablewidgetitem
2个回答
5
投票

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

考虑到 QTableWidget::setItem

 文档明确指出该小部件拥有该项目的所有权,我并不觉得奇怪!

您可以创建自己的 QTableWidgetItem 子类,而不是猜测它是否泄漏,并将代码放入其析构函数中,以便您有一个地方可以放置断点并确定。另外,Qt 源代码非常清晰。

setRowCount
调用
removeRows
,这确实删除了QTableWidgetItems:

但这再次与QTableWidget::setRowCount

文档一致:

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

您真的不应该看到

clearContents()
setRowCount(0)
之间有太大区别。您是否生成了一个可重现的小示例,而不是与任何较大的程序交织在一起,来演示这种现象?


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.
© www.soinside.com 2019 - 2024. All rights reserved.