I would like to implement undo/redo in a small paint application. It seems the Command Pattern fits the use nicely, but I am unsure how to best implement it.
As I understand the pattern, it is necessary to include in each command:
GeneralPath
)My understanding based on that is that each command needs to be 'atomic' or self contained, with all the information needed for undo/redo that operation.
Unfortunately that would require storing more information than I'd first anticipated. For a line we must also account for things like the Color
, Stroke
and RenderingHints
used to draw it initially. This turns my 'simple little commands' into something ..more bulky in memory, and with more boiler-plate code to churn out (each will be a serializable bean1).
For reasons of memory conservation (mostly) I was wanting to 'cheat' on the specification of the commands. Perhaps take a backup of the entire drawing area every 100th update, but otherwise store no part of the changed image, and simply rebuild the last (up to) 100 commands for each new paint operation. But that seems problematic to ensure that the state of the Graphics
object is right before painting each part - this part might require a line, but the RenderingHints
were changed 4 commands ago, the Color
was changed 98 commands ago, while the Stroke
has remained the same for the last 227 commands.
Pursuing a more memory efficient command seems to throw the pattern right out the window in terms of being 'atomic'. That in turn leads to difficulties in determining the earliest command that might affect the rendering.
Should I:
Graphics2D
(which neatly encapsulates many parameters used when drawing) is not serializable. Further, a BasicStroke
is serializable, but the thickness of the stroke is not stored. I could create serializable versions of many of the attributes but it seems to make for a lot more code, so I'm going to abandon that spec. as well. I will only attempt to store a reference to a BufferedImage
at run-time.I would stick with command pattern and first try a naive solution (=the most memory-hungry). For some graphical operations it may be even necessary to keep a copy of the entire image in the command object (eg. think of filters). This is a common problem also in professional image editing applications, they often have a memory or step limit of last commands that are remembered. And if the memory consumption is really large you may think of swapping the oldest entries in command-history to file system. I think user will not mind waiting a second until the change is undone.
Maybe, it would be better not to store copy of entire image in command, but store only copy of area, which is changing by command. Of course, this is not a panacea
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With