packageundoRedo;
importjava.awt.Frame;
import java.awt.event.*;
public class MainFrame extendsFrame {
private staticUndoableTextArea text;
private staticItsukyuQuatation panel;
publicMainFrame(String title)
{
super(title);
}
public static voidmain(String[] args)
{
//构造可撤消的textArea
text = new UndoableTextArea("Your text here");
//构造panel
panel = newItsukyuQuatation(text);
//构造frame
MainFrame frame = new MainFrame("测试undo和redo");
//增加窗体关闭事件
frame.addWindowListener(newWindowAdapter()
{
public voidwindowClosing(WindowEvent e)
{
System.exit(0);
}
});
frame.add(panel);
frame.setSize(300,300);
frame.setVisible(true);
}
}
ItsukyuQuatation类:面板类,里面包括undo和redo两个按钮,类似于命令模式中的摇控器。实现了ActionListener接口。
packageundoRedo;
importjava.awt.BorderLayout;
importjava.awt.Panel;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
public class ItsukyuQuatation extends Panel implementsActionListener {
private finalCommand undo;
private finalCommand redo;
publicItsukyuQuatation(UndoableTextArea text)
{
this.setLayout(newBorderLayout());
Panel toolbar = newPanel();
undo = newUndoCommand(text);
redo = newRedoCommand(text);
undo.addActionListener(this);
redo.addActionListener(this);
toolbar.add(undo);
toolbar.add(redo);
this.add(toolbar,"North");
this.add(text,"Center");
}
public voidactionPerformed(ActionEvent e) {
//TODO Auto-generated method stub
Command cmd =(Command)e.getSource();
cmd.execute();
}
}
UndoableTextArea类:类似于命令模式中的电视机类。实现了StateEditable接口,因此该类具有可撤销和重做的功能。重载的storeState和restoreState即是把文本中的内容放到hashTable里去。
该类是最核心的类,实现ctrl+z的原理简单说就是UndoManger.edits是一个Vector动态数组,对每次的按键动作,都会存储一份当前的文本内容到数据。当点击undo按钮,
数组索引(UnoManager类的indexOfNextAdd变量)前移一位,取得前一状态的文本内容。点击redo按钮,数组索引后移一位,取后一状态的文本内容。但是各状态内容均未删或修改。
initUndoable()方法,如果用keyPressed事件,那么最近的状态未加到undoManager.edits列里。因此选用keyReleased事件。如果监听valueChanged事件,那么代码就
和JAVA与模式一书中一样,只能实现最近一次的编辑撤消。
packageundoRedo;
importjava.awt.TextArea;
import java.awt.event.*;
importjava.util.Hashtable;
import javax.swing.undo.*;
importjavax.swing.undo.StateEditable;
public class UndoableTextArea extends TextArea implementsStateEditable {
privateUndoManager undoManager;
private final static String KEY_STATE="UndoableTextAreaKey";
privateStateEdit currentEdit;
boolean textChanged = false;
publicUndoableTextArea()
{
super();
initUndoable();
}
publicUndoableTextArea(String string)
{
super(string);
initUndoable();
}
//存储状态
public void storeState(HashtablehashTable) {
//TODO Auto-generated method stub
hashTable.put(KEY_STATE, this.getText());
}
//还原状态
public void restoreState(Hashtable, ?>hashTable) {
//TODO Auto-generated method stub
Object data =hashTable.get(KEY_STATE);
if(data!=null)
{
this.setText((String)data);
}
}
//撤销方法
public booleanundo()
{
try{
undoManager.undo();
System.out.println("undo=" +undoManager.toString());
return true;
}catch(CannotUndoException e)
{
System.out.println("Can't undo");
}
return false;
}
//重做方法
public booleanredo()
{
try{
undoManager.redo();
System.out.println("redo=" +undoManager.toString());
return true;
}catch(CannotRedoException e)
{
System.out.println("Can't redo");
}
return false;
}
private voidinitUndoable()
{
this.undoManager = newUndoManager();
this.currentEdit = new StateEdit(this);
this.addKeyListener(newKeyAdapter()
{
/**
* 如果用keyPressed事件,那么最近的状态未加到undoManager.edits列里。
* 因此选用keyReleased事件。
*
public void keyPressed(KeyEvent event)
{
if(event.isActionKey())
{
//takeSnapshot();
}else
{
textChanged = true;
takeSnapshot();
}
}
*/
public voidkeyReleased(KeyEvent event)
{
if(event.isActionKey())
{
//takeSnapshot();
}else{
textChanged = true;
takeSnapshot();
}
}
});
this.addFocusListener(newFocusAdapter()
{
public voidfocusLost(FocusEvent event)
{
//takeSnapshot();
}
});
}
private voidtakeSnapshot()
{
if(textChanged)
{
this.currentEdit.end();
this.undoManager.addEdit(this.currentEdit);
this.currentEdit = new StateEdit(this);
System.out.println("takeSnapshot=" +undoManager.toString());
textChanged = false;
}
}
}
Command抽象类:定义按钮,抽象方法 execute()
UndoCommand,RedoCommand均是Command类的实现,类似于命令模式中的具体按钮,调用接收者的方法进行实现。
packageundoRedo;
importjava.awt.Button;
public abstract class Command extendsButton {
publicCommand(String caption)
{
super(caption);
}
public abstract voidexecute();
}
packageundoRedo;
public class UndoCommand extendsCommand {
UndoableTextArea text;
publicUndoCommand(UndoableTextArea text)
{
super("Undo");
this.text =text;
}
@Override
public voidexecute() {
//TODO Auto-generated method stub
text.undo();
}
}
packageundoRedo;
public class RedoCommand extendsCommand {
UndoableTextArea text;
publicRedoCommand(UndoableTextArea text)
{
super("Redo");
this.text =text;
}
@Override
public voidexecute() {
//TODO Auto-generated method stub
text.redo();
}
}