在上两篇中,我们研究了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