撤销与恢复主要用到了命令模式,也许还会和其他模式相结合:
package org.forever.drawlines { //命令接口 public interface Command { function execute():void;//执行操作 function unexecute():void;//取消操作 function canExecute():Boolean;//是否允许执行操作 function canUnexecute():Boolean;//是否允许取消操作 } }
package org.forever.drawlines { //命令集合类,负责存储执行过的命令和撤销执行的命令 public class CommandList { private var _executedCommands:Array = new Array(); private var _unexecutedCommands:Array = new Array(); private function _execute(command:Command):void{ command.execute();//执行具体的命令 _executedCommands.push(command);//记录执行的命令 } public function execute(command:Command):void{ _unexecutedCommands = new Array(); _execute(command); } //撤销执行,每执行一次该方法,将从最近的一次操作开始撤销 public function unexecute():void{ var command:Command = _executedCommands.pop();//出栈最后一次执行命令 command.unexecute();//撤销该命令的执行 _unexecutedCommands.push(command);//记录撤销的命令 } //恢复执行,每执行一次该方法,将从最近的一次操作开始撤销 public function reexecute():void{ var command:Command = _unexecutedCommands.pop();//出栈最后一次撤销命令 _execute(command);//重新执行 } public function reset():void{ _executedCommands = new Array(); _unexecutedCommands = new Array(); } //是否允许撤销命令,没有执行过命令就不存在撤销 public function canUnexecuteCommand():Boolean{ return !(_executedCommands.length==0); } //是否允许恢复命令,没有撤销过命令就不存在恢复 public function canReexecuteCommand():Boolean{ return !(_unexecutedCommands.length==0); } } }
package org.forever.drawlines { //添加线命令类 public class AddLineCommand implements Command { private var _drawing:Drawing;//画布 private var _line:Line;//直线 public function AddLineCommand(drawing:Drawing,line:Line) { this._drawing = drawing; this._line = line; } public function execute():void { _drawing.add(_line); } public function unexecute():void { _drawing.remove(_line); } public function canExecute():Boolean { return true; } public function canUnexecute():Boolean { return true; } } }
package org.forever.drawlines { import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.geom.Point; import mx.collections.ArrayList; import mx.controls.Alert; import spark.components.BorderContainer; //(接收者,负责具体实施和执行一个请求)画布,可以在该画布上画任意条直线 public class Drawing extends BorderContainer { private var _application:DrawLines;//应用程序 private var _lines:ArrayList;//直线集合 private var _startPosition:Point;//画线开始位置 private var _mousePosition:Point;//鼠标位置 private var _mousePressed:Boolean;//鼠标是否按下 private var _currentLine:Line;//正在画的直线 public function Drawing(owner:DrawLines) { _application = owner; _lines = new ArrayList(); _mousePressed = false;//默认鼠标未按下 addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler); addEventListener(MouseEvent.MOUSE_UP,mouseUpHandler); addEventListener(MouseEvent.MOUSE_MOVE,mouseMoveHandler); } //鼠标按键在组件上按下时调用 public function mouseDownHandler(event:MouseEvent):void{ _mousePressed = true;//鼠标为按下状态 _startPosition = new Point(mouseX,mouseY);//记录下直线的开始位置 _currentLine = new Line(_startPosition,_startPosition); addElement(_currentLine); } public function mouseUpHandler(event:MouseEvent):void{ if(mouseX!=_startPosition.x&& mouseY!=_startPosition.y){//两点不重合 var _addLineCommand:AddLineCommand = new AddLineCommand(this,_currentLine);//创建添加直线的一个命令 _application.execute(_addLineCommand);//请求者请求命令的执行 }else{//两点重合,不画直线 removeElement(_currentLine); } _mousePressed = false;//未按下状态 } public function mouseMoveHandler(event:MouseEvent):void{ if(_mousePressed){//画线进行中...... _mousePosition = new Point(mouseX,mouseY); _currentLine.end = _mousePosition; _currentLine.draw(); } } public function add(line:Line):void{ _lines.addItem(line); if(!contains(line)){ addElement(line); } } public function remove(line:Line):void{ _lines.removeItem(line); removeElement(line); } } }
package org.forever.drawlines { import flash.display.Graphics; import flash.geom.Point; import mx.core.UIComponent; public class Line extends UIComponent { public var x1:int; public var y1:int; public var x2:int; public var y2:int; public var _length:int; private var _start:Point; private var _end:Point; public function Line(start:Point,end:Point) { this.x1 = start.x; this.y1 = start.y; this.x2 = end.x; this.y2 = end.y; //_length = Number(Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2)).toFixed()); } public function get end():Point { return _end; } public function set end(value:Point):void { _end = value; x2 = end.x; y2 = end.y; } public function get start():Point { return _start; } public function set start(value:Point):void { _start = value; x1 = start.x; y1 = start.y; } public function draw():void{ this.graphics.clear(); this.graphics.moveTo(x1,y1); this.graphics.beginFill(0x00FF00); this.graphics.lineTo(x2, y2); this.graphics.lineStyle(2, 0x0000a00); this.graphics.endFill(); } } }
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" creationComplete="init()" xmlns:drawlines="org.forever.drawlines.*"> <fx:Script> <![CDATA[ import mx.controls.Alert; import org.forever.drawlines.Command; import org.forever.drawlines.CommandList; import org.forever.drawlines.Drawing; private var _drawing:Drawing; private var _commands:CommandList; //请求者(负责调用命令对象执行请求) public function init():void{ _commands = new CommandList(); _drawing = new Drawing(this); _drawing.x = 0; _drawing.y = 0; _drawing.percentWidth = 100; _drawing.percentHeight = 100; vg.addElement(_drawing); undoButton.addEventListener(MouseEvent.MOUSE_DOWN,undoMouseDownHandler); redoButton.addEventListener(MouseEvent.MOUSE_DOWN,redoMouseDownHandler); resetButton.addEventListener(MouseEvent.MOUSE_DOWN,resetMouseDownHandler); this.addEventListener(KeyboardEvent.KEY_DOWN,appKeyDownHandler); this.addEventListener(KeyboardEvent.KEY_UP,appKeyUpHandler); this.setFocus(); } public function appKeyDownHandler(event:KeyboardEvent):void{ } public function appKeyUpHandler(event:KeyboardEvent):void{ } public function undoMouseDownHandler(event:MouseEvent):void{ _commands.unexecute(); updateButtons(); } public function redoMouseDownHandler(event:MouseEvent):void{ _commands.reexecute(); updateButtons(); } public function resetMouseDownHandler(event:MouseEvent):void{ _commands.reset(); updateButtons(); } public function execute(command:Command):void{ _commands.execute(command);// 执行命令 updateButtons(); } // 更新按钮状态(根据是否能够undo撤销或者是否能够redo恢复) private function updateButtons():void { undoButton.enabled = _commands.canUnexecuteCommand(); redoButton.enabled = _commands.canReexecuteCommand(); } ]]> </fx:Script> <fx:Declarations> <!-- 将非可视元素(例如服务、值对象)放在此处 --> </fx:Declarations> <s:VGroup x="0" y="0" width="100%" height="100%" id="vg"> <s:HGroup width="100%" height="34" verticalAlign="middle"> <s:Button x="0" y="1" label="撤销" id="undoButton"/> <s:Button x="82" y="0" label="重做" id="redoButton"/> <s:Button x="160" y="0" label="重置" id="resetButton"/> </s:HGroup> </s:VGroup> </s:Application>