何时从QAbstractItemModel发出dataChanged

时间:2013-05-15 09:55:35

标签: qt qtreeview qabstractitemmodel

在Qt中,我有一个子类化QAbstractItemModel的模型 - 它是QTreeView中显示的树。

该模型支持各种形式的变更,一切正常。两个相关性是:

1)少数相关行中的一些数据发生变化

2)可视化更改意味着大多数行应更改其格式 - 特别是它们会更改背景突出显示。他们的DisplayRole数据不会改变。

当前设计以相同的方式处理这两个方面:对于任何有任何更改的行,模型都会发出dataChanged(start_of_row_index,end_of_row_index)。我为两个更改的父行以及任何已更改的子项发出信号。

然而,在模型2变大的情况下,这在情况2中表现不佳:发出了大量的dataChanged信号。

我更改了代码,以便在案例2中,模型仅针对作为整个树的父级的(单个)行发出dataChanged

这仍然可以正常工作,但不符合我对模型责任的理解。但我怀疑我可能错了。

也许我误解了dataChanged信号?它是否真的导致视图更新所有子项以及指定的范围?或者,当dataChanged不是正在发生变化的DisplayRole时,我可以避免发出dataChanged吗?

编辑我目前的进展

正如Jan指出的那样,对于案例2中的大多数或所有行,我应该发出dataChanged

我的代码最初通过为每个更改的行发出dataChanged来做到这一点,但这太贵了 - 视图处理所有这些信号的时间太长了。

一个可能的解决方案可能是为任何连续的已更改行块聚合QTreeView信号,但是当例如每隔一行发生更改时,这仍然无法正常运行 - 它仍然会发出太多信号。

理想情况下,我想告诉视图将所有数据视为可能已更改(但所有索引仍然有效 - 布局未更改)。单个信号似乎无法做到这一点。

由于dataChanged(tl,br类的怪癖,只要tl != br,就有可能(虽然根据规范不正确)只能发出一个dataChanged(tl,br)。我有这个工作,它通过了我们的测试,但让我感到紧张。

我现在已经解决了遍历树的版本,并为每个父项发出一个{{1}}(使用tl,br跨越该父项的所有子项)。这符合模型/视图协议,对于我们的模型,它通常会将信号数量减少大约10倍。

然而,它似乎并不理想。有人提出任何其他建议吗?

1 个答案:

答案 0 :(得分:6)

每当有任何数据发生变化时,您都应该让您的观点知道。这种“让人知道”可以通过多种方式发生;当索引的结构没有改变时,发光dataChanged是最常见的;其他人是“严重”的,如modelResetlayoutChanged。巧合的是,即使没有dataChanged,Qt的一些观点也能够获得变化。鼠标悬停,但你不应该依赖它。这是一个实施细节和一个需要改变的主题。

要回答问题的最后一点,是的,每当从dataChanged返回的任何数据发生变化时,必须发出QAIM::data(),即使它只是“仅”Qt::DisplayRole以外的其他角色

你引用了性能问题。有哪些难以理解的数字 - 您实际上是否正在获得任何可衡量的减速,或者您是否过早地担心这可能会成为一个问题?您是否意识到可以使用dataChanged的两个参数来表示对大型索引矩阵的更改?

修改

还有几件事要尝试:

  • 确保您的视图不会请求额外数据。例如,除非设置QTreeView的{​​{1}}(IIRC),否则视图必须对每个uniformRowHeights信号执行O(n)调用,从而导致O(n ^ 2) )复杂性。那太糟糕了。

  • 如果您确定无法解决此问题,那么可能通过合并dataChangedlayoutAboutToBeChangedupdatePersistentIndexes来逃避。由于您实际上并未更改索引的结构,因此这可能相当便宜。但是,前一点的优化机会仍值得一试。