(swing读书笔记)Undo/Redo(上)
By cszhao1980
一.UndoableEdit系列
Undo、Redo是十分有用的功能,Swing提供了一组类来协助用户完成Undo、Redo功能。
1.1 UndoableEdit
首先是执行Undo、Redo操作功能的类——“UndoableEdit <--------AbstractUndoableEdit”。其中,UndoableEdit是接口,而AbstractUndoableEdit是Swing提供的简单实现该接口的类。
UndoableEdit中最重要的方法是undo()和redo()方法,分别完成undo、redo操作。显然,用户必须重新实现这两个方法——AbstractUndoableEdit(或其他的什么Swing预先提供的类)是不可能知道用户究竟要如何进行undo、redo操作的。需要注意的是,继承AbstractUndoableEdit(或其他)的类在实现undo()、redo()方法时,必须首先调用父类的同名方法。
通过UndoableEdit对象,就可以实现一级的Undo、Redo。通过记录每次的UndoableEdit对象,就能实现多级的Redo、Undo。
1.2 UndoableEditListener和UndoableEditEvent
显然,当用户执行了一个可undo的操作时,就需要通知它的观察者们,以使他们能够进行此次操作的Undo、Redo。观察者必须实现undoableEditListener接口。该接口仅有一个方法,public void undoableEditHappened(UndoableEditEvent e),而UndoableEditEvent.getEdit()会返回UndoableEdit对象。
1.3 UndoableEditSupport
UndoableEditSupport类是Swing提供的,供undoableEdit对象维护其观察者名单的辅助类。它提供addUndoableEditListener()、reMoveUndoableEditListener()方法。容易理解,该类内部维护了一个观察者的List(vector),而且,它还提供了getUndoableEditListeners()方法来返回观察者数组。
前面提到,当UndoableEdit对象的状态发生变化时,必须通知观察者,而这一点也是通过UndoableEditSupport完成的——你必须调用UndoableEditSupport的postEdit(UndoableEdit e),才能进行消息传递。正如你所想象的那样,postEdit(UndoableEdit e)会使用UndoableEdit e参数生成一个UndoableEditEvent对象,并调用各个观察者的undoableEditHappened方法。
二.组合Undo、Redo
有时候,我们希望能够将“一系列的操作”一次Undo,Swing提供了继承自AbstractUndoableEdit的CompoundEdit类来完成这个功能。
CompoundEdit内部维护一个UndoableEdit
数组
(vector)——
它的
Undo
、
Redo
方法时
,
会
(
逆序
)
委托该数组的每一个元素完成
——
以此就完成了组合
Undo
、
Redo
。
addEdit
方法可以将一个UndoableEdit对象添加进来,作为组合的一部分。
boolean | addEdit(UndoableEdit anEdit) |
inProgress用来表示CompoundEdit对象是否还在“组合编辑”的过程中,isInProgress()方法会返回这个值——它将一直为true,直到调用CompoundEdit对象的end
()
方法。
顺便说一句,如果在调用了end
()
方法之前,调用redo()、undo()方法,会抛出异常。
CompoundEdit往往配合“普通”的UndoableEdit对象使用,当执行一次操作后,CompoundEdit 对象(可以自己实现Listener接口,也可以有Listener委托)捕获“普通”的UndoableEdit对象的UndoableEditEvent消息,将其Add进来,作为组合的一部分。
三.更好的工具——UndoManager
使用CompoundEdit似乎还不是那么方便,比如:
(1) 我们必须自己实现UndoableEditListener接口,以截获UndoableEditEvent对象,然后调用CompoundEdit.AddEdit(UndoableEdit a)将其加入组合;
(2)
CompoundEdit对象本身也有一些问题,比如,只有在调用end
()
方法后
,
才能进行
redo()
、
undo()
操作,否则会抛出异常。
Swing
的设计者们看到了这一点,于是提供了一个更好的工具——UndoManager。UndoManager继承自
CompoundEdit,不仅如此,它还实现了UndoableEditListener接口,自动进行addEdit()操作。
不仅如此,UndoManager
在调用
end
()
方法之前
,
也可以进行
redo()
、
undo()
操作——只进行last UndoableEdit对象的操作。而一旦调用了
end
()
方法,
UndoManager
就可以进行组合redo()
、
undo()
操作了——其实就是连续的Redo、Undo的能力。
UndoManager
是个很好用的接口,我们可以直接使用它;也可以扩展它——多数情况下,是为它添加一个装饰者。