我正在尝试创建一个 QUndoCommand
的子类,它表示一个或多个 QGraphicsItem
的移动。如果一次移动多个项目(首先选择它们),这应该表示为 QUndoStack
中的单个命令。
由于整个移动逻辑(包括选择)已经由 QGraphicsScene
实现,我不确定创建撤消命令的最佳位置。
Qt提供的undoframework
实例子类QGraphicsScene
并覆盖mousePressEvent()
/mouseReleaseEvent()
来执行一些手动 HitTest 。这真的是要走的路吗?
恐怕这种方法可能会遗漏一些特殊情况,例如生成的撤消命令不会完全反射(reflect)内部 Qt 实现所执行的相同 Action 。例如,某些项目可能未设置 ItemIsMovable
标志。此外,当一次移动多个项目时,最好只存储增量移动而不是新旧位置。
如果您能提供一些简短的示例代码/草图以进行说明,那就太好了。
最佳答案
我个人会包装和封装 QGraphicsScene
并在那里实现撤消/重做。这允许定义您自己的和更清晰的界面,摆脱所有您不需要的功能的困惑。如果将来出现这种需要,它还可以更轻松地用另一个 API 替换 QGraphicsScene
,并使您的核心内容更具可移植性。
Qt 中的许多高级类,尤其是那些用于图形的类,并不完全是我所说的“前沿”,这同样适用于 Qt 为它们提供的基本示例。有几个使用 Qt 的专业图形应用程序,但没有一个使用像 QGraphicsScene
这样的东西。我想这样做的原因也是我根据自己使用 Qt 的经验推断的原因——尽管它可能是一个框架,但有很多东西缺失了,而且很多东西并没有真正发挥作用人们对专业软件的期望方式,甚至是此类工作流程中的通用逻辑。 Qt 是由非常优秀的程序员开发的,但他们似乎没有在实际图形应用程序工作流程方面有经验的人来指导他们。
专注于具有所需功能的包装器,并使其与 QGraphicsScene
一起使用,而不是直接使用它。这样你就不太可能错过一些东西,你的设计也更加独立和干净。这同样适用于撤消 API,不要觉得必须使用 Qt,我自己已经尝试过并最终实现了我自己的,因为我发现 Qt 提供的那个相当“僵硬”。
在一次移动多个项目的情况下 - 是的,这应该创建一个撤消条目,它将撤消选择组的移动,该选择组将包含所有选定的项目。您是使用增量还是头寸 - 这完全取决于您。当您移动多个选定项目时,delta 确实更有意义,因为选择组并不是真正具有位置的项目。
另一个考虑因素是,如果您计划让历史在不同的 session 中保持持久 - 您不能依赖指针,因为每次运行应用程序时它们都是任意的。我的策略是实现一个唯一的整数 ID 和一个存储每个项目的 ID 和指针的关联注册表。然后您使用历史记录的 ID,这将在内部映射到实际项目的指针。
关于c++ - QGraphicsScene : How to map item movements into QUndoCommand?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32973326/