使用 QAbstractItemModel (C++) 支持多重添加/删除(以及撤消/重做)

发布于 2024-08-11 03:20:35 字数 960 浏览 2 评论 0原文

您好,

我一直在编写一些令人讨厌的代码来支持从模型中删除任意一组对象的撤消/重做。我觉得我正在正确地处理这个问题,因为所有其他变异器(添加/复制粘贴)都是此功能的子集。

该代码比我需要的更糟糕,主要是因为改变模型的唯一方法涉及调用 beginInsertRows/beginRemoveRows 并删除某个范围内的行(一次只执行 1 行,无需将“邻居”优化为单个行) 。

beginInsertRows/beginRemoveRows 的问题是删除一行可能会影响另一个 QModelIndex(例如,缓存在列表中的一个) 例如:

ParentObj
   ->ChildObj1
   ->ChildObj2
   ->ChildObj3

假设我选择 ChildObj1 和 ChildObj3 并删除它们,如果我首先删除 ChildObj1,我会更改 ChildObj3 的 QModelIndex (行现在不同)。如果我删除父对象,也会出现类似的问题(但我已通过从对象列表中“修剪”子对象来解决此问题)。

以下是我想到的解决此接口限制的方法,但我想在继续前进之前我应该​​寻求更好的方法:

  1. “向后”移动,假设提供的 QModelIndices 列表是从上到下排序的从下往上走。这确实需要可靠的排序,并且排序可能会很幼稚且缓慢(也许有一种对 QModelIndexes 集合进行排序的聪明方法?或者 QItemSelectionModel 是否提供良好的(有序)列表?)

  2. 每次更新其他 QModelIndeces删除/添加一个对象(想不出一个非天真的解决方案,搜索列表,在需要的地方获取新的 QModelIndeces)

  3. 由于更新实际数据很容易,只需更新数据并重建模型即可。这看起来很奇怪,我可以想象它在处理大量数据时会变得相当慢。

这些是我目前的想法。我现在正在研究选项 1。

问候, 丹欧

Greetings,

I've been writing some nasty code to support the undo/redo of deletion of an arbitrary set of objects from my model. I feel like I'm going about this correctly, as all the other mutators (adding/copy-pasting) are subsets of this functionality.

The code is nastier than it needs to me, mostly because the only way to mutate the model involves calling beginInsertRows/beginRemoveRows and removing the rows in a range (just doing 1 row at a time, no need to optimize "neighbors" into a single call yet)

The problem with beginInsertRows/beginRemoveRows is that removal of a row could affect another QModelIndex (say, one cached in a list). For instance:

ParentObj
   ->ChildObj1
   ->ChildObj2
   ->ChildObj3

Say I select ChildObj1 and ChildObj3 and delete them, if I remove ChildObj1 first I've changed ChildObj3's QModelIndex (row is now different). Similar issues occur if I delete a parent object (but I've fixed this by "pruning" children from the list of objects).

Here are the ways I've thought of working around this interface limitation, but I thought I'd ask for a better one before forging ahead:

  1. Move "backwards", assuming a provided list of QModelIndices is orderered from top to bottom just go from bottom up. This really requires sorting to be reliable, and the sort would probably be something naive and slow (maybe there's a smart way of sorting a collection of QModelIndexes? Or does QItemSelectionModel provide good (ordered) lists?)

  2. Update other QModelIndeces each time an object is removed/added (can't think of a non-naive solution, search the list, get new QModelIndeces where needed)

  3. Since updating the actual data is easy, just update the data and rebuild the model. This seems grotesque, and I can imagine it getting quite slow with large sets of data.

Those are the ideas I've got currently. I'm working on option 1 right now.

Regards,
Dan O

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁月苍老的讽刺 2024-08-18 03:20:35

将 beginRemoveRows/endRemoveRows 等视为要求 QAbstractItemModel 基类为您修复持久模型索引的方法,而不仅仅是更新视图的方法,并尽量不要混淆 QAbstractItemModel 基类在这些索引上的工作。查看 http://labs.trolltech.com/page/Projects/Itemview/Modeltest< /a> 来练习您的模型并查看您是否使 QAbstractItemModel 基类保持满意。

如果您想将撤消/重做数据保留在模型之外,则 QPersistentModelIndex 没有帮助。我构建了一个经过大量编辑的模型,并且我不想尝试将所有内容保留在模型中。我将撤消/重做数据存储在撤消堆栈上。问题是,如果您编辑一列,将该列的持久索引存储在撤消堆栈上,然后删除保存该列的行,则该列的持久索引将变得无效。

我所做的是保留持久模型索引和“历史”常规 QModelIndex。当需要撤消/重做时,我检查持久索引是否已变得无效。如果有,我将历史 QModelIndex 传递给模型的一个特殊方法,要求它根据行、列和内部指针重新创建索引。由于我的所有编辑都位于撤消堆栈上,因此当我备份到撤消堆栈上的该列编辑时,该行肯定存在于模型中。我在内部指针中保留足够的状态来重新创建原始索引。

Think of beginRemoveRows/endRemoveRows, etc. as methods to ask the QAbstractItemModel base class to fix up your persistent model indexes for you instead of just a way of updating views, and try not to confuse the QAbstractItemModel base class in its work on those indexes. Check out http://labs.trolltech.com/page/Projects/Itemview/Modeltest to exercise your model and see if you are keeping the QAbstractItemModel base class happy.

Where QPersistentModelIndex does not help is if you want to keep your undo/redo data outside of the model. I built a model that is heavily edited, and I did not want to try keeping everything in the model. I store the undo/redo data on the undo stack. The problem is that if you edit a column, storing the persistent index of that column on the undo stack, and then delete the row holding that column, the column's persistent index becomes invalid.

What I do is keep both a persistent model index, and a "historical" regular QModelIndex. When it's time to undo/redo, I check if the persistent index has become invalid. If it has, I pass the historical QModelIndex to a special method of my model to ask it to recreate the index, based on the row, column, and internalPointer. Since all of my edits are on the undo stack, by the time I've backed up to that column edit on the undo stack, the row is sure to be there in the model. I keep enough state in the internalPointer to recreate the original index.

剑心龙吟 2024-08-18 03:20:35

我会考虑使用“全数据”模型和带有数据模型的过滤代理模型。数据只会添加到全数据模型中,而不会被删除。这样,您就可以通过引用该模型来存储撤消/重做信息。 (我可以建议QPersistentModelIndex吗?)。您的数据模型还可以以某种方式跟踪应该显示的内容。然后,过滤器模型将仅返回应在给定时间显示的项目的信息。

I would consider using a "all-data" model and a filter proxy model with the data model. Data would only be added to the all-data model, and never removed. That way, you could store your undo/redo information with references to that model. (May I suggest QPersistentModelIndex?). Your data model could also track what should be shown, somehow. The filter model would then only return information for the items that should be shown at a given time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文