撤销与恢复主要用到了命令模式,也许还会和其他模式相结合:
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>