4

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

该模型支持各种形式的变化,它们都可以正常工作。相关的两个是:

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

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

当前的设计以相同的方式处理这两种情况:对于模型发出的任何更改的每一行dataChanged(start_of_row_index,end_of_row_index)。我为改变的父行和改变的任何子行发出信号。

然而,当模型变大时,这在案例 2 中表现不佳:发出了大量的dataChanged信号。

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

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

也许我误解了dataChanged信号?它实际上是否会导致视图更新所有子项以及指定范围?或者我可以避免dataChanged在没有DisplayRole变化的情况下发射吗?

编辑了我到目前为止的进展

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

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

一种可能的解决方案可能是dataChanged为任何连续的更改行块聚合信号,但这仍然不能很好地执行,例如,当每隔一行发生更改时 - 它仍然会发出太多信号。

理想情况下,我只想告诉视图将所有数据视为可能已更改(但所有索引仍然有效 - 布局未更改)。对于单个信号,这似乎是不可能的。

由于QTreeView该类的一个怪癖,dataChanged(tl,br只要tl != br. 我有这个工作,它通过了我们的测试,但让我很紧张。

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

然而,这似乎并不理想。还有其他建议吗?

4

1 回答 1

6

每当任何数据发生更改时,您都应该让您的视图知道。这种“让知道”可以通过多种方式发生;当索引的结构没有改变时,发射dataChanged是最常见的;其他人是“严重”的人,例如modelResetor layoutChanged。巧合的是,即使没有dataChanged鼠标悬停,Qt 的某些视图也能够获取更改,但您不应该依赖它。这是一个实现细节,也是一个可能发生变化的主题。

要回答您问题的最后一点,是的,dataChanged必须在任何从QAIM::data()更改返回的数据时发出,即使它“只是”除Qt::DisplayRole.

你在引用性能问题。硬性数字是什么——您实际上是否有任何可衡量的放缓,或者您是否过早地担心这可能会成为以后的问题?您是否知道您可以使用两个参数来表示dataChanged对大型索引矩阵的更改?

编辑:

还有几件事要尝试:

  • 确保您的视图不请求额外数据。例如,除非您设置QTreeView's uniformRowHeights(IIRC),否则视图必须为每个dataChanged信号执行 O(n) 次调用,从而导致 O(n^2) 复杂度。那很糟。

  • 如果你真的确定没有办法解决这个问题,你可能会通过组合layoutAboutToBeChanged,updatePersistentIndexeslayoutChanged. 由于您实际上并未更改索引的结构,因此这可能相当便宜。不过,前一点的优化机会还是值得把握的。

于 2013-05-15T13:57:36.307 回答