- 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功能。