您的位置:首页 > 其它

Undo/Redo的使用,以及用命令模式实现Undo/Redo无限制

2008-08-06 17:18 986 查看
import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.net.*;

import java.applet.*;

import java.util.LinkedList;

import java.util.Iterator;

import javax.swing.*;

import javax.swing.undo.*;

/**

* A very simple applet demonstrating usage of javax.swing.undo package.

*/

public class undomgrtest extends JApplet {

JButton linebutton;

JButton circlebutton;

JButton undobutton;

JButton redobutton;

JPanel buttonpanel;

JGraphPanel graphpanel;

LineListener linelistener;

CircleListener circlelistener;

UndoListener undolistener;

RedoListener redolistener;

LinkedList shapes;

UndoManager undomgr;

public void init() {

// Force SwingApplet to come up in the System L&F

String laf = UIManager.getSystemLookAndFeelClassName();

try {

UIManager.setLookAndFeel(laf);

// If you want the Cross Platform L&F instead, comment out the above line and

// uncomment the following:

// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

} catch (UnsupportedLookAndFeelException exc) {

System.err.println("Warning: UnsupportedLookAndFeel: " + laf);

} catch (Exception exc) {

System.err.println("Error loading " + laf + ": " + exc);

}

getContentPane().setLayout(new BorderLayout());

linebutton = new JButton("Draw Line");

circlebutton = new JButton("Draw Circle");

undobutton = new JButton("Undo");

redobutton = new JButton("Redo");

graphpanel = new JGraphPanel(false);

graphpanel.setPreferredSize(new Dimension(300, 300));

buttonpanel = new JPanel(false);

buttonpanel.setLayout(new FlowLayout());

buttonpanel.add(linebutton);

buttonpanel.add(circlebutton);

buttonpanel.add(undobutton);

buttonpanel.add(redobutton);

getContentPane().add(buttonpanel, BorderLayout.SOUTH);

getContentPane().add(graphpanel, BorderLayout.NORTH);

linelistener = new LineListener();

linebutton.addActionListener(linelistener);

circlelistener = new CircleListener();

circlebutton.addActionListener(circlelistener);

undolistener = new UndoListener();

undobutton.addActionListener(undolistener);

redolistener = new RedoListener();

redobutton.addActionListener(redolistener);

shapes = new LinkedList();

undomgr = new UndoManager();

}

public void stop() {

}

class JGraphPanel extends JPanel {

public JGraphPanel(boolean doublebuffer) {

super(doublebuffer);

}

public void paintComponent(Graphics g) {

Graphics2D g2 = (Graphics2D) g;

g2.setColor(Color.white);

g2.fill3DRect(0, 0, getWidth(), getHeight(), true);

Iterator it;

Shape shape;

g2.setColor(Color.black);

for (it = shapes.iterator(); it.hasNext();) {

shape = (Shape) it.next();

g2.draw(shape);

}

}

}

class LineListener implements ActionListener {

Shape temp;

public void actionPerformed(ActionEvent e) {

temp = new Line2D.Double(0.0, 0.0, Math.random() * 100.0, Math

.random() * 100.0);

shapes.add(temp);

repaint();

UndoableEdit edit = new graphEdit(temp);

undomgr.addEdit(edit);

}

}

class CircleListener implements ActionListener {

Shape temp;

public void actionPerformed(ActionEvent e) {

temp = new Ellipse2D.Double(0.0, 0.0, Math.random() * 100.0, Math

.random() * 100.0);

shapes.add(temp);

repaint();

UndoableEdit edit = new graphEdit(temp);

undomgr.addEdit(edit);

}

}

class UndoListener implements ActionListener {

public void actionPerformed(ActionEvent e) {

try {

undomgr.undo();

} catch (CannotUndoException ex) {

System.err.println("Can't Undo More");

}

}

}

class RedoListener implements ActionListener {

public void actionPerformed(ActionEvent e) {

try {

undomgr.redo();

} catch (CannotRedoException ex) {

System.err.println("Can't Redo More");

}

}

}

class graphEdit extends AbstractUndoableEdit {

Shape shape;

public graphEdit(Shape _shape) {

shape = _shape;

}

public void undo() {

shapes.remove(shape);

repaint();

System.out.println("undo draw line");

}

public void redo() {

shapes.add(shape);

repaint();

System.out.println("redo draw line");

}

}

}

利用Command模式实现无限次数的Undo/Redo功能- -

几乎现在所有的文档式应用程序中,都提供了恢复/撤消功能,如Word,Excel,还有我们的写Java程序用的JBuilder。

在早期,许多的应用程序还只能提供单一的Undo/Redo,自进入90年代以来,随着OOP及Design Pattern的流行,实现无限次数的Undo/Redo编辑功能已不是难事。

每一个编辑动作我们可以把它当成一个命令,如cut,del等,在做每一个编辑动作前,我们先要保存旧的数据,以便于undo它。我们为这些编辑命令设计了如下一个通用接口:

public Interface Command

{

public void execute(); 

public void undo();

}

其中execute用来执行命令,undo用来恢复(undo).

接下来实现这个接口,先来实现Cut命令:

public class CutCommand implements Command

{

public void execute()

{

/* 备份旧数据 */

/* 剪切 */

}

public void undo()

{

/* 还原成备份的数据 */

}

}

再来实现一个Delete命令:

public class DeleteCommand implements Command

{

public void execute()

{

/* 备份旧数据 */

/* 删除 */

}

public void undo()

{

/* 还原成备份的数据 */

}

}

OK,我们就只列出了cut和del两个命令,其它的命令相似的写法.

这样的话我们每做一个编辑动作,就执行一个相应的command.接下来我们要考虑如何将这些执行过的命令保存下来,以实现undo/redo. 我们再设计一个CommandManager:

public Interface CommandManager

{

public void storeCommand(Command cmd);

public void clearAllCommand();

public void undo();

public void redo();

}

再来实现一个CommandManager, 我们称作CommandHistoryManager:

public class CommandHistoryManager implements CommandManager

{

Vector undoList=new Vector();

Vector redoList=new Vector();

public void storeCommand(Command cmd)

{

undoList.add(cmd);

}

public void clearAllCommand()

{

undoList.clear();

redoList.clear();

}

public void undo()

{

if ( undoList.size() <= 0 ) return;

Command cmd = ((Command)(undoList.get(undoList.size()-1)));

cmd.undo();

undoList.remove(cmd);

redoList.add(cmd);

}

public void redo()

{

if ( redoList.size() <= 0 ) return;

Command cmd = ((Command)(redoList.get(redoList.size()-1)));

cmd.execute();

redoList.remove(cmd);

undoList.add(cmd);

}

}

通过storeCommand()方法,每次执行的command就可以保存到undoList中,假设再在我们在程序中放置了两个按钮,一个undo,一个redo.按下undo按钮,就执行CommandHistoryManager的undo()方法,undo()方法会调用undoList中保存的最后一个command的undo()方法,并将这个command再放到redoList中,最后从undoList中删除这个命令。这时如果再按redo按钮,它会调用CommandHistoryManager中的redo()方法。redo()方法会调用redoList中保存的最后一个command的execute()方法,并将这个command又存回到undoList中。这样就实现了无限次数的undo/redo功能。

利用Command模式实现无限次数的Undo/Redo功能- -

几乎现在所有的文档式应用程序中,都提供了恢复/撤消功能,如Word,Excel,还有我们的写Java程序用的JBuilder。

在早期,许多的应用程序还只能提供单一的Undo/Redo,自进入90年代以来,随着OOP及Design Pattern的流行,实现无限次数的Undo/Redo编辑功能已不是难事。

每一个编辑动作我们可以把它当成一个命令,如cut,del等,在做每一个编辑动作前,我们先要保存旧的数据,以便于undo它。我们为这些编辑命令设计了如下一个通用接口:

public Interface Command

{

public void execute(); 

public void undo();

}

其中execute用来执行命令,undo用来恢复(undo).

接下来实现这个接口,先来实现Cut命令:

public class CutCommand implements Command

{

public void execute()

{

/* 备份旧数据 */

/* 剪切 */

}

public void undo()

{

/* 还原成备份的数据 */

}

}

再来实现一个Delete命令:

public class DeleteCommand implements Command

{

public void execute()

{

/* 备份旧数据 */

/* 删除 */

}

public void undo()

{

/* 还原成备份的数据 */

}

}

OK,我们就只列出了cut和del两个命令,其它的命令相似的写法.

这样的话我们每做一个编辑动作,就执行一个相应的command.接下来我们要考虑如何将这些执行过的命令保存下来,以实现undo/redo. 我们再设计一个CommandManager:

public Interface CommandManager

{

public void storeCommand(Command cmd);

public void clearAllCommand();

public void undo();

public void redo();

}

再来实现一个CommandManager, 我们称作CommandHistoryManager:

public class CommandHistoryManager implements CommandManager

{

Vector undoList=new Vector();

Vector redoList=new Vector();

public void storeCommand(Command cmd)

{

undoList.add(cmd);

}

public void clearAllCommand()

{

undoList.clear();

redoList.clear();

}

public void undo()

{

if ( undoList.size() <= 0 ) return;

Command cmd = ((Command)(undoList.get(undoList.size()-1)));

cmd.undo();

undoList.remove(cmd);

redoList.add(cmd);

}

public void redo()

{

if ( redoList.size() <= 0 ) return;

Command cmd = ((Command)(redoList.get(redoList.size()-1)));

cmd.execute();

redoList.remove(cmd);

undoList.add(cmd);

}

}

通过storeCommand()方法,每次执行的command就可以保存到undoList中,假设再在我们在程序中放置了两个按钮,一个undo,一个redo.按下undo按钮,就执行CommandHistoryManager的undo()方法,undo()方法会调用undoList中保存的最后一个command的undo()方法,并将这个command再放到redoList中,最后从undoList中删除这个命令。这时如果再按redo按钮,它会调用CommandHistoryManager中的redo()方法。redo()方法会调用redoList中保存的最后一个command的execute()方法,并将这个command又存回到undoList中。这样就实现了无限次数的undo/redo功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: