何时从QAbstractItemModel发出dataChanged [英] When to emit dataChanged from a QAbstractItemModel

查看:413
本文介绍了何时从QAbstractItemModel发出dataChanged的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In Qt, I have a model subclassing QAbstractItemModel - it's a tree displayed in a QTreeView.

模型支持各种形式的更改,这些更改都可以正常运行.相关的两个是:

The model supports various forms of change which all work OK. The two of relevance are:

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

1) Some data in a small number of related rows changes

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

2) A visualisation change means that the majority of rows should change their formatting - in particular they have a change of background highlighting. Their DisplayRole data does not change.

当前的设计以相同的方式处理这两个问题:每行有任何更改的模型都会发出dataChanged(start_of_row_index,end_of_row_index).我会为所有更改的父行及其所有已更改的子级发出信号.

The current design deals with both of these in the same way: for every row that has any change the model emits dataChanged(start_of_row_index,end_of_row_index). I emit the signal for both parent rows that change and for any of their children that have changed.

但是,由于模型变大,这种情况在情况2中表现不佳:发出了大量dataChanged信号.

However, this performs badly in case 2 as the model gets big: a very large number of dataChanged signals are emitted.

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

I have changed the code so that in case 2 the model emits dataChanged only for the (single) row that is the parent of the entire tree.

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

This still appears to work correctly but does not accord with my understanding of the responsibilities of the model. But I suspect I may be wrong.

也许我误会了dataChanged信号?它是否实际上导致视图更新所有子级以及指定范围?还是在DisplayRole不变的情况下避免发出dataChanged?

Perhaps I am misunderstanding the dataChanged signal? Does it actually cause the view to update all children as well as the specified range? Or can I avoid emitting dataChanged when it is not the DisplayRole that is changing?

正如Jan所指出的,在情况2中,我应该为大多数或所有行发出dataChanged.

As Jan points out, I ought to emit dataChanged either for most or all of the rows in case 2.

我的代码最初是通过为每个更改的行发出dataChanged来完成此操作的,但这太昂贵了-视图花费太长时间来处理所有这些信号.

My code originally did this by emitting dataChanged for every changed row but this is too expensive - the view takes too long to process all these signals.

一种可能的解决方案是为更改行的任何连续块聚合dataChanged信号,但是例如在每隔一行更改后,它仍然不能很好地工作-它仍然会发出太多信号.

A possible solution could be to aggregate the dataChanged signal for any contiguous blocks of changed rows but this will still not perform well when, for example, every other row has changed - it would still emit too many signals.

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

Ideally I would like to just tell the view to consider all data as potentially changed (but all indexes still valid - the layout unchanged). This does not seem to be possible with a single signal.

由于QTreeView类的怪癖,可能会(尽管根据规范是不正确的)仅发出一个dataChanged(tl,br),只要发出tl != br的时间即可.我进行了这项工作,它通过了我们的测试,但让我感到紧张.

Because of a quirk of the QTreeView class, it is possible (though incorrect according to the spec) to emit only one dataChanged(tl,br) as long as tl != br. I had this working and it passed our testing but left me nervous.

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

I have settled for now on a version which traverses the tree and emits a single dataChanged(tl,br) for every parent (with tl,br spanning all the children of that parent). This conforms to the model/view protocol and for our models it typically reduces the number of signals by about a factor of 10.

但是,这似乎并不理想.还有其他建议吗?

It does not seem ideal however. Any other suggestions anyone?

推荐答案

每当更改任何数据时,您都应该告知您的观点.这种告知"可以通过多种方式发生.当索引的结构未更改时,发出dataChanged是最常见的一种.其他的是严重"的,例如modelResetlayoutChanged.巧合的是,即使在没有dataChanged的情况下,Qt的某些视图也能够获取更改.鼠标悬停,但您不应该依赖它.这是一个实现细节,并且有待更改.

You are expected to let your views know whenever any data gets changed. This "letting know" can happen through multiple ways; emitting dataChanged is the most common one when the structure of the indexes has not changed; others are the "serious" ones like modelReset or layoutChanged. By a coincidence, some of the Qt's views are able to pick up changes even without dataChanged on e.g. a mouseover, but you aren't supposed to rely on that. It's an implementation detail and a subject to change.

要回答您问题的最后一部分,是的,只要从QAIM::data()返回的任何数据发生更改,就必须发出dataChanged,即使它只是"Qt::DisplayRole"以外的其他角色.

To answer the final bit of your question, yes, dataChanged must be emitted whenever any data returned from the QAIM::data() changes, even if it's "just" some other role than Qt::DisplayRole.

您在引用性能问题.困难的数字是什么-您实际上是否有任何可衡量的减速,还是只是过早担心这可能会在以后成为问题?您是否知道可以同时使用dataChanged的两个参数来表示对大型索引矩阵进行更改的事实?

You're citing performance problems. What are the hard numbers -- are you actually getting any measurable slowdown, or are you just prematurely worried that this might be a problem later on? Are you aware of the fact that you can use both arguments to the dataChanged to signal a change over a big matrix of indexes?

还有更多尝试的方法:

  • 确保您的视图不请求其他数据.例如,除非您设置QTreeViewuniformRowHeights(IIRC),否则视图将必须为每个dataChanged信号执行O(n)调用,从而导致O(n ^ 2)复杂性.不好.

  • Make sure that your view does not request extra data. For example, unless you set the QTreeView's uniformRowHeights (IIRC), the view will have to execute O(n) calls for each dataChanged signal, leading to O(n^2) complexity. That's bad.

如果您真的确定没有办法解决此问题,则可以通过组合layoutAboutToBeChangedupdatePersistentIndexeslayoutChanged可能.由于您实际上并未更改索引的结构,因此这可能会很便宜.但是,上一点中的优化机会仍然值得一试.

If you are really sure that there's no way around this, you might get away by combining the layoutAboutToBeChanged, updatePersistentIndexes and layoutChanged. As you are not actually changing the structure of your indexes, this might be rather cheap. However, the optimization opportunity in the previous point is still worthwhile taking.

这篇关于何时从QAbstractItemModel发出dataChanged的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆