简体   繁体   English

QGraphicsScene:如何将项目移动映射到QUndoCommand?

[英]QGraphicsScene: How to map item movements into QUndoCommand?

I'm trying to create a subclass of QUndoCommand that represents a movement of one or more QGraphicsItem . 我试图创建一个表示一个或多个QGraphicsItem运动的QUndoCommand的子类。 If several items are moved at once (by selecting them first), this should be represented as a single command within the QUndoStack . 如果一次移动多个项目(首先选择它们),则应在QUndoStack其表示为单个命令。

Since the whole movement logic (including selections) is already implemented by QGraphicsScene , I'm not sure what would be the best place to create the undo commands. 由于整个运动逻辑(包括选择)已经由QGraphicsScene实现,所以我不确定创建撤消命令的最佳位置是什么。

The undoframework example provided by Qt subclasses QGraphicsScene and overrides mousePressEvent() / mouseReleaseEvent() to perform some manual hit testing. Qt提供的undoframework示例将QGraphicsScene子类化,并重写mousePressEvent() / mouseReleaseEvent()来执行一些手动命中测试。 Is this really the way to go? 这真的是要走的路吗?

I'm afraid that this approach could miss some special cases such that the generated undo commands do not reflect exactly the same movement that has been performed by the internal Qt implementation. 恐怕这种方法可能会遗漏一些特殊情况,以至于生成的撤消命令不会反映出内部Qt实现所执行的完全相同的移动。 Some items could have the ItemIsMovable flag unset for example. 例如,某些项目可能ItemIsMovable设置ItemIsMovable标志。 Also, when moving multiple items at once, it seems better to store just the delta movement instead of old and new position. 另外,一次移动多个项目时,最好只存储增量运动,而不要存储新旧位置。

It would be great if you could provide some short sample code/sketch for clarification. 如果您可以提供一些简短的示例代码/草图来进行说明,那就太好了。

I personally would wrap and encapsulate QGraphicsScene and implement the undo/redo stuff there. 我个人将包装QGraphicsScene并将其封装并在那里实现撤消/重做。 This allows to define your own and cleaner interface, free of the clutter of all the functionality you won't need. 这使您可以定义自己的界面,使界面更加整洁,而无需使用所有不必要的功能。 It will also make it easier to replace QGraphicsScene with another API if such a need arises in the future and makes your core stuff more portable. 如果将来有这样的需求,它也将使用另一个API替换QGraphicsScene变得更加容易,并使您的核心内容更加可移植。

Many of the high level classes in Qt, especially those for graphics, are not exactly what I'd call "cutting edge", the same applies even more so to the rudimentary examples Qt provides for them. Qt中的许多高级类,尤其是图形类,并不是我所谓的“尖端”,这同样适用于Qt为它们提供的基本示例。 There are several professional graphics applications that use Qt, but none of them uses stuff like QGraphicsScene . 有一些使用Qt的专业图形应用程序,但是没有一个使用QGraphicsScene东西。 I suppose the reason for this is also the reason I extrapolated from my own experience using Qt - as big as a framework it may be, there is a lot of stuff that's missing, and a lot of stuff that just doesn't really work the way people have come to expect from professional software, or even common logic in such workflows. 我想这也是我从自己使用Qt的经验中推断出来的原因-可能与框架一样大,缺少很多东西,而很多东西实际上并没有起作用。人们对专业软件甚至是此类工作流程中的通用逻辑的期望。 Qt was developed by very good programmers, but it seems like they didn't have someone experienced in the actual graphics applications workflow to advise them. Qt是由非常优秀的程序员开发的,但是似乎他们没有在实际图形应用工作流程中经验丰富的人员来为他们提供建议。

Focus on a wrapper that features the functionality you need, and make it work with QGraphicsScene instead of using it directly. 将重点放在具有所需功能的包装器上,并使它与QGraphicsScene使用,而不是直接使用它。 This way there is less chance that you miss something, your design is more self contained and cleaner too. 这样,您错过某些东西的机会就更少了,您的设计也更加自给自足并且更加干净。 The same applies to the undo API as well, don't feel obligated to use Qt's, I myself have tried it and ended up implementing my own, as I found the one provided by Qt was rather "stiff". 撤消API也是如此,不要觉得有义务使用Qt,我自己也尝试过并最终实现了自己的,因为我发现Qt提供的功能相当“僵硬”。

In the case of moving several items at once - yes, that should create a single undo entry, which will undo the moving of a selection group, which will feature all the selected items. 在一次移动多个项目的情况下-是的,应该创建一个撤消条目,这将撤消选择组的移动,该组将具有所有选中的项目。 Whether you will use a delta or position - it is entirely up to you. 是否使用增量或头寸-完全取决于您。 The delta does make a little more sense when you move multiple selected items, since the selection group is not really an item with position. 当您移动多个选定项目时,增量确实更有意义,因为选择组实际上并不是具有位置的项目。

Another consideration, if you plan on making history persistent across different sessions - you can't rely on pointers, since those will be arbitrary each time you run your application. 另一个考虑因素是,如果计划使历史记录在不同的会话之间保持不变-您就不能依赖指针,因为每次运行应用程序时指针都是任意的。 My strategy is to implement a unique integer ID and an associative registry which stores the id and pointer for each item. 我的策略是实现一个唯一的整数ID和一个关联注册表,该注册表存储每个项目的ID和指针。 Then you use the ID for the history, and that will internally map to the pointer of the actual item. 然后,您将ID用于历史记录,并将在内部映射到实际项目的指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM