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

 
  1. import java.awt.*;
  2. import java.awt.event.*;
  3. import java.awt.geom.*;
  4. import java.net.*;
  5. import java.applet.*;
  6. import java.util.LinkedList;
  7. import java.util.Iterator;
  8. import javax.swing.*;
  9. import javax.swing.undo.*;
  10. /**
  11.  * A very simple applet demonstrating usage of javax.swing.undo package.
  12.  */
  13. public class undomgrtest extends JApplet {
  14.     JButton linebutton;
  15.     JButton circlebutton;
  16.     JButton undobutton;
  17.     JButton redobutton;
  18.     JPanel buttonpanel;
  19.     JGraphPanel graphpanel;
  20.     LineListener linelistener;
  21.     CircleListener circlelistener;
  22.     UndoListener undolistener;
  23.     RedoListener redolistener;
  24.     LinkedList shapes;
  25.     UndoManager undomgr;
  26.     public void init() {
  27.         // Force SwingApplet to come up in the System L&F
  28.         String laf = UIManager.getSystemLookAndFeelClassName();
  29.         try {
  30.             UIManager.setLookAndFeel(laf);
  31.             // If you want the Cross Platform L&F instead, comment out the above line and
  32.             // uncomment the following:
  33.             // UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
  34.         } catch (UnsupportedLookAndFeelException exc) {
  35.             System.err.println("Warning: UnsupportedLookAndFeel: " + laf);
  36.         } catch (Exception exc) {
  37.             System.err.println("Error loading " + laf + ": " + exc);
  38.         }
  39.         getContentPane().setLayout(new BorderLayout());
  40.         linebutton = new JButton("Draw Line");
  41.         circlebutton = new JButton("Draw Circle");
  42.         undobutton = new JButton("Undo");
  43.         redobutton = new JButton("Redo");
  44.         graphpanel = new JGraphPanel(false);
  45.         graphpanel.setPreferredSize(new Dimension(300300));
  46.         buttonpanel = new JPanel(false);
  47.         buttonpanel.setLayout(new FlowLayout());
  48.         buttonpanel.add(linebutton);
  49.         buttonpanel.add(circlebutton);
  50.         buttonpanel.add(undobutton);
  51.         buttonpanel.add(redobutton);
  52.         getContentPane().add(buttonpanel, BorderLayout.SOUTH);
  53.         getContentPane().add(graphpanel, BorderLayout.NORTH);
  54.         linelistener = new LineListener();
  55.         linebutton.addActionListener(linelistener);
  56.         circlelistener = new CircleListener();
  57.         circlebutton.addActionListener(circlelistener);
  58.         undolistener = new UndoListener();
  59.         undobutton.addActionListener(undolistener);
  60.         redolistener = new RedoListener();
  61.         redobutton.addActionListener(redolistener);
  62.         shapes = new LinkedList();
  63.         undomgr = new UndoManager();
  64.     }
  65.     public void stop() {
  66.     }
  67.     class JGraphPanel extends JPanel {
  68.         public JGraphPanel(boolean doublebuffer) {
  69.             super(doublebuffer);
  70.         }
  71.         public void paintComponent(Graphics g) {
  72.             Graphics2D g2 = (Graphics2D) g;
  73.             g2.setColor(Color.white);
  74.             g2.fill3DRect(00, getWidth(), getHeight(), true);
  75.             Iterator it;
  76.             Shape shape;
  77.             g2.setColor(Color.black);
  78.             for (it = shapes.iterator(); it.hasNext();) {
  79.                 shape = (Shape) it.next();
  80.                 g2.draw(shape);
  81.             }
  82.         }
  83.     }
  84.     class LineListener implements ActionListener {
  85.         Shape temp;
  86.         public void actionPerformed(ActionEvent e) {
  87.             temp = new Line2D.Double(0.00.0, Math.random() * 100.0, Math
  88.                     .random() * 100.0);
  89.             shapes.add(temp);
  90.             repaint();
  91.             UndoableEdit edit = new graphEdit(temp);
  92.             undomgr.addEdit(edit);
  93.         }
  94.     }
  95.     class CircleListener implements ActionListener {
  96.         Shape temp;
  97.         public void actionPerformed(ActionEvent e) {
  98.             temp = new Ellipse2D.Double(0.00.0, Math.random() * 100.0, Math
  99.                     .random() * 100.0);
  100.             shapes.add(temp);
  101.             repaint();
  102.             UndoableEdit edit = new graphEdit(temp);
  103.             undomgr.addEdit(edit);
  104.         }
  105.     }
  106.     class UndoListener implements ActionListener {
  107.         public void actionPerformed(ActionEvent e) {
  108.             try {
  109.                 undomgr.undo();
  110.             } catch (CannotUndoException ex) {
  111.                 System.err.println("Can't Undo More");
  112.             }
  113.         }
  114.     }
  115.     class RedoListener implements ActionListener {
  116.         public void actionPerformed(ActionEvent e) {
  117.             try {
  118.                 undomgr.redo();
  119.             } catch (CannotRedoException ex) {
  120.                 System.err.println("Can't Redo More");
  121.             }
  122.         }
  123.     }
  124.     class graphEdit extends AbstractUndoableEdit {
  125.         Shape shape;
  126.         public graphEdit(Shape _shape) {
  127.             shape = _shape;
  128.         }
  129.         public void undo() {
  130.             shapes.remove(shape);
  131.             repaint();
  132.             System.out.println("undo draw line");
  133.         }
  134.         public void redo() {
  135.             shapes.add(shape);
  136.             repaint();
  137.             System.out.println("redo draw line");
  138.         }
  139.     }
  140. }
  1. 利用Command模式实现无限次数的Undo/Redo功能- - 
  2. 几乎现在所有的文档式应用程序中,都提供了恢复/撤消功能,如Word,Excel,还有我们的写Java程序用的JBuilder。
  3. 在早期,许多的应用程序还只能提供单一的Undo/Redo,自进入90年代以来,随着OOP及Design Pattern的流行,实现无限次数的Undo/Redo编辑功能已不是难事。
  4. 每一个编辑动作我们可以把它当成一个命令,如cut,del等,在做每一个编辑动作前,我们先要保存旧的数据,以便于undo它。我们为这些编辑命令设计了如下一个通用接口:
  5. public Interface Command
  6. {
  7.     public void execute(); 
  8.     public void undo();
  9. }
  10. 其中execute用来执行命令,undo用来恢复(undo).
  11. 接下来实现这个接口,先来实现Cut命令:
  12. public class CutCommand implements Command
  13. {
  14.     public void execute()
  15.     {
  16.         /* 备份旧数据 */
  17.         /* 剪切 */
  18.     }
  19.     public void undo()
  20.     {
  21.          /*  还原成备份的数据  */
  22.     }
  23. }
  24. 再来实现一个Delete命令:
  25. public class DeleteCommand implements Command
  26. {
  27.     public void execute()
  28.     {
  29.         /* 备份旧数据 */
  30.         /* 删除 */
  31.     }
  32.     public void undo()
  33.     {
  34.          /*  还原成备份的数据  */
  35.     }
  36. }
  37. OK,我们就只列出了cut和del两个命令,其它的命令相似的写法.
  38. 这样的话我们每做一个编辑动作,就执行一个相应的command.接下来我们要考虑如何将这些执行过的命令保存下来,以实现undo/redo. 我们再设计一个CommandManager:
  39. public Interface CommandManager
  40. {
  41.     public void storeCommand(Command cmd);
  42.     public void clearAllCommand();
  43.     public void undo();
  44.     public void redo();
  45. }
  46. 再来实现一个CommandManager, 我们称作CommandHistoryManager:
  47. public class CommandHistoryManager implements CommandManager
  48. {
  49.  Vector undoList=new Vector();
  50.  Vector redoList=new Vector();
  51.  public void storeCommand(Command cmd)
  52.  {
  53.   undoList.add(cmd);
  54.  }
  55.  public void clearAllCommand()
  56.  {
  57.   undoList.clear();
  58.   redoList.clear();
  59.  }
  60.  public void undo()
  61.  {
  62.         if ( undoList.size() <= 0 ) return;
  63.         Command cmd = ((Command)(undoList.get(undoList.size()-1)));
  64.         cmd.undo();
  65.         undoList.remove(cmd);
  66.         redoList.add(cmd);
  67.  }
  68.  public void redo()
  69.  {
  70.         if ( redoList.size() <= 0 ) return;
  71.         Command cmd = ((Command)(redoList.get(redoList.size()-1)));
  72.         cmd.execute();
  73.         redoList.remove(cmd);
  74.         undoList.add(cmd);
  75.   
  76.  }
  77. }
  78. 通过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功能。
  1. 利用Command模式实现无限次数的Undo/Redo功能- - 
  2. 几乎现在所有的文档式应用程序中,都提供了恢复/撤消功能,如Word,Excel,还有我们的写Java程序用的JBuilder。
  3. 在早期,许多的应用程序还只能提供单一的Undo/Redo,自进入90年代以来,随着OOP及Design Pattern的流行,实现无限次数的Undo/Redo编辑功能已不是难事。
  4. 每一个编辑动作我们可以把它当成一个命令,如cut,del等,在做每一个编辑动作前,我们先要保存旧的数据,以便于undo它。我们为这些编辑命令设计了如下一个通用接口:
  5. public Interface Command
  6. {
  7.     public void execute(); 
  8.     public void undo();
  9. }
  10. 其中execute用来执行命令,undo用来恢复(undo).
  11. 接下来实现这个接口,先来实现Cut命令:
  12. public class CutCommand implements Command
  13. {
  14.     public void execute()
  15.     {
  16.         /* 备份旧数据 */
  17.         /* 剪切 */
  18.     }
  19.     public void undo()
  20.     {
  21.          /*  还原成备份的数据  */
  22.     }
  23. }
  24. 再来实现一个Delete命令:
  25. public class DeleteCommand implements Command
  26. {
  27.     public void execute()
  28.     {
  29.         /* 备份旧数据 */
  30.         /* 删除 */
  31.     }
  32.     public void undo()
  33.     {
  34.          /*  还原成备份的数据  */
  35.     }
  36. }
  37. OK,我们就只列出了cut和del两个命令,其它的命令相似的写法.
  38. 这样的话我们每做一个编辑动作,就执行一个相应的command.接下来我们要考虑如何将这些执行过的命令保存下来,以实现undo/redo. 我们再设计一个CommandManager:
  39. public Interface CommandManager
  40. {
  41.     public void storeCommand(Command cmd);
  42.     public void clearAllCommand();
  43.     public void undo();
  44.     public void redo();
  45. }
  46. 再来实现一个CommandManager, 我们称作CommandHistoryManager:
  47. public class CommandHistoryManager implements CommandManager
  48. {
  49.  Vector undoList=new Vector();
  50.  Vector redoList=new Vector();
  51.  public void storeCommand(Command cmd)
  52.  {
  53.   undoList.add(cmd);
  54.  }
  55.  public void clearAllCommand()
  56.  {
  57.   undoList.clear();
  58.   redoList.clear();
  59.  }
  60.  public void undo()
  61.  {
  62.         if ( undoList.size() <= 0 ) return;
  63.         Command cmd = ((Command)(undoList.get(undoList.size()-1)));
  64.         cmd.undo();
  65.         undoList.remove(cmd);
  66.         redoList.add(cmd);
  67.  }
  68.  public void redo()
  69.  {
  70.         if ( redoList.size() <= 0 ) return;
  71.         Command cmd = ((Command)(redoList.get(redoList.size()-1)));
  72.         cmd.execute();
  73.         redoList.remove(cmd);
  74.         undoList.add(cmd);
  75.   
  76.  }
  77. }
  78. 通过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功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值