撤消绘画程序 [英] Undo for a paint program

查看:223
本文介绍了撤消绘画程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究如何写一个油漆程序,支持撤消和看到,很可能,一个命令模式是我想要的。有些事情仍然逃脱我,虽然,我希望有人可以提供一个简单的回答或确认。

I am looking into how to write a paint program that supports undo and seeing that, most likely, a command pattern is what I want. Something still escapes me, though, and I'm hoping someone can provide a simple answer or confirmation.

基本上,如果我要实现撤消命令的能力,例如在屏幕上标记一个实心圆,这是否意味着我需要将该圆所覆盖的帧缓冲区复制到该命令对象中?我没有看到任何其他方式可以撤消可能是什么,例如,冲压在一堆随机像素颜色。

Basically, if I am to embody the ability to undo a command, for instance stamping a solid circle on the screen, does this mean I need to essentially copy the frame buffer that the circle covers into memory, into this command object? I don't see any other way of being able to undo what might be, for instance, stamping over a bunch of random pixel colors.

我听说了一个方法只是跟踪前进动作,当执行撤消时,您只需从步骤1开始,并前进到撤消之前的步骤,但如果您要支持大型撤消堆栈,这似乎是不可行的。

I've heard that one approach is just to keep track of the forward actions and when an undo is performed, you simply start from step 1 and draw forwards to the step before the undo, but this seems unfeasible if you are to support a large undo stack.

也许解决方案是在你保存每15-20个动作的位图,从最后的保存转发开始。

Perhaps the solution is something in between where you keep a bitmap of every 15-20 actions and start from the last 'save' forwards.

有人可以提供任何洞察,在这种情况下,典型的接受的方法是,在命令中保存缓冲区矩形,重做每个动作转发,还是我一直错过的东西?

Can someone provide any insight on what is the typical accepted approach in this case, either saving buffer rectangles in the commands, redo-ing every action forwards, or something I've altogether missed?

更新:大量的好回答。感谢大家。我想从我正在读,我将通过保存缓冲区每N个动作,当用户发出一个撤消命令重做所有命令从最近保存的缓冲区。我可以调整N到尽可能高的值,不显着地淹没了需要响应的撤消的用户体验(为了最小化内存使用),但我怀疑没有真正知道在这一点上,我应该能够在一帧中执行相当多的动作,使得这不是太糟糕。希望这个方法让我快速确定是否转向另一个方向,而不是保存位图矩形为以前的状态为需要它的行动。

Update: Plenty of good responses. Thanks, everyone. I'm thinking from what I'm reading that I will approach this by saving out the buffer every N actions and when the user issues an undo command redo all commands from the most recent saved buffer. I can tweak N to as high a value as possible that doesn't noticeably bog down the user experience of needing responsive undo (in order to minimize memory usage), but I suspect without really knowing for sure at this point, that I should be able to get away with performing quite a few actions in one frame such that this isn't too bad. Hopefully this approach will let me quickly determine whether to turn the other direction and instead go with saving bitmap rects for the previous states for actions that require it.

推荐答案

首先,要小心过度设计:如果你的应用程序不复杂,你的图片很小,你可能会发现只是存储一切快速,便宜和可行。但假设不是这样:

First, beware overdesign: if your app isn't complex and your images small, you may find 'just store everything' to be quick, cheap and feasible. But assuming that's not so:

你是正确的,从每个撤消的第1步重新绘制整个画布是不可行的;除非你的绘图程序很简单,一些操作只需要太长时间。另外,无限的撤消缓冲区可能不被调用(并且可能非常消耗空间来存储)。

You are correct that it is not feasible to redraw the entire canvas from step 1 forward for each undo; unless your paint program is very simple some operations simply take too long. Also, an infinite undo buffer is probably not called for (and could be very space-consuming to store).

如果你的艺术节目很复杂,用混合方法,来处理各种操作。每隔一段时间保存帧缓冲区(你建议的每15-20个命令似乎就OK了;我可以从10开始,一旦我工作了就调整),并从上次保存开始。但是不要让每15个操作变得僵硬,因为很可能有一些额外的经验法则会让用户看起来更流畅。

If your art program is complex, I'd actually start with a hybrid approach, to deal with the variety of operations. Save frame buffer every so often (the every 15-20 commands you suggest seems OK; I might start with 10 and adjust once I had it working) and go forward from last save. But don't make the 'every 15 operations' rigid, because it is likely that a few extra rules of thumb would make it seem much more fluid to the user.

例如,一些耗时或棘手到逆向操作可能总是创建一个新的保存点:

- 任何画布调整大小(裁剪等)

- 任何保存。 (我刚刚保存是用户可能还原的地方。)

- 任何非常耗时的操作都应在之后创建新的保存点 ,不是之前,操作;即它应该标记下一个操作以保存缓冲区以撤消。 (为什么?如果操作需要30秒,您不要希望每个撤消在堆栈中后接一个额外的30秒以上。)

- 相反,任何操作具有容易执行的数学负数,或者是自反转的(例如光子负载的)不需要费心保存帧缓冲,并且不应计入下一次保存。

For example, some time-consuming or tricky-to-reverse operations could always create a new save point:
- Any canvas resize (crop etc.)
- Any save. ("I just saved" is a very likely place for the user to undo back to.)
- Any operation which is extremely time-consuming should create a new save point after, not before, the operation; i.e. it should flag the next operation to save the buffer to undo. (Why? If the op takes 30 seconds, you don't want every undo in the stack afterwards to take an extra 30+ seconds.)
- Conversely, any operation which has an easily performed mathematical negative, or is self-inverting (like photonegative) need never bother to save frame buffer, and shouldn't count towards the next save.

这就抛弃了层的问题;如果你的程序有它们显然足以保存只有那些更改的层。

All of this leaves out the question of layers; if your program has them it's obviously sufficient to save only those layers that change.

绝对是我最高优先级的建议:无论你使用什么方法,你应该总是保存帧缓冲区用于执行的最近的操作。 糟糕,并不意味着是撤消的最可能的原因,所以你总是想要撤消一步到响应。如果不是您要保存的命令,您可以在下一个命令执行后丢弃此缓冲区。

Definitely my highest-priority suggestion though: regardless of what method you use, you should always save frame buffer for the most recent operation performed. "Whoops, didn't mean that" is the most likely reason for undo, so you always want undo-one-step to be responsive. You can discard this buffer after the next command execution if it's not one you're keeping.

您还需要考虑什么构成一个原子撤消操作。 (例如,是一组笔画与单个画笔工具一个操作还是多个?两者都有优点和缺点。)

You'll also need to consider what constitutes one atomic undo operation. (For example, is a set of strokes with a single brush tool one operation or many? Both have advantages and drawbacks.)

这篇关于撤消绘画程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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