我正在编写一个画家程序,我想在其中实现基本操作的撤消和重做,如绘制线条,绘制椭圆等。
有没有好的方法呢?一项操作应包含哪些属性?
修改
实际上我知道Command模式,但我想弄清楚的是,应该在Command对象中记录哪些数据,以便完成撤消。
答案 0 :(得分:5)
因此,在光栅应用程序中撤消/重做有点棘手。
首先,花25分钟观看this talk(通过@chris)。它可能会让你大吃一惊,而且速度很快。然后继续阅读。
最简单的方法是在每次操作之前简单地制作光栅画布的副本。将这些列表存储在撤消/重做缓冲区中,您可以愉快地前进和后退。 (您可能还想存储工具状态)。
这样做的缺点是它庞大且昂贵。有很多方法可以缓解这种情况。
首先,您可以平铺图像(无论如何),并使用copy-on-write。现在,未修改的切片将通过撤消列表共享。
其次,而不是完整的栅格,记录重新创建效果所需的参数。只要你有一个合理的附近(在重建时间方面)"之前"你可以重建的图像,这可能非常快。
第三,记录"擦除"所需的信息和信息。效果。这有时比您触摸的所有图块的副本便宜(并且您触摸的所有图块的副本是实现此目的的一种方式)。
您可以将撤消/重做堆叠与此混合。对于可重构的舞台,您需要光栅副本或先前的光栅副本以及一组可以重复以重新生成它的前向操作,或者将来的光栅副本和一组向后操作可以重复以重新生成它
除此之外,您还可以将所述撤消信息推出内存并将其保存到磁盘。
在某些情况下,您还希望能够将多个步骤折叠为一个撤消/重做步骤。这可以让你保持细粒度的撤销/重做操作"最近",同时仍然能够一直撤消到"你打开文件"。
通常,您关心从当前步骤到达撤消/重做步骤(这意味着您只需要重做步骤的向前差异信息,向后撤销),但这会增加管理撤消/重做堆栈的复杂性(有时候更容易存储两种方法。
还有一个问题是"您是否要在保存文件时保存撤消/重做操作数据"或不(它是否可序列化?)。您想支持撤消/重做树还是仅支持线性历史记录? (即,如果你撤消3次,然后绘制一个像素,你是否能够"回到原始历史记录中,或者是否被像素绘制破坏了?)
然而,实际上你从画布的简单光栅副本开始。这是必须测量任何其他实现的标准,因此对于单元测试目的而言,#34;完整的光栅"无论如何都需要撤消/重做功能。添加"在撤消/重做上花费的总内存"设置和磁盘序列化(以及"撤消/重做&#34上的总磁盘空间;)和下一个折叠规则(因为这些是简单的步骤)。然后平铺光栅图像并实现写入时复制图块,您的效率将达到90%。
之后,开始担心为某些工具进行优化的撤消/重做,以便大规模打击基于图块的栅格信息。
现在,回到帖子开头的视频。再看一遍。使用暂停可在每个代码点停止视频。自己输入代码。试着理解你写的是什么。如果你不理解你写的是什么,那就去了解它。你将成为一个更好的程序员,如果你在谈话结束时,你将编写一个更强大的撤销/重做更好的光栅绘画应用程序。
该实现的基础是文档数据的写入类型擦除系统的副本,使用类型擦除来允许值语义。它没有立即推广到文档模型,但即使您所做的唯一事情就是为您的tile系统使用类似的东西(使用use_count()==1
导致您打破const
以进行copy-on-write)你将领先于比赛。
答案 1 :(得分:2)
您可以使用Memento模式来实现撤消/重做:
memento模式是一种软件设计模式,提供了 将对象恢复到先前状态的能力(撤消通过 回滚)。
memento模式用三个对象实现:发起者, 看守和纪念品。发起者是一个具有的对象 内部国家。看护人将要做的事情 发起人,但希望能够撤消变更。看守 首先向发起人询问纪念品。然后它做任何事情 它将要做的操作(或操作顺序)。回滚 在操作之前的状态,它返回memento对象 发起人。纪念品对象本身是一个不透明的对象(一个 看护人不能或不应该改变)。使用时 模式,如果发端人可以改变其他方式,应该小心 对象或资源 - 纪念品模式在一个单一的上运作 对象
答案 2 :(得分:0)
您应该阅读有关命令设计模式http://en.wikipedia.org/wiki/Command_pattern的信息 - 这正是您实现多级撤消所需的。基本上你不直接执行修改,但是你创建了实现Do()和Undo()方法的对象。然后很容易在一个地方实现代码生成和撤消更改。您可以创建一个对象,调用其Do()方法,然后将其添加到撤消队列,而不是更改内容。然后,对于撤消,您可以在队列中的对象中调用Undo()方法。
答案 3 :(得分:0)
我执行此操作的方法是让每个操作在操作的开始和结束时调用撤消管理器(用于簿记),然后在绘制它时#34;检查"或者要求对矩形像素范围(通常为128x128或256x256像素的图块)进行写访问。撤消管理器制作原始像素的副本,并用修改后的像素替换活动副本。然后在撤消时它会替换原来的背面,并在重做时替换修改后的背面。使用磁贴是跟踪单个像素和每次操作备份整个图像之间的良好中间点。