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功能。
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功能。
相关文章推荐
- 使用设计模式实现Undo,Redo框架
- 设计模式——命令模式实现undo、redo
- 命令模式中Undo/Redo的实现原理和方法
- C++实现Undo和Redo框架(命令模式)
- 4.4 《硬啃设计模式》 第21章 神奇的Undo与Redo - 命令模式(Command Pattern)
- 通过例子学设计模式之--简单工厂模式以及使用场景说明(C++实现)
- 单例设计模式双判空实现以及使用volatile修饰instance讲解
- 用 Command设计模式实现 Undo和Redo 功能
- 装饰者模式---使用装饰者模式实现带日志记录功能的数据库命令执行类
- 通过例子学设计模式之--适配器模式以及使用场景说明(C++实现)
- Linux下使用crontab命令以及Python脚本实现自动签到
- 通过例子学设计模式之--外观模式以及使用场景说明(C++实现)
- Java枚举使用以及枚举实现单例模式
- Linux 使用init命令实现关机,重启,切换模式
- 设计模式-观察者模式,以及如何使用观察者来为app实现即时通讯功能
- Linux系统使用--定时关机的实现以及crontab命令和文件详解
- 六、从Undo,Redo谈命令模式
- 从Undo,Redo谈命令模式
- 使用Java来实现编辑器的Undo Redo功能
- 通过例子学设计模式之--抽象工厂模式以及使用场景说明(C++实现)