Flash AS2 事件处理机制

| |
[2007/07/13 11:21 | 分类: Flash技术 | by gdgzboy ]
[此文来源于互联网,牛C网只负责收集整理]
本教程中你将学习下面的内容:

       1.事件处理机制.
       2.创建类库.
       3.使用 回调函数.
              3.1.示例: CFEventClass 类(简单的示例).
              3.2.示例: CFTimer 类(定时器).
       4.使用 addListener 方法(AsBroadcaster / BroadcasterMX 类).
              4.1.示例: AsBEventClass 类(简单的示例).
              4.2.示例: AsBTimer 类(定时器).
       5.使用 addEventListener 方法(EventDispatcher 类).
              5.1.示例: EDEventClass 类(简单的示例).
              5.2.示例: EDTimer 类(定时器).
       6.建立强大的事件处理机制.
              6.1.创建 CFDelegate 类(修改 Delegate 类).
              6.2.创建 CFEventDispatcher 类(修改 EventDispatcher 类).
              6.3.创建 Event 类(事件基类,继承 Object 类).
              6.4.创建 IOErrorEvent 类(错误事件类,继承 Event 类).
              6.5.创建 HTTPStatusEvent 类(http状态事件类,继承 Event 类).
              6.6.示例: EventClass 类(简单的示例).
              6.7.示例: Timer 类(定时器,功能跟 AS3 中的 Timer 类一样).
       7.小结.

源文件(LRC 和 CFSound 类也在这):Flash Class Library.rar

[1.事件处理机制]

AS2 的事件处理机制并不完美.形态多样.不易于管理.在这里可以解决此问题的一半.本文会先了解和使用
AS2 中基本的事件处理机制.然后建立强大的事件处理机制.来方便管理自己的程序.下面讲解.

形态多样的事件处理机制(后面会详细的讲解):
1.回调函数.(如 onLoad, onHTTPStatus 等)
2.使用 addListener 方法. (如 onLoadStart, onLoadInit 等)
3.使用 addEventListener 方法. (如 click, change 等)

它们的作用域和形态(代码):
作用域是指标识符(如常量、数据类型、变量或例程)在程序内可被引用的范围.
1.this 指向触发此事件的对象

object.onLoad = function()
{
    trace(this); //输出: object
}

2.this 指向侦听器对象

var listenerObject:Object = {};
listenerObject.onLoadStart = function()
{
    trace(this); //输出: listenerObject
}
broadcasterObject.addListener(listenerObject);

3.使用侦听器对象:this 指向侦听器对象

var listenerObject:Object = {};
listenerObject.click = function(evt:Object)
{
    trace(this); //输出: listenerObject
}
broadcasterObject.addEventListener("click", listenerObject);

使用函数:this 指向触发此事件的对象

function clickHandler(evt:Object):Void
{
    trace(this); //输出: broadcasterObject
}
broadcasterObject.addEventListener("click", clickHandler);

有时我们需要更改它们的作用域怎么办?
想要改变它们的作用域,需使用 Delegate 类的 create 方法.
此类的全路径: mx.utils.Delegate;
用法: Delegate.create(要运行函数的范围, 函数);
例:
1.this 指向 _level0

import mx.utile.Delegate;
object.onLoad = Delegate.create(this, _onLoad);
function _onLoad():Void
{
    trace(this); //输出: _level0
}

2.this 指向 _level0

import mx.utile.Delegate;
var listenerObject:Object = {};
listenerObject.onLoadStart = Delegate.create(this, loadStart);
function loadStart():Void
{
    trace(this); //输出: _level0
}
broadcasterObject.addListener(listenerObject);

3.
使用侦听器对象:this 指向 _level0

import mx.utile.Delegate;
var listenerObject:Object = {};
listenerObject.click = Delegate.create(this, clickHandler);
function clickHandler(evt:Object)
{
    trace(this); //输出: _level0
}
broadcasterObject.addEventListener("click", listenerObject);

使用函数:this 指向 _level0

function clickHandler(evt:Object):Void
{
    trace(this); //输出: _level0
}
broadcasterObject.addEventListener("click", Delegate.create(this, clickHandler));

事件对象:
它包含两个基本属性:
type:String              事件名.
target:Object       事件源.此属性可以不指定,默认为事件源(调用dispatchEvent方法的对象).
此对象传递给 EventDispatcher 类的 dispatchEvent 方法并作为参数传递到侦听器.
例:

//发送事件.
dispatchEvent({type:"click", target:this});
//事件处理函数.
function clickHandler(evt:Object):Void
{
    trace([evt.type, evt.target]);  
}
//添加事件侦听器.
addEventListener("click", clickHandler);

下一节讲:[2.创建类库]

在开始下面的教程之前.先要创建类库.在硬盘中创建如图结构的文件目录:

Flash AS2 事件处理机制


Classes 目录是用来存放类文档.
Example 目录是用来存放示例文档.
创建好后还需要在 Flash 中添加类路径:
Flash 8: 编辑-->首选参数-->ActionScript-->ActionScript 2.0 设置-->添加( )-->浏览到 Flash Class Library/Classes 目录.
Flash AS2 事件处理机制

Flash CS3: Edit-->Preferences-->ActionScript-->ActionScript 2.0 Settings-->Add New Path( )-->Browse To Flash Class Library/Classes 目录.
ActionScript 3.0 也要添加(在后续文章中会用到).
Flash AS2 事件处理机制

下一节讲: [3.使用 回调函数]

[3.使用 回调函数]

回调函数也可以说是匿名函数,先看下面的代码:

var myXML:XML = new XML();
myXML.load("xml.xml");
myXML.onLoad = function(success:Boolean)
{
    trace(success);
}

XML.onLoad 是一个回调函数.将匿名函数与特定的事件关联,以创建回调函数.函数将在特定事件发生后调用回调函数.
在自定义类中怎么做呢?看下面的示例.

[3.1.示例: CFEventClass 类(简单的示例)]
此示例文档详细:
Example/AS2/events/CFEvent/CFEventClass.as                            
Example/AS2/events/CFEvent/CFEventExample.as                    
Example/AS2/events/CFEvent/CFEventExample.xml                    
Example/AS2/events/CFEvent/CFEventExample.fla                    

主类:
打开 CFEventClass.as  文档,输入下面的代码:

import mx.utils.Delegate;
//----------------------------------------
class CFEventClass
{
    //----------------------------------------
    public var tXML:XML;
    //定义事件函数.
    public var complete:Function;
    //----------------------------------------
    public function CFEventClass(url:String)
    {
        this.tXML = new XML();
        this.tXML.onLoad = Delegate.create(this, this.XMLonLoad);
        this.tXML.load(url);
    }
    private function XMLonLoad(success:Boolean):Void
    {
        if (success) {
            //执行事件函数.
            this.complete();
        }
    }
    //----------------------------------------
}

保存文档,这样我们就创建了一个名为 CFEventClass 的类,拥有一个事件,一个属性,此事件在 XML 文档成功加载后发生.

示例类:
打开 CFEventExample.as 文档,输入下面的代码:

import CFEventClass;
//----------------------------------------
class CFEventExample
{
    public function CFEventExample()
    {
        var ee:CFEventClass = new CFEventClass("CFEventExample.xml");
        ee.complete = this.complete;
    }
    private function complete():Void
    {
        trace("complete");
    }
}

保存文档.
在示例类中我们创建主类的一个实例.来加载 CFEventExample.xml 文档.然后使用自定义函数与 complete 事件关联.
如果要移除事件,请使用下面的方法:

ee.complete = undefined
//或
ee.complete = null;
//或
delete ee.complete;

要加载的 XML 文档:
打开 CFEventExample.xml 文档,随便输入一些内容便可.测试用.

示例 fla 文档:
打开 CFEventExample.fla 文档.将"图层 1"重命名为  Actions.并在第一帧中输入下面的代码:

new CFEventExample();

保存文档.
测试 Flash 文档.在 XML 文档成功加载后会在输出面板中显示以下内容

complete

如需给事件传递参数,在执行事件函数时如下添加参数:

this.complete(参数1, 参数2, 参数N);

在调用事件时:

private function complete(参数1, 参数2, 参数N)
{
    trace([参数1, 参数2, 参数N]);
}

下面再看一个示例:

[3.2.示例: CFTimer 类(定时器)]
此示例文档详细:
Classes/AS2/utils/CFTimer.as
Example/AS2/utils/CFTimer/CFTimerExample.as
Example/AS2/utils/CFTimer/CFTimerExample.fla

主类:
打开 CFTimer.as 文档,输入下面的代码:

import mx.utils.Delegate;
//----------------------------------------
class AS2.utils.CFTimer
{
    //----------------------------------------
    private var _timerID:Number;
    private var _delay:Number;
    private var _repeatCount:Number;
    private var _currentCount:Number = 0;
    private var _running:Boolean;
    //----------------------------------------
    public var timer:Function;
    public var timerComplete:Function;
    //----------------------------------------
    /*
    @parameter    delay:            延迟,单位毫秒.
    @parameter    repeatCount:    重复的次数.默认为Infinity(正无穷大);
    */
    public function CFTimer(delay:Number, repeatCount:Number)
    {
        if (isNaN(delay)) {
            return;
        }
        if (isNaN(repeatCount)) {
            repeatCount = Infinity;
        }
        this._delay = delay;
        this._repeatCount = repeatCount;
    }
    //----------------------------------------
    public function reset():Void
    {
        this._currentCount = 0;
        this.stop();
    }
    public function start():Void
    {
        this._timerID = setInterval(CFDelegate.create(this, this.startTimer), this._delay);
        this._running = true;
    }
    public function stop():Void
    {
        clearInterval(this._timerID);
        this._running = false;
    }
    public function toString():String
    {
        return "[CFTimer]";
    }
    //----------------------------------------
    private function startTimer():Void
    {
        this._currentCount  ;
        this.timer(this._currentCount);
        if (this._currentCount == this._repeatCount) {
            this.reset();
            this.timerComplete();
        }
    }
    //----------------------------------------
    public function get delay():Number
    {
        return this._delay;
    }
    public function set delay(d:Number):Void
    {
        this._delay = d;
    }
    public function get repeatCount():Number
    {
        return this._repeatCount;
    }
    public function set repeatCount(r:Number):Void
    {
        this._repeatCount = r;
    }
    public function get currentCount():Number
    {
        return this._currentCount;
    }
    public function get running():Boolean
    {
        return this._running;
    }
    //----------------------------------------
}

保存文档.
此类的详细信息:
构造函数:
public CFTimer(delay:Number, repeatCount:Number)
参数:
delay:Number              ---延迟,单位毫秒.
repeatCount:Number       ---重复次数.默认为 Infinity(正无穷大);

方法:
public reset():Void                     ---停止定时.并复位 currentCount .
public start():Void                     ---开始计时.
public stop():Void                     ---停止定时.
public toString():String       ---返回类名称"[CFTimer]".

属性:
public delay:Number                                   ---延迟,单位毫秒.
public repeatCount:Number                      ---重复的次数.默认值为 Infinity(正无穷大);
public currentCount:Number [只读]       ---当前的次数.当开始计时,此值会递增,直到等于 repeatCount.
public running:Boolean           [只读]       ---定时器目前的状态,true 表示正在运行, false 表示已停止.

事件:
timer = function(currentCount:Number){}              ---每当时间间隔到达 delay 时调用.
timerComplete = function(){}                            ---当 currentCount 等于 repeatCount 时调用.

示例类:
打开 CFTimerExample.as 文档.输入下面的代码:

import AS2.utils.CFTimer;
//----------------------------------------
class CFTimerExample
{
    //----------------------------------------
    public function CFTimerExample()
    {
        var te:CFTimer = new CFTimer(1000, 5);
        te.timer = this.timer;
        te.timerComplete = this.timerComplete;
        te.start();
    }
    private function timer(currentCount:Number):Void
    {
        trace("timer: "   currentCount);
    }
    private function timerComplete():Void
    {
        trace("timerComplete: ");
    }
    //----------------------------------------
}

保存文档.
这里我们创建 CFTimer 类的一个实例, 时间间隔为 1000 毫秒,重复执行 5 次.然后实现 timer 和 timerComplete 事件.

示例 fla 文档:
打开 CFTimerExample.fla 文档,将"图层 1" 重命名为 Actions.并在第一帧中输入下面的代码:

new CFTimerExample();

测试 Flash 文档.输出面板会陆续显示以下的内容:

timer: 1
timer: 2
timer: 3
timer: 4
timer: 5
timerComplete:

下一节讲: [4.使用 addListener 方法(AsBroadcaster / BroadcasterMX 类)]

[4.使用 addListener 方法(AsBroadcaster / BroadcasterMX 类)]

在 MovieClipLoader 和 Tween 等类中都用到了 addListener 方法来注册侦听.
我们该怎么用呢? Macromedia 为我们提供了如下二个类:
AsBroadcaster 属于系统类.
BroadcasterMX 属于自定义类.类路径: mx.transitions.BroadcasterMX
这两个类的很相似.它们都是提供事件通知和侦听器管理功能.
但 AsBroadcaster 类是系统内置的.执行效率会比 BroadcasterMX 类快很多.所以这里我们就用 AsBroadcaster
类来讲解.
此类详细:
public addListener(listenerObj:Object):Boolean         ---注册侦听器.
public broadcastMessage(eventName:String):Void         ---广播消息/发送事件.
public static initialize(obj:Object):Void                ---将事件通知和侦听器管理功能添加到给指定的对象
public removeListener(listenerObj:Object):Boolean ---移除侦听器.
public _listeners:Array [只读]                                     ---对已注册侦听器对象的引用.

该怎么用呢? 看下面的示例:
[4.1.示例: AsBEventClass 类(简单的示例)]
此示例文档详细:
Example/AS2/events/AsBEvent/AsBEventClass.as
Example/AS2/events/AsBEvent/AsBEventExample.as
Example/AS2/events/AsBEvent/AsBEventExample.xml
Example/AS2/events/AsBEvent/AsBEventExample.fla

主类:
打开 CFEventClass.as  文档,输入下面的代码:

import mx.utils.Delegate;
//----------------------------------------
class AsBEventClass extends AsBroadcaster
{
    //----------------------------------------
    public var tXML:XML;
    //----------------------------------------
    public function AsBEventClass(url:String)
    {
        AsBroadcaster.initialize(AsBEventClass.prototype);
        this.tXML = new XML();
        this.tXML.onLoad = Delegate.create(this, this.XMLonLoad);
        this.tXML.load(url);
    }
    private function XMLonLoad(success:Boolean):Void
    {
        if (success) {
            this.broadcastMessage("complete");
        }
    }
    //----------------------------------------
}

保存文档.
这里首先继承 AsBroadcaster 类.然后在构造函数中使用

AsBroadcaster.initialize(AsBEventClass.prototype);

来获取事件通知和侦听器管理功能.最后使用

this.broadcastMessage("complete");

来广播消息或发送事件.
当然你也可以选择不继承它,但需要在类中添加下面的方法:

public var addListener:Function;
public var removeListener:Function;
private var broadcastMessage:Function;

示例类:
打开 CFTimerExample.as 文档.输入下面的代码:

import AsBEventClass;
//----------------------------------------
class AsBEventExample
{
    public function AsBEventExample()
    {
        var ee:AsBEventClass = new AsBEventClass("AsBEventExample.xml");
        ee.addListener(this);
    }
    private function complete():Void
    {
        trace("complete");
    }
}

保存文档.
在示例类中我们创建主类的一个实例.来加载 AsBEventExample.xml 文档.然后添加侦听器.
如果要移除侦听器,请使用下面的方法:

ee.removeListener(this);

要加载的 XML 文档:
打开 AsBEventExample.xml 文档,随便输入一些内容便可.测试用.

示例 fla 文档:
打开 AsBEventExample.fla 文档.将"图层 1"重命名为  Actions.并在第一帧中输入下面的代码:

new AsBEventExample();

保存文档.
测试 Flash 文档.在 XML 文档成功加载后会在输出面板中显示以下内容

complete

如需给事件传递参数,在发送事件时如下添加参数:

this.broadcastMessage("complete", 参数1, 参数2, 参数N);

在调用事件时:

private function complete(参数1, 参数2, 参数N)
{
    trace([参数1, 参数2, 参数N]);
}

下面再看一个示例:
[4.2.示例: AsBTimer 类(定时器)]
此示例文档详细:
Classes/AS2/utils/AsBTimer.as
Example/AS2/utils/AsBTimer/AsBTimerExample.as
Example/AS2/utils/AsBTimer/AsBTimerExample.fla

主类:
打开 AsBTimer.as 文档,输入下面的代码:

import AS2.utils.CFDelegate;
//----------------------------------------
class AS2.utils.AsBTimer extends AsBroadcaster
{
    //----------------------------------------
    private var _timerID:Number;
    private var _delay:Number;
    private var _repeatCount:Number;
    private var _currentCount:Number = 0;
    private var _running:Boolean;
    //----------------------------------------
    /*
    @parameter    delay:            延迟,单位毫秒.
    @parameter    repeatCount:    重复次数.默认为Infinity(正无穷大);
    */
    public function AsBTimer(delay:Number, repeatCount:Number)
    {
        AsBroadcaster.initialize(AsBTimer.prototype);
        if (isNaN(delay)) {
            return;
        }
        if (isNaN(repeatCount)) {
            repeatCount = Infinity;
        }
        this._delay = delay;
        this._repeatCount = repeatCount;
    }
    //----------------------------------------
    public function reset():Void
    {
        this._currentCount = 0;
        this.stop();
    }
    public function start():Void
    {
        this._timerID = setInterval(CFDelegate.create(this, this.startTimer), this._delay);
        this._running = true;
    }
    public function stop():Void
    {
        clearInterval(this._timerID);
        this._running = false;
    }
    public function toString():String
    {
        return "[AsBTimer]";
    }
    //----------------------------------------
    private function startTimer():Void
    {
        this._currentCount  ;
        this.broadcastMessage("timer", this._currentCount);
        if (this._currentCount == this._repeatCount) {
            this.reset();
            this.broadcastMessage("timerComplete");
        }
    }
    //----------------------------------------
    public function get delay():Number
    {
        return this._delay;
    }
    public function set delay(d:Number):Void
    {
        this._delay = d;
    }
    public function get repeatCount():Number
    {
        return this._repeatCount;
    }
    public function set repeatCount(r:Number):Void
    {
        this._repeatCount = r;
    }
    public function get currentCount():Number
    {
        return this._currentCount;
    }
    public function get running():Boolean
    {
        return this._running;
    }
    //----------------------------------------
}

因此类详细前面已讲,功能一样,只是事件处理机制不同而已.这里就不再啰嗦.

示例类:
打开 AsBTimerExample.as 文档.输入下面的代码:

import AS2.utils.AsBTimer;
//----------------------------------------
class AsBTimerExample
{
    //----------------------------------------
    public function AsBTimerExample()
    {
        var te:AsBTimer = new AsBTimer(1000, 5);
        te.addListener(this);
        te.start();
    }
    private function timer(currentCount:Number):Void
    {
        trace("timer: "   currentCount);
    }
    private function timerComplete():Void
    {
        trace("timerComplete: ");
    }
    //----------------------------------------
}

保存文档.

示例 fla 文档:
打开 AsBTimerExample.fla 文档,将"图层 1" 重命名为 Actions.并在第一帧中输入下面的代码:

new AsBTimerExample();

测试 Flash 文档.输出面板会陆续显示以下的内容:

timer: 1
timer: 2
timer: 3
timer: 4
timer: 5
timerComplete:

下一节讲:[5.使用 addEventListener 方法(EventDispatcher 类)]

[5.使用 addEventListener 方法(EventDispatcher 类)]


打瞌睡了吧? 貌似有口水流下来了.呵.本人文字表达能力不是很好(好像是没吃多少书).让大家见笑了.其实学编程
是比较闷的.不只是闷,还有很多很多,但既然选择了,这些就只是学习途中的坎,需要我们跨过去.就像是你选择走哪
条路一样,既然选择了,就必需是要走的.但这路不只是你一个人走,人多了就会有竞争,我们不能总走在别人后面.所
以需要加快脚步走在前面,让后面的人去追.但有时也会在不知不觉中走弯路,我一样也会,所以在本文中如果你看到
有不正确的,希望你能指正,谢谢.此文的目的是想让大家在这条路上能走快点.你很啰嗦呀....呵.题外话就说到这.
下面继续.

这一节讲 EventDispatcher 类.此类也是提供事件通知和侦听器管理功能的,但比前面讲的功能会强一些.在 AS2
中,此类用于组件的事件处理机制中.因 Macromedia 没有过多的讲解此类.很少人将它用于自定义类中.本人在研究
mx包下的类时才知道此类的用法.

首先看看在组件中如何使用:
1.

function clickHandler(evt:Object):Void
{
    trace("click");
]
button.addEventListener("click", clickHandler);

2.

function click(evt:Object):Void
{
    trace("click");
]
button.addEventListener("click", this);

3.

function handleEvent(evt:Object):Void
{
    trace("click");
]
button.addEventListener("click", this);

4.

button.clickHandler = function(evt:Object)
{
    trace("click");
}

这几种写法其效果都是一样的.都是侦听 button 实例的 click 事件.

下面来了解此类详细:
public addEventListener(eventName:String, 侦听器对象或函数):Void              ---添加事件侦听器
public removeEventListener(eventName:String, 侦听器对象或函数):Void              ---移除事件侦听器
public dispatchEvent(eventObj:Object):Void          object:Object):Void

帮助文档中没有讲解 initialize 方法.此方法的功能同 AsBroadcaster 类的 initialize 方法一样.

该怎么用呢? 看下面的示例:
[5.1.示例: EDEventClass 类(简单的示例)]
此示例文档详细:
Example/AS2/events/EDEvent/EDEventClass.as
Example/AS2/events/EDEvent/EDEventExample.as
Example/AS2/events/EDEvent/EDEventExample.xml
Example/AS2/events/EDEvent/EDEventExample.fla

主类:
打开 EDEventClass.as 文档,输入下面的代码:

import mx.utils.Delegate;
import mx.events.EventDispatcher;
//----------------------------------------
class EDEventClass extends EventDispatcher
{
    //----------------------------------------
    public var tXML:XML;
    //----------------------------------------
    public function EDEventClass(url:String)
    {
        this.tXML = new XML();
        this.tXML.onLoad = Delegate.create(this, this.XMLonLoad);
        this.tXML.load(url);
    }
    private function XMLonLoad(success:Boolean):Void
    {
        if (success) {
            this.dispatchEvent({type:"complete"});
        }
    }
    //----------------------------------------
}

如果不继承 EventDispatcher 类.请将代码改成如下:

import mx.utils.Delegate;
import mx.events.EventDispatcher;
//----------------------------------------
class EDEventClass
{
    //----------------------------------------
    //不继承需添加这三个方法.
    public var addEventListener:Function;
    public var removeEventListener:Function;
    private var dispatchEvent:Function;
    //----------------------------------------
    public var tXML:XML;
    //----------------------------------------
    public function EDEventClass(url:String)
    {
        //还有使用 initialize 静态方法.
        EventDispatcher.initialize(this);
        this.tXML = new XML();
        this.tXML.onLoad = Delegate.create(this, this.XMLonLoad);
        this.tXML.load(url);
    }
    private function XMLonLoad(success:Boolean):Void
    {
        if (success) {
            this.dispatchEvent({type:"complete"});
        }
    }
    //----------------------------------------
}

保存文档.
这里首导入 EventDispatcher 类,你可以选择继承或不继承此类.上面的代码一个是继承,一个是不继承.区别
也很容易看出来.这里就不讲了.

示例类:
打开 EDEventExample.as 文档,输入下面的代码:

import EDEventClass;
//----------------------------------------
class EDEventExample
{
    public function EDEventExample()
    {
        var ee:EDEventClass = new EDEventClass("EDEventExample.xml");
        ee.addEventListener("complete", this);
    }
    private function complete(evt:Object):Void
    {
        trace("complete");
    }
}

保存文档.
在示例类中我们创建主类的一个实例.来加载 EDEventExample.xml 文档.然后添加侦听器.
如果要移除事件侦听器,请使用下面的方法:

ee.removeEventListener("complete", this);

要加载的 XML 文档:
打开 EDEventExample.xml 文档,随便输入一些内容便可.测试用.

示例 fla 文档:
打开 EDEventExample.fla 文档.将"图层 1"重命名为  Actions.并在第一帧中输入下面的代码:

new EDEventExample();

保存文档.
测试 Flash 文档.在 XML 文档成功加载后会在输出面板中显示以下内容

complete

如需给事件传递参数,在发送事件时将参数添加事件对象(请看:1.事件处理机制)中,如下添加:

this.dispatchEvent({type:"complete", 参数1:"参数1", 参数2:"参数2", 参数N:"参数N");

在调用事件时:

private function complete(evt:Object)
{
    trace([evt.type, evt.target, evt.参数1, evt.参数2, evt.参数N]);
}

下面再看一个示例:
[5.2.示例: EDTimer 类(定时器)]
此示例文档详细:
Classes/AS2/utils/EDTimer.as
Example/AS2/utils/EDTimer/EDTimerExample.as
Example/AS2/utils/EDTimer/EDTimerExample.fla

主类:
打开 EDTimer.as 类,输入下面的代码(当不急时,应多打代码(有利于巩固知识).不应 copy/paste):

import mx.utils.Delegate;
import mx.events.EventDispatcher;
//------------------------------
class AS2.utils.EDTimer extends EventDispatcher
{
    //------------------------------
    private var _timerID:Number;
    private var _delay:Number;
    private var _repeatCount:Number;
    private var _currentCount:Number = 0;
    private var _running:Boolean;
    //------------------------------
    /*
    @parameter    delay:            延迟,单位毫秒.
    @parameter    repeatCount:    重复次数.默认为Infinity(正无穷大);
    */
    public function EDTimer(delay:Number, repeatCount:Number)
    {
        if (isNaN(delay)) {
            return;
        }
        if (isNaN(repeatCount)) {
            repeatCount = Infinity;
        }
        this._delay = delay;
        this._repeatCount = repeatCount;
    }
    //------------------------------
    public function reset():Void
    {
        this._currentCount = 0;
        this.stop();
    }
    public function start():Void
    {
        this._timerID = setInterval(Delegate.create(this, this.startTimer), this._delay);
        this._running = true;
    }
    public function stop():Void
    {
        clearInterval(this._timerID);
        this._running = false;
    }
    public function toString():String
    {
        return "[EDTimer]";
    }
    //----------------------------------------
    private function startTimer():Void
    {
        this._currentCount  ;
        this.dispatchEvent({type:"timer", currentCount:this._currentCount});
        if (this._currentCount == this._repeatCount) {
            this.reset();
            this.dispatchEvent({type:"timerComplete"});
        }
    }
    //------------------------------
    public function get delay():Number
    {
        return this._delay;
    }
    public function set delay(d:Number):Void
    {
        this._delay = d;
    }
    public function get repeatCount():Number
    {
        return this._repeatCount;
    }
    public function set repeatCount(r:Number):Void
    {
        this._repeatCount = r;
    }
    public function get currentCount():Number
    {
        return this._currentCount;
    }
    public function get running():Boolean
    {
        return this._running;
    }
    //------------------------------
}

因此类详细前面已讲,功能一样,只是事件处理机制不同而已.这里就不再啰嗦.

示例类:
打开 EDTimerExample.as 文档,输入下面的代码:

import AS2.utils.EDTimer;
//----------------------------------------
class EDTimerExample
{
    //----------------------------------------
    public function EDTimerExample()
    {
        var te:EDTimer = new EDTimer(1000, 5);
        te.addEventListener("timer", this);
        te.addEventListener("timerComplete", this);
        te.start();
    }
    private function timer(evt:Object):Void
    {
        trace("timer: "   evt.currentCount);
    }
    private function timerComplete(evt:Object):Void
    {
        trace(evt.type);
    }
    //----------------------------------------
}

示例 fla 文档:
打开 EDTimerExample.fla 文档,将"图层 1" 重命名为 Actions.并在第一帧中输入下面的代码:

new EDTimerExample();

测试 Flash 文档.输出面板会陆续显示以下的内容:

timer: 1
timer: 2
timer: 3
timer: 4
timer: 5
timerComplete

下一节:[6.建立强大的事件处理机制]

[6.建立强大的事件处理机制]

这一节讲建立强大的事件处理机制.学完这节,如果有接触过 AS3 的,马上会想到一句:这不就是 AS3 的事件处理机制吗?
的确.可以说跟 AS3 的事件处理机制一模一样.但还是有个作用域的问题.这节对想学习 AS3 的事件处理机制会有很大
帮助.如果你掌握这节中的内容,在 AS3 中就只有语法问题.也就会很快进入状态.毕竟是"水往低处流,人往高处走".对现
在用 AS2 的,学 AS3 是迟早的问题.不过 AS2 在新版本出来之前还是会很有用的(个人的看法).

作用域因为一样,前面也讲过,这里就不在啰嗦.
事件对象.这里已经创建一个 Event 类(或其子类)来代替.但功能一样.

这节讲的事件处理机制的形态(代码).
发送事件:

//继承.
import AS2.events.Event;
import AS2.events.CFEventDispatcher;
class className extends CFEventDispatcher
{
    ...
    this.dispatchEvent(new Event(Event.COMPLETE));
    ...
}

//不继承.
import AS2.events.Event;
import AS2.events.CFEventDispatcher;
class className
{
    public var addEventListener:Function;
    public var removeEventListener:Function;
    private var dispatchEvent:Function;
    
    public function className()
    {
        //此方法要在使用 dispatchEvent 方法前被执行.一般放于构造函数中.
        CFEventDispatcher.initialize(this);
    }
    
    ...
    this.dispatchEvent(new Event(Event.COMPLETE));
    ...
}

侦听事件:

//使用自定义函数.
import AS2.events.Event;
import className;
...
var cn:className = new className();
//自定义函数.
function completeHandler(evt:Event):Void
{
    trace(this); //输出: _level0.cn
}
cn.addEventListener(Event.COMPLETE, completeHandler);
...

//使用事件侦听器对象.
import AS2.events.Event;
import className;
...
var cn:className = new className();
//事件同名函数.
function complete(evt:Event):Void
{
    trace(this); //输出: this(指向侦听器对象)
}
cn.addEventListener(Event.COMPLETE, this);
...

移除侦听:

//使用自定义函数.
...
cn.removeEventListener(Event.COMPLETE, completeHandler);
...

//使用事件侦听器对象.
...
cn.removeEventListener(Event.COMPLETE, this);
...

AS2.utils.CFDelegate;
AS2.events.Event;
AS2.events.CFEventDispatcher;
这些是什么?下面讲解:

[6.1.创建 CFDelegate 类(修改 Delegate 类)]
CFDelegate 类是 Delegate 类的修改版本.简化了代码(一般不用的功能).提高了执行效率.

此类文档详细:
Classes/AS2/utils/CFDelegate.as

主类:
打开 CFDelegate.as 文档.输入下面的代码:

class AS2.utils.CFDelegate
{
    public static function create(scope:Object, method:Function):Function
    {
        var f:Function = function ()
        {
            method.apply(scope, arguments);
        };
        return f;
    }
}

保存文档.

[6.2.创建 CFEventDispatcher 类(修改 EventDispatcher 类)]
CFEventDispatcher 类是 EventDispatcher 类的修改版本.简化了代码(一般不用的功能).提高了执行效率.

此类文档详细:
Classes/AS2/events/CFEventDispatcher.as

主类:
打开 CFEventDispatcher.as 文档.输入下面的代码:

*/
//----------------------------------------
class AS2.events.CFEventDispatcher
{
    //----------------------------------------
    //构造函数
    public function CFEventDispatcher(){}
    //----------------------------------------
    //当不继承此类时,此属性才有效.
    private static var _ed:CFEventDispatcher;
    //----------------------------------------
    private static function _removeEventListener(queue:Object, handler):Void
    {
        /*
        这里主要用于删除事件数组中的事件处理器.
        */
        if (queue != undefined) {
            var l:Number = queue.length;
            while(l--){
                if(queue[l] == handler){
                    queue.splice(l, 1);
                    return;
                }
            }
        }
    }
    //当不继承此类时.此方法有效.
    public static function initialize(o:Object):Void
    {
        /*
        如果没有继承此类,而是使用 initialize 此方法时, _ed 等于 undefined.然后创建此类的实例.
        最后将事件通知和侦听器管理功能添加到 initialize 方法中的对象 o.
        前面所讲的不继承此类时需添加的三个方法,其实是四个.还有 dispatchQueue 方法.但此方法在
        调用 dispatchEvent 方法时就会自动调用.可能有人会问,为什么没有定义就能调用?因为在函数
        中可以操作对象.从而对对象动态添加方法和属性.这里就是用了在函数中操作对象.
        */
        if (_ed == undefined) {
            _ed = new CFEventDispatcher();
        }
        o.addEventListener = _ed.addEventListener;
        o.removeEventListener = _ed.removeEventListener;
        o.dispatchEvent = _ed.dispatchEvent;
        o.dispatchQueue = _ed.dispatchQueue;
    }
    //----------------------------------------
    private function dispatchQueue(queueObj:Object, eventObj:Object):Void
    {
        /*
         这里主要用于判断事件处理器是对象还是函数.
        */
        if (queueObj[eventObj.type] != undefined) {
            for (var i:String in queueObj[eventObj.type]) {
                var o = queueObj[eventObj.type][i];
                if (typeof (o) == "object" || typeof (o) == "movieclip") {
                    //调用对象中的handleEvent函数.
                    //if (o.handleEvent != undefined) {
                        //o.handleEvent(eventObj);
                    //}
                    //调用对象中的事件同名函数.  
                    //if (o[eventObj.type] != undefined) {
                        o[eventObj.type](eventObj);
                    //}
                } else {
                    //调用自定义函数.
                    o.apply(queueObj, [eventObj]);
                }
            }
        }
    }
    public function dispatchEvent(eventObj:Object):Void
    {
        //将事件源始终指向this(应用此类的对象).
        eventObj.target = this;
        //此句对动态类,或在类中定义"事件名Handler" 这样的函数时才有效.在这里我注释了这句.你如果你想用,可以启用它.
        /*
        用法: 对象.事件名Handler = function(evt:Object){};
        */
        //this[eventObj.type   "Handler"](eventObj);
        this.dispatchQueue(this, eventObj);
    }
    public function addEventListener(event:String, handler):Void
    {
        //这里可以这样理解:
        /*
        使用
        addEventListener("click", 事件处理器);
        添加事件.
        这时, this["click"] 就等于 undefined.
        (this["click"] == undefined) = true
            然后将创建一个新数组来存储事件处理器.
            this["click"] = [];
        然后执行
        CFEventDispatcher._removeEventListener(this["click"], 事件处理器);
        来检测此事件是否有相同的事件处理器.如果是就删除它.
        举个例:当你在一个网站注册用户名时.网站的注册程序会从数据库中检测是否有与你相同的用户名.
        如果有将会提示你重新输入用户名(在这里就是直接删除了).如果没有就会注册成功(这里就在后面
        执行 push).但是网站的注册程序不会从数据库中检测是否有与你相同的密码.
        
        就是说一个事件,可添加多个不同的事件处理器,但不能添加相同的事件处理器.
        当添加新的事件时,也是一样的
        
        最后使用
        this["click"].push(事件处理器);
        将事件处理器添加到事件数组.
        */
        if (this[event] == undefined) {
            this[event] = new Array();
        }
        //ASSetPropFlags 是隐藏的方法.用它和不用它貌似没有区别.大家可以研究下.
        //_global.ASSetPropFlags(this, event, 1);
        CFEventDispatcher._removeEventListener(this[event], handler);
        this[event].push(handler);
    }
    public function removeEventListener(event:String, handler):Void
    {
        //这里我就不啰嗦了.
        CFEventDispatcher._removeEventListener(this[event], handler);
    }
    //----------------------------------------
}

保存文档.

[6.3.创建 Event 类(事件基类,继承 Object 类)]
你可以把它看作事件对象.因应它的工作就是生成事件对象.

此类文档详细:
Classes/AS2/events/Event.as

主类:
打开 Event.as 文档.输入下面的代码:

class AS2.events.Event extends Object
{
    //----------------------------------------
    //事件的常数名.
    public static var COMPLETE:String = "complete";
    public static var CANCEL:String = "cancel";
    public static var CHANGE:String = "change";
    public static var CLOSE:String = "close";
    public static var CONNECT:String = "connect";
    public static var FULLSCREEN:String = "fullScreen";
    public static var OPEN:String = "open";
    public static var REMOVED:String = "removed";
    public static var RESIZE:String = "resize";
    public static var SCROLL:String = "scroll";
    public static var SELECT:String = "select";
    //----------------------------------------
    public var type:String;
    public var target:Object;
    //----------------------------------------
    private var className:String = "Event";
    //----------------------------------------
    //构造函数.
    public function Event(type:String)
    {
        this.type = type;
    }
    //----------------------------------------
    public function toString():String
    {
        var str:String = "";
        for (var i:String in this) {
            if (this[i] != undefined) {
                str  = i   "="   this[i]   " ";
            }
        }
        return "["   this.className   " "   str.slice(0,str.length - 1)   "]";
    }
    //----------------------------------------
}

保存文档.

此类包含下面内容:
1.事件的常数名.如:

    public static var COMPLETE:String = "complete";
    ...

2.基本的属性.如:

    public var type:String;
    ...

3.className 属性.如:

private var className:String = "Event";

4.构造函数.如:

    public function Event(type:String)
    {
        this.type = type;
    }
5.toString() 方法.如:

    public function toString():String
    {
        var str:String = "";
        for (var i:String in this) {
            if (this[i] != undefined) {
                str  = i   "="   this[i]   " ";
            }
        }
        return "["   this.className   " "   str.slice(0,str.length - 1)   "]";
    }

如果你嫌此方法阻碍你的执行效率.可以改成如下(标准):

    public function toString():String
    {
        return "[object "   this.className   "]";
    }

这里讲下 toString() 方法.在类中定义此方法.在输出此类实例名实调用此方法.如:

class className
{
    ...
    private var className:String  = "className";
    public function toString():String
    {
        return "[object "   this.className   "]";
    }
    ...
}


import className;
var cn:className = new className();
trace(cn);// 调用 toString() 方法.输出: [object className]

当然你也可以改成 AS3 中 Event 类一样的方法.但没有必要,很少会用到.
如果要向 Event 类传递参数和定义新的事件名,请看下面.

[6.4.创建 IOErrorEvent 类(错误事件类,继承 Event 类)]
此类文档详细:
Classes/AS2/events/IOErrorEvent.as

主类:
打开 IOErrorEvent.as 文档,输入下面的代码:

import AS2.events.Event;
//----------------------------------------
class AS2.events.IOErrorEvent extends Event
{
    //----------------------------------------
    //事件的常数名.
    public static var IO_ERROR:String = "IOError";
    //----------------------------------------
    //属性参数.
    public var text:String;
    //----------------------------------------
    //className 属性
    private var className:String = "IOErrorEvent";
    //----------------------------------------
    //在构造函数中添加参数.
    public function IOErrorEvent(type:String, text:String)
    {
        super(type);
        this.text = text;
    }
    //----------------------------------------
    
}

保存文档.

[6.5.创建 HTTPStatusEvent 类(http状态事件类,继承 Event 类)]
此类文档详细:
Classes/AS2/events/HTTPStatusEvent.as

主类:
打开 HTTPStatusEvent.as 文档.输入下面的代码:

import AS2.events.Event;
//----------------------------------------
class AS2.events.HTTPStatusEvent extends Event
{
    //----------------------------------------
    //事件的常数名.
    public static var HTTP_STATUS:String = "httpStatus";
    //----------------------------------------
    //属性参数.
    public var status:Number;
    //----------------------------------------
    //className 属性
    private var className:String = "HTTPStatusEvent";
    //----------------------------------------
    //在构造函数中添加参数.
    public function HTTPStatusEvent(type:String, status:Number)
    {
        super(type);
        this.status = status;
    }
    //----------------------------------------
    
}

保存文档.

[6.6.示例: EventClass 类(简单的示例)]
此示例文档详细:
Example/AS2/events/Event/EventClass.as
Example/AS2/events/Event/EventExample.as
Example/AS2/events/Event/EventExample.xml
Example/AS2/events/Event/EventExample.fla

主类:
打开 EventClass.as 文档.输入下面的代码:

import AS2.utils.CFDelegate;
import AS2.events.Event;
import AS2.events.IOErrorEvent;
import AS2.events.HTTPStatusEvent;
import AS2.events.CFEventDispatc
    


            


作者:gdgzboy@牛C网
地址:http://www.niuc.net/post/1960/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!



评论(0) | 引用(0) | 阅读(193)
发表评论
昵称 [注册]
密码 游客无需密码
网址
电邮
打开HTML 打开UBB 打开表情 隐藏 记住我