(swing读书笔记)Undo/Redo(上)

来源:互联网 发布:qq群文件件网络不可用 编辑:程序博客网 时间:2024/05/17 08:05

(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)——它的UndoRedo方法时逆序委托该数组的每一个元素完成——以此就完成了组合UndoRedo

 

addEdit方法可以将一个UndoableEdit对象添加进来,作为组合的一部分。

 boolean

addEdit(UndoableEdit anEdit)
          如果此编辑为 inProgress,则接受 anEdit 并返回 true。

 

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是个很好用的接口,我们可以直接使用它;也可以扩展它——多数情况下,是为它添加一个装饰者。