zoukankan      html  css  js  c++  java
  • ctrl+z的JAVA实现,借助了命令模式(command pattern)

    前些天学习<<JAVA与模式>>,到命令模式时,随带给了一个CTRL+Z案例的实现,想来学习编程这么久,CTRL+Z还没有认真实现过。

    因此,借助JAVA与模式里面的源代码,自己对撤销和回退进行了实现(JAVA与模式书中代码有部分问题)。此次用到了命令模式,因为有界面,有按钮,有接收者,有发送者。

    以下是类图,只为方便,未考虑UML细节规范。

     
    以下是程序的实现。
     
    MainFrame类:提供Main方法,Client类:类似于看电视的人,这里关联了UndoableTextArea,ItsukyuQuatation是因为要初始化该对象
    package undoRedo;
    
    import java.awt.Frame;
    import java.awt.event.*;
    
    public class MainFrame extends Frame {
    
        private static UndoableTextArea text;
        private static ItsukyuQuatation panel;
        
        public MainFrame(String title)
        {
            super(title);
        }
        
        public static void main(String[] args)
        {
            
            //构造可撤消的textArea
            text = new UndoableTextArea("Your text here");
            //构造panel
            panel = new ItsukyuQuatation(text);
            //构造frame
            MainFrame frame = new MainFrame("测试undo和redo");
            //增加窗体关闭事件
            frame.addWindowListener(new WindowAdapter()
            {
                public void windowClosing(WindowEvent e)
                {
                    System.exit(0);
                }
            });
            frame.add(panel);
            frame.setSize(300,300);
            frame.setVisible(true);
        }
    }

    ItsukyuQuatation类:面板类,里面包括undo和redo两个按钮,类似于命令模式中的摇控器。实现了ActionListener接口。

    package undoRedo;
    
    import java.awt.BorderLayout;
    import java.awt.Panel;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    public class ItsukyuQuatation extends Panel implements ActionListener {
    
        private final Command undo;
        private final Command redo;
        
        public ItsukyuQuatation(UndoableTextArea text)
        {
            this.setLayout(new BorderLayout());
            Panel toolbar = new Panel();
            undo = new UndoCommand(text);
            redo = new RedoCommand(text);
            undo.addActionListener(this);
            redo.addActionListener(this);
            toolbar.add(undo);
            toolbar.add(redo);
            
            this.add(toolbar,"North");
            this.add(text,"Center");
            
        }
        
        
        public void actionPerformed(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与模式一书中一样,只能实现最近一次的编辑撤消。

    package undoRedo;
    
    import java.awt.TextArea;
    import java.awt.event.*;
    import java.util.Hashtable;
    import javax.swing.undo.*;
    
    import javax.swing.undo.StateEditable;
    
    public class UndoableTextArea extends TextArea implements StateEditable {
    
        private UndoManager undoManager;
        private final static String KEY_STATE="UndoableTextAreaKey";
        private StateEdit currentEdit;
        boolean textChanged = false;
        
        public UndoableTextArea()
        {
            super();
            initUndoable();
        }
        public UndoableTextArea(String string)
        {
            super(string);
            initUndoable();
        }
    
        //存储状态
        public void storeState(Hashtable<Object, Object> hashTable) {
            // 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 boolean undo()
        {
            try
            {
                undoManager.undo();
                System.out.println("undo=" + undoManager.toString());
                return true;
            }catch(CannotUndoException e)
            {
                System.out.println("Can't undo");
            }
            return false;
        }
        
        //重做方法
        public boolean redo()
        {
            try
            {
                undoManager.redo();
                System.out.println("redo=" + undoManager.toString());
                return true;
            }catch(CannotRedoException e)
            {
                System.out.println("Can't redo");
            }
            return false;
        }
        
        private void initUndoable()
        {
            this.undoManager = new UndoManager();
            
            this.currentEdit = new StateEdit(this);
            
            this.addKeyListener(new KeyAdapter()
            {
                /*
                 * 
                 * 如果用keyPressed事件,那么最近的状态未加到undoManager.edits列里。
                 * 因此选用keyReleased事件。
                 * 
                public void keyPressed(KeyEvent event)
                {
                    if(event.isActionKey())
                    {
                        //takeSnapshot();
                    }else
                    {
                        textChanged = true;
                        takeSnapshot();
                    }
                }
                */
                public void keyReleased(KeyEvent event)
                {
                    if(event.isActionKey())
                    {
                        //takeSnapshot();
                    }else
                    {
                        textChanged = true;
                        takeSnapshot();
                    }
                }
            });
            
            this.addFocusListener(new FocusAdapter()
            {
                public void focusLost(FocusEvent event)
                {
                    //takeSnapshot();
                }
            });
            
        }
        
        private void takeSnapshot()
        {
            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类的实现,类似于命令模式中的具体按钮,调用接收者的方法进行实现。

    package undoRedo;
    
    import java.awt.Button;
    
    public abstract class Command extends Button {
    
        public Command(String caption)
        {
            super(caption);
        }
        
        public abstract void execute();
    }
    package undoRedo;
    
    public class UndoCommand extends Command {
    
        UndoableTextArea text;
        
        public UndoCommand(UndoableTextArea text)
        {
            super("Undo");
            this.text = text;
        }
        
        @Override
        public void execute() {
            // TODO Auto-generated method stub
            text.undo();
        }
    
    }
    package undoRedo;
    
    public class RedoCommand extends Command {
    
        UndoableTextArea text;
        
        public RedoCommand(UndoableTextArea text)
        {
            super("Redo");
            this.text = text;
        }
        
        @Override
        public void execute() {
            // TODO Auto-generated method stub
            text.redo();
        }
    
    }
  • 相关阅读:
    Django基础
    MySQL(索引)
    MySQL(进阶部分)
    MySQL(Python+ORM)
    JavaScript的对象
    abc
    Let's Encrypt,免费好用的 HTTPS 证书
    Java调试那点事
    Memcache mutex 设计模式
    从 Nginx 默认不压缩 HTTP/1.0 说起
  • 原文地址:https://www.cnblogs.com/xckk/p/4309920.html
Copyright © 2011-2022 走看看