ActionScript2 delegate 研究(下)

在上两篇中,我们研究了Macromedia Updater 2的Delegate的用法、起源、实现、优点。
然而这个Delegate可以很好的实现一个事件对应一个代理方法。但很多时候不是这样的,有更多的事物需要知道发生了这件事,然后调用自己的处理函数。比如我的一个组件,鼠标按下去的时候,有可能一个Label组件知道这个事件后改变自己的标题changeText(),同时也有可能一个MediaPlayback组件知道这个事件后要播放一个FLV视频play()……  而用Delegate,只能用一个函数来代理这些事务。然而这些事务是不同对象的方法,changeText()方法是属于Label对象的,play()方法是属于MediaPlayback对象的。当然可以把这些放在一个方法内,如下:
function EevntHandler()
{
    lbl.changeText();
    mpb.play();
}
但很多时候这些方法不能写在一个EventHandler函数中,这时我们想到了EventDispatcher,他可以让一个对象增加监听器,然后由这个对象广播事件给各个监听者。这些监听者监听到这些事件后,各自调用自己的处理事件。但Macromedia的EventDispatcher最大的一个缺点就是很多事件发生的相关信息没有传递,如鼠标点下去,很多时候需要鼠标的位置,按下的键是哪个。EventDispatcher却没有一个很好的规范去传递。

综合两者的优点。我大致构思了多播委托的模型。

Delegate改成EventHandler,构造函数稍为变化一下:

//****************************************************************************
// @FileName EventHander.as
// @Package com.flashvan.event
// @Description 事件代理句柄
// @Author aol
// @Email jeremy1982@21cn.com
// @Create 2004.10.21
// @LastChange 2004.10.21
// @History
//****************************************************************************

import com.flashvan.event.EventArgs;
import com.flashvan.event.except.Exception;

class com.flashvan.event.EventHandler extends Object
{
 /**
 Creates a functions wrapper for the original function so that it runs
 in the provided context.
 @parameter obj Context in which to run the function.
 @paramater func Function to run.
 */
 static function create(obj:Object, func:Function):Function
 {
  var f = function()
  {
   var target = arguments.callee.target;
   var func = arguments.callee.func;
   
//    
//    if(typeof(arguments[0])!= "object" && (arguments[1] instanceof EventArgs))
//     throw new Exception("参数得满足[sender:Object,e:EventArgs]的形式",this,[target,func]);

   return func.apply(target, arguments);
  };
  
  f.target = obj;
  f.func = func;

  return f;
 }

 function EventHandler(o:Object,f:Function)
 {
  obj = o
  func = f;
 }

 private var func:Function;
 private var obj:Object;

 function createEventHandler():Function
 {
  return create(obj, func);
 }
}

一个专门记录事件发生相关信息EventArgs:

//****************************************************************************
// @FileName EventArgs.as
// @Package com.flashvan.event
// @Description 事件参数类(事件发生之后传递的就是这个)
// @Author aol
// @Email jeremy1982@21cn.com
// @Create 2004.10.21
// @LastChange 2004.10.21
// @History
//****************************************************************************

class com.flashvan.event.EventArgs
{
 function EventArgs()
 {
 
 };
 
 public static function get Empty():EventArgs
 {
  return new EventArgs();
 }
 
 public function Dispose():Void
 {
  delete this;
 }
};

由EventArg继承下来的,例如专门针对鼠标事件的MouseEvntArgs
import com.flashvan.event.EventArgs;

class com.flashvan.component.core.MouseEventArgs extends EventArgs
{
 private var _clicks:Number;//鼠标被按下的次数
 
 //按下鼠标的哪个按钮
 // 0为没按, 1为左键, 2为右键, 3为滚轮
 // 要全部监测到那得用未公开函数了 ^_^
 private var _button:Number;
 
 private var _x,_y:Number;//鼠标位置
 
 private var _delta:Number;//滚轮位置
 
 private var _springTime:Number;//触发时间
 
 public function MouseEventArgs(button:Number,clicks:Number,x:Number,y:Number,delta:Number)
 {
  _springTime = getTimer();
  _button = button;
  _clicks = clicks;
  _x  = x;
  _y  = y;
  _delta  = (delta == null)? 0:delta;
  
 }
 
 public function get X():Number
 {
  return _x;
 }
 
 public function get Y():Number
 {
  return _y;
 }
 
 public function get Clicks():Number
 {
  return _clicks;
 }
 
 public function get Button():Number
 {
  return _clicks;
 }
 
 public function get Delta():Number
 {
  return _delta;
 }
 
 //触发时间
 public function get SpringTime():Number
 {
  return _springTime;
 }
}

要实现多播至少要实现这列的多播接口:
import com.flashvan.event.EventArgs;
import com.flashvan.collections.ArrayList;
import com.flashvan.event.EventHandler;

interface com.flashvan.event.IMulticastEventDelegate
{
//  public function AddEventHandler(o:Object,f:Function):Void;
 public function AddEventHandler(eh:EventHandler):Void;
 
 public function getInvocationList():ArrayList;
 
//  public function RemoveEventHandler(o:Object,f:Function):Void;
 public function RemoveEventHandler(eh:EventHandler):Void;
 
 public function RemoveAllEventHandler():Void;
 
 public function InvokeAllEventHandler(sender:Object,e:EventArgs):Void;

}

最主要的Event类实现了这个接口:

import com.flashvan.event.IMulticastEventDelegate;
import com.flashvan.collections.ArrayList;
import com.flashvan.collections.IEnumerator;
import com.flashvan.event.EventArgs;
import com.flashvan.event.EventHandler;


class com.flashvan.event.Event implements IMulticastEventDelegate
{
 private var invocationlist:ArrayList;
 
 public function Event()
 {
  invocationlist = new ArrayList();
 }
 
 
//  public function AddEventHandler(o:Object,f:Function):Void
//  {
//   invocationlist.Add({object:o,method:f});
//  }
//  public function RemoveEventHandler(o:Object,f:Function):Void
//  {
//   invocationlist.Remove({object:o,method:f});
//  }

 public function AddEventHandler(eh:EventHandler):Void
 {
  invocationlist.Add(eh);
 }
 public function RemoveEventHandler(eh:EventHandler):Void
 {
  invocationlist.Remove(eh);
 }
 
 public function RemoveAllEventHandler():Void
 {
  invocationlist.Clear();
 }
 
 public function getInvocationList():ArrayList
 {
  return invocationlist;
 }
 
//  public function InvokeAllEventHandler(sender:Object,e:EventArgs):Void
//  {
//   var enumerator:IEnumerator = invocationlist.GetEnumerator();
//   while(enumerator.MoveNext())
//   {
//    var obj:Object = enumerator.getCurrent().object;
//    var f:Function = enumerator.getCurrent().method;
//    f.apply(obj,[sender,e]);
//   }
//  }

 public function InvokeAllEventHandler(sender:Object,e:EventArgs):Void
 {
  var enumerator:IEnumerator = invocationlist.GetEnumerator();
  while(enumerator.MoveNext())
  {
   enumerator.getCurrent().createEventHandler()(sender,e);
  }
 }
}

下面用一个测试组件来测试一下:
import com.flashvan.event.Event;
import com.flashvan.event.EventArgs;
import com.flashvan.event.EventHandler;

import com.flashvan.component.core.Component;
import com.flashvan.component.core.MouseEventArgs;

class com.flashvan.test.EventTestComponent extends Component
{
 public var MouseMove:Event;
 public var MouseDown:Event;
 
 public function EventTestComponent()
 {
  MouseMove = new Event();
 }
 
 public function onMouseMove():Void
 {
  var e:MouseEventArgs = new MouseEventArgs(0,0,_xmouse,_ymouse);
  MouseMove.InvokeAllEventHandler(this,e);
 } 
}

上面的经常都已经封装好,包括上面的测试组件,实际上很多时候用户编码只需要这些:

新建一个fla文件,把做好的EventTestComponent拖到场景中命名为etc。

新建一个类com.flashvan.test.EventTest:

import com.flashvan.event.EventHandler;

import com.flashvan.component.core.Component;
import com.flashvan.component.core.MouseEventArgs;

import com.flashvan.test.EventTestComponent;

class com.flashvan.test.EventTest extends Component
{
 private var etc:EventTestComponent;
 public function EventDelegate(sender:Object,e:MouseEventArgs):Void
 {
  trace(sender);
 }
 
 public function EventDelegate2(sender:Object,e:MouseEventArgs):Void
 {
  trace(e.SpringTime);
 }
 
 public function EventTest(c:EventTestComponent)
 {
  etc = c;
  etc.MouseMove.AddEventHandler(new EventHandler(this,EventDelegate));
  etc.MouseMove.AddEventHandler(new EventHandler(this,EventDelegate2));
 }
 
 public static function main():Void
 {
  new EventTest(EventTestComponent(arguments[0]));
 }
 
}


fla文件主时间轴加上
com.flashvan.test.EventTest.main(etc);

Ctrl+ Enter测试,只要鼠标移动就会出现类似如下的结果:
_level0.etc
72
_level0.etc
1563

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值