Action Script:Flash开发者应该知道的基本知识

第1步:事件框架的简化描述

我深知如果直接开始讲专业术语,你会很难理解事件框架,因此我首先描述一个现实生活中的例子。

整个情形是事件框架的一个比喻,具体情形如下:

我是“计算机艺术”杂志的忠实读者,我每天都等着看最新一期的“计算机艺术”。当我收到新期刊后,开始阅读它。

第2步:分析事件框架的这个比喻

这里一共发生了这么几件事:

1,我收到新的期刊,收到期刊就是一个“事件”。

2, 这个事件发生在某处,发生在我身上,我就是“事件的触发者”。

3,我等待新期刊的到来,我是一个对象,我等待这个事件发生。我就是监听这个事件发生的对象,我是具有“事件性”的对象。这个事件性监听一个特定的事件(收到新的期刊)。

4,当我收到期刊,我开始阅读。当这个事件发生,我做了一些事,执行了一个方法。我就是处理了这个事件。我这时候做的事情就叫做“事件处理器”或者“监听方法”。

第3步:技术术语——事件

我刚才提到的一些东西:

1, 事件

2,事件触发者

3,事件传递者

4,事件处理器/监听方法

“事件”就是一个描述发生了什么的对象,在第1步中对应的是新期刊的到来。大多数情况下,你会看到一个事件被写成类似的结构:

MouseEvent.CLICK

这段代码包含了两部分:

1, MouseEvent 这是一个包含一个或多个事件的类。多采用驼峰式的书写方法。

2,CLICK 这是一个事件类型。多采用纯大写字母。

事件类型其实是一个string类型的静态常量。这听起来很奇怪,但是一个事件其实就是一个字符串。运行如下代码段:

trace(MouseEvent.MOUSE_MOVE);

你会得到这样的输出“mouseMove”。我们刚才trace了MouseEvent类中的静态变量MOUSE_MOVE。事件就是一个字符串!但是这个字符串代表发生了一件事,例如在这里表示鼠标的移动。

第4步:技术术语——事件触发者

一个事件总是在某处发生的。事件发生的地方就是事件触发的地方。触发事件的根源在EventDiapatcher这个类中。一定要认识到,事件在哪儿发生的就是在哪儿触发的。因此,如果movie clip A触发了一个事件,添加到movie clip B上的事件性(将在第5步介绍)是无法接收到这个事件的。

简而言之,所有的显示对象都有内置的dispatchEvent(event:Event)方法。

var myMC:MovieClip = new MovieClip();
myMC.dispatchEvent(new Event(MouseEvent.CLICK));

大多数情况下,你不需要手动地触发事件,事件都是自动触发。例如,如果我点击

movie clip A,就是自动触发事件MouseEvent.CLICK。

第5步:技术术语——事件传递者

当一个特定事件发生的时候,我们作为Flash开发者,希望做些事情来响应这个事件。事件性正是我们需要用的。事件性有点特殊,没有自己单独的类。事件性是添加到一个对象上的。事件是“监听”一个特定事件的一些对象。当这个事件触发时,会调用一个方法,也就是处理器。

实际上,这些并不是addEventListener方法接收的所有参数,还有三个参数我没有写出来。你基本上用不到它们,尤其是当你刚开始使用时间性。让我们看看addEventListener()方法的完整结构。

第6步:事件处理器/监听方法

当一个事件监听的事件发生时,会调用一个方法。这个方法就是“事件处理器”或叫做“监听方法”。

注意处理器中的参数,这个参数是必不可少的。监听方法只有一个参数,并且不运行有多个。事件本身会包含自身的信息,这个会在第9步中介绍。

第7步:添加事件n和处理器

现在,我想要myMC来响应触发的事件,因此我添加一个事件和一个处理器方法。代码如下:

//create our myMC movie clip
var myMC:MovieClip = new MovieClip();

//let myMC dispatch the event MouseEvent.CLICK
myMC.dispatchEvent(new Event(MouseEvent.CLICK));

//add an event listener to myMC, that listens to the event MouseEvent.CLICK, and will call clickHandler
myMC.addEventListener(MouseEvent.CLICK, clickHandler);

//define the handler function
function clickHandler (event:Event){
trace("I heard the event MouseEvent.CLICK");
}

然后测试你的影片(Windows:Ctrl+Enter,Mac:cmd+Enter,这里用的是Flash Authoring Tools开发环境)。

你是否看到输出了?没有?呵呵,我也没有。我们会在下一步看看到底怎么回事。

第8步:代码顺序

那么,到底怎么回事呢?这不可能是语法错误,至少我没有看到任何报错信息。的确,这不是技术上的错误。再看一遍代码,这次要谨记,代码是一行一行执行的:

//create our myMC movie clip
var myMC:MovieClip = new MovieClip();

//let myMC dispatch the event MouseEvent.CLICK
myMC.dispatchEvent(new Event(MouseEvent.CLICK));

//add an event listener to myMC, that listens to the event MouseEvent.CLICK, and will call clickHandler
myMC.addEventListener(MouseEvent.CLICK, clickHandler);

//define the handler function
function clickHandler (event:Event){
trace("I heard the event MouseEvent.CLICK");
}

希望你已经认识到错在哪里了:事件是在添加到myMC上之前触发的。这时候再添加事件已经晚了,事件已经发生过了。幸运的是这很好解决,只用改变一下顺序,先添加事件,然后再触发事件:

//create our myMC movie clip
var myMC:MovieClip = new MovieClip();

//add an event listener to myMC, that listens to the event MouseEvent.CLICK, and will call clickHandler
myMC.addEventListener(MouseEvent.CLICK, clickHandler);

//let myMC dispatch the event MouseEvent.CLICK
myMC.dispatchEvent(new Event(MouseEvent.CLICK));

//define the handler function
function clickHandler (event:Event){
trace("I heard the event MouseEvent.CLICK");
}

我们为什么要做这个测试呢?因为你很可能会遇到这样的问题,并且要找出问题所在可能会花一番功夫。提前在这里指出这个问题并教你怎样解决。

第9步:事件参数

事件处理函数有一个参数:事件参数。这个参数包含事件本身和事件触发者的数据信息。这个参数包含一些我们需要介绍的属性。下面是一些经常要用到的参数列表:

1, target:这个属性返回目标对象,也就是事件的触发者。

2, currentTarget:这个属性返回事件流中的当前目标对象,我们将在第10步讨论事件流。

3, type:这个属性返回事件字符串。这个值多用小驼峰书写,MOUSE_DOWN的值为mouseDown。

使用这个,我们可以对不同类型的事件使用同一个处理器。怎么做呢?我们会在下一步讨论。

第10步:多个事件,一个监听方法

先让我们来看一段代码:

stage.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, upHandler);

function downHandler(event:MouseEvent){
trace("Down");
}

function upHandler(event:MouseEvent){
trace("Up");
}

我们使用了两个事件,名为MouseEvent.MOUSE_DOWN和MouseEvent.MOUSE_UP。第一个事件是在鼠标的按钮被按下并保持按下时触发。当你释放这个按钮时,事件MouseEvent.MOUSE_UP触发。释放后,鼠标按钮弹起。

现在我们可以使用一个处理器来取代两个处理器(一个叫downHandler,一个叫upHandler)。删除刚才代码,写下面的代码:

stage.addEventListener(MouseEvent.MOUSE_DOWN, handler);
stage.addEventListener(MouseEvent.MOUSE_UP, handler);

function handler(event:MouseEvent){
trace("Something has occurred...");
}

好了,现在已经创建了处理器并且正常工作了,但是我们想让处理器可以根据捕获的事件来做不同的事情。幸运的是,我们可以使用event.type。具体使用如下:

stage.addEventListener(MouseEvent.MOUSE_DOWN, handler);
stage.addEventListener(MouseEvent.MOUSE_UP, handler);

function handler(event:MouseEvent){
if(event.type == "mouseDown"){
trace("Down");
}else{
trace("Up");
}
}

第11步:事件流

现在假设一个点击事件发生在一个影片剪辑上,命名为mcA。这个事件并不是简单的分配给mcA,而是流经整个播放器。这个事件流动的机制称为“事件流”,想一想事件是怎样在播放器中流动的。

事件从“舞台”的顶层开始,然后流经mcA的父节点,直到mcA。再从mcA向回“冒泡”,回到“舞台”。

太酷了,但是有什么用呢?因为现在我们知道一个事件会流经触发者的所有父节点,就可以使用一个事件,捕获多个对象触发的事件。

第12步:多个对象,一个事件

好了,让我们在一些多影片剪辑里创建影片剪辑。你可以自己做,也可以直接下载提供的文件。

我们创建3个影片剪辑,并将其实例取名为redMC,blueMC和greenMC。然后将他们都放在一个更大的名为container的影片剪辑中。

现在,我们开始写代码。我已经创建了一个名为Actions的层,你需要在这个层里写代码。首先,为container添加事件,监听MouseEvent.CLICK事件,事件处理器名为clickHandler。

container.addEventListener(MouseEvent.CLICK, clickHandler);

function clickHandler(event:MouseEvent){
//function body
}

你可以看到,事件是被redMC触发的,然而事件还是要通过“冒泡”回到container的。container添加的事件性可以监听到这个事件,会调用性方法clickHandler。对于blueMC和greenMC也是如此。

下面我们要使用event.target,因为event.target是事件的触发者,这里事件触发者是redMC。那么我们怎样使用event.target呢?我们可以验证event.target.name,这会将实例的名字以string类型返回。因此我们可以使用普通的if语句:

container.addEventListener(MouseEvent.CLICK, clickHandler);

function clickHandler(event:MouseEvent){

if(event.target.name == "redMC"){

trace("Red");

}

if(event.target.name == "blueMC"){

trace("Blue");

}

if(event.target.name == "greenMC"){

trace("Green");

}

}

第13步:常用的事件

现在你已经对事件框架有了很好的理解,然而有些时候为实现某些功能,最重要的是知道该用哪个事件。要查找所有的事件,可以访问ActionScript 3.0语言和组件参考。只需要点击事件容器类,例如MouseEvent,看看都有什么事件。

第14步:MouseEvent.MOUSE_MOVE

这个事件在用户移动鼠标的时候发生。如果你为名为myMC的影片剪辑添加这个事件性,你就会知道鼠标什么时候划过myMC。

myMC.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);

function mouseMoveHandler(event:MouseEvent){

trace("Your mouse is moving over myMC");

}

第15步:MouseEvent.MOUSE_OVER

这个事件在用户将鼠标移入到对象上面时触发。此事件只在用户将光标由另一个对象移动到本对象上时触发。在本对象上移动鼠标就不再触发MouseEvent.MOUSE_OVER事件了,而会触发MouseEvent.MOUSE_MOVE事件。

 myMC.addEventListener(MouseEvent.MOUSE_OVER, overHandler);function overHandler(event:MouseEvent){

trace("You just moved the mouse on myMC");

}

第16步:MouseEvent.MOUSE_OUT

这个事件正好与MouseEvent.MOUSE_OVER事件相反。当用户的光标移出对象时触发。

myMC.addEventListener(MouseEvent.MOUSE_OUT, outHandler);

function outHandler(event:MouseEvent){

trace("You just moved the mouse out myMC");

}

第17步:MouseEvent.MOUSE_DOWN

这个事件会在鼠标的主键被按下,或者一直被按下时触发。

myMC.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);

function downHandler(event:MouseEvent){

trace("The primary mouse button is pressed down on myMC");

}

第18步:MouseEvent.MOUSE_UP

这个事件正好与MouseEvent.MOUSE_DOWN事件相反。当用户释放鼠标主键时,事件MouseEvent.MOUSE_UP触发。

myMC.addEventListener(MouseEvent.MOUSE_UP, upHandler);

function upHandler(event:MouseEvent){

trace("The primary mouse button has been released, while it was hovering over myMC");

}

第19步:MouseEvent.CLICK

此事件的名字已经很清楚地表明了事件什么时候被触发,这个事件在用户点击鼠标按键时触发。

myMC.addEventListener(MouseEvent.CLICK, clickHandler);

function clickHandler(event:MouseEvent){

trace("You just clicked myMC");

}

第20步:MouseEvent.DOUBLE_CLICK

这个事件在用户双击鼠标按钮时触发。值得注意的是当MouseEvent.DOUBLE_CLICK事件触发时,MouseEvent.CLICK事件已经是第二次发生了。

myMC.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);

function doubleClickHandler(event:MouseEvent){

trace("You just double clicked myMC");

}

如果你现在测试你的影片,双击鼠标,什么都没有发生。为什么呢?默认情况下,影片剪辑(包括大部分的显示对象)将doubleClickEnable属性设置为false。因此MouseEvent.DOUBLE_CLICK事件不会被触发。只需要将其设置为true,一切都会正常工作。

myMC.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);

function doubleClickHandler(event:MouseEvent){

trace("You just double clicked myMC");

}

myMC.doubleClickEnabled = true;

第21步:Event.ENTER_FRAME

这个事件会在对象进入下一帧时触发(是的,听起来有点奇怪)。基本上这个事件触发的频率与帧率相同。意思是,如果你的影片帧率为30 fps,这个事件每秒会调用30次。这个事件用来干什么呢?你可以使用这个事件让物体渐渐变化。例如,你能以帧率让一个对象的横坐标增加5。

myMC.addEventListener(Event.ENTER_FRAME, enterFrameHandler);

function enterFrameHandler(event:Event){

myMC.x += 5;

}

第22步:Event.COMPLETE

这个事件会在对象完成自己正在做的事情后触发。大多数情况下,你将在载入什么东西或者播放一些媒体格式的时候使用它。一个URLLoader会载入一个URLRequest,在URLLoader载入完成后,我们要将这些数据载入另一个loader中,再将其添加到舞台上。

var myURLRequest:URLRequest = new URLRequest("xxx");

var myURLLoader:URLLoader = new URLLoader(myURLRequest);

myURLLoader.dataFormat = URLLoaderDataFormat.BINARY;

 

myURLLoader.addEventListener(Event.COMPLETE, completeHandler);

function completeHandler(event:Event){

var loader:Loader = new Loader();

loader.loadBytes(myURLLoader.data);

addChild(loader);

}

第23步:Event.RESIZE

当flash应用嵌入到的flash播放器或者页面的尺寸发生变化时,这个事件被触发。使用这个事件,你可以在尺寸变化后重新放置对象的位置。

stage.addEventListener(Event.RESIZE, resizeHandler);

function resizeHandler(event:Event) {

trace("The dimensions of the stage are "+stage.stageWidth+" x "+stage.stageHeight);

}

第24步:KeyboardEvent.KEY_DOWN

这个事件在键盘上的任何按键被按下时触发。

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

function keyDownHandler(event:KeyboardEvent){

trace("You just pressed a key!");

}

第25步:KeyboardEvent.KEY_UP

这个事件与KeyboardEvent.KEY_DOWN事件正好相反,在任意按键被释放时触发。

stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);

function keyUpHandler(event:KeyboardEvent){

trace("You just released a key");

}

第26步:使用内置的按键布尔值

当然,响应任意按键确实没有什么用(除了屏保),因此我们需要提取是哪个按键被按下的信息。幸运的是,一些按键被内置到KeyboardEvent类中了,它们都是布尔变量,当被按下时会被置为true。这些内置布尔变量是:

l KeyboardEvent.altKey,当alt键被按下时设置为true。

l KeyboardEvent.commandKey,当command键被按下时设置为true(只适合AIR)。

l KeyboardEvent.controlKey,当control(ctrl)键被按下时设置为true(只适合AIR)。

l KeyboardEvent.ctrlKey,在Windows系统中,当control(ctrl)键被按下时设置为true。但是在Mac系统中,当cmd键被按下时,ctrl键设置为true。

l KeyboardEvent.shiftKey,当shift键被按下时设置为true。

因此,在做一些事情之前,我们可以利用这些来确定哪个键被按下了。

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

function keyDownHandler(event:KeyboardEvent){

if(event.shiftKey){

trace("You just pressed the shift key");

}

}

第27步:使用按键编码

你可能会问,那其它的按键呢?有一个概念叫做“按键编码”。每一个按键都有一个特定的编号:一个按键编码。我们可以验证触发事件的按键的按键编码。event.keyCode将返回一个整数,通过它可以实现这个功能。点击这里查看按键编码清单。虽然是用于javascript的,但是按键编码是相同的。

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

function keyDownHandler(event:KeyboardEvent){

if(event.keyCode == 65){

trace("You just pressed the A key");

}

}

现在,很容易就可以将按键编码存储在一个变量中,直接使用这个变量,就不用按键编码了。

var A:uint = 65;

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

function keyDownHandler(event:KeyboardEvent){

if(event.keyCode == A){

trace("You just pressed the A key");

}

}

第28步:使用字符编码

使用按键编码,大多数情况都能应付,然而有些时候并不是你需要的。例如,a和A字符使用的是相同的按键。但是,我们仍然想要区别这两个字符。事件带有事件触发者的字符编码。

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

function keyDownHandler(event:KeyboardEvent) {

trace(event.charCode);

}

好了,一切正常,但是我们真的需要记住这些字符编码吗?不用,幸运的是我们可以使用charCodeAt()方法,将返回一个字符的字符编码(string类型)。charCodeAt()默认取字符串的第一个字符。charCodeAt(0)是第一个字符,charCodeAt(1)是第二个,以此类推。

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

function keyDownHandler(event:KeyboardEvent){

if(event.charCode == String("a").charCodeAt()){

trace("You just pressed the lowercase a key");

}

}

第20步:聚焦

现在键入如下代码:

myMC.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

function keyDownHandler(event:KeyboardEvent){

trace("You just pressed a key, while being focused on myMC");

}

测试这段代码,无法正常工作!为什么?如果myMC是一个电影剪辑,它不会接受键盘输入,即键盘事件不会在影片剪辑上触发。如果你想让myMC响应,添加事件性到stage上,然后让myMC做一些事情。试着将myMC从影片剪辑改为动态文本域,就能正常工作了。

那么两个动态文本域呢?如果用户键入,两个文本域都会触发事件吗?不会,只有你正在键入的文本域会触发。这就叫做“聚焦”。键盘事件会被获得焦点的对象触发。舞台是唯一一个在其它对象获得焦点的同时,也能获得焦点的对象。

第30步:TimerEvent.TIMER

这个事件是专门为timers服务的。它在一个timer到达延迟事件时触发。意味着设定时间间隔,你可以使用这个事件做一些非常精确的事情。

var myTimer:Timer = new Timer(1000, 5);

myTimer.start();

 

myTimer.addEventListener(TimerEvent.TIMER, timerHandler);

function timerHandler(event:TimerEvent){

trace("one second later...");

}

第31步:TimerEvent.TIMER_COMPLETE

所有的timer有一个可选的第二参数。这个参数用来设置timer的重复次数。意味着当timer到达延迟时间后,会再次启动。如果timer重复了设定的次数后,会触发事件TimerEvent.TIMER_COMPLETE。

var myTimer:Timer = new Timer(1000, 5);

myTimer.start();

 

myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerHandler);

function timerHandler(event:TimerEvent){

trace("The timer has repeated 5 times");

}

总结

Flash的显示列表是一个典型的组合设计模式的实例,父节点和子节点并不是继承的关系,而是组合关系,事件是ActionScript 3.0中对象之间通信的工具。显示对象对于一些鼠标键盘等事件都是自动触发的,不需要手动地调用dispatchEvent()方法。所有的显示对象都继承了EventDispatcher类,都可以触发事件。如果是自定义的一个类想要触发事件必须继承EventDispatcher类,触发事件时也需调用dispatchEvent()方法。

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

下面讨论一下其余的3个参数:

1, useCapture:当设置这个参数为true时,我们讲在捕获阶段监听这个事件。默认情况下,这个参数为false,这样我们会在目标阶段和冒泡阶段监听这个事件。我们将在第10步讨论事件流。

2, priority:虽然看起来所有的事件是同时工作的,其实并非如此。有些情况下,事件之间会相互冲突。这个参数是为了确保一个特定的事件具有比其它事件更高的优先级。

3,useWeakReference:当这个参数设置为true时,就是在监听对象和事件之间创建一个弱连接。什么意思呢?正常情况下,一个对象如果没有引用指向它就会被垃圾回收器回收。当删除一个添加了事件的对象后,如果还有其它引用指向事件,它就还会存在。这在“强内存引用”的情况下发生。使用“弱内存引用”,当添加事件的对象被删除后,事件也会被删除。我个人喜欢将这个参数设置为true(因此我使用的是“弱内存引用”)。

删除一个事件和添加一个同样简单。

//this adds an event listener to the stage

stage.addEventListener(MouseEvent.CLICK, clickHandler);

 

//this removes the event listener added to the stage

stage.removeEventListener(MouseEvent.CLICK, clickHandler);
相关推荐:
一个躺在床上的本本…… 笔记本小巧方便对于有笔记本电脑的朋友来说,肯定喜欢躺在床上使用笔记本悠闲的玩玩游戏或者是看看电影、听听音乐。但是就在你这样使用电脑的时候,你的笔记本也在慢慢的遭受着损耗。 …
将Android开发项目从一台机子转移到另一台机子时,运行AS后报出: Error:CreateProcess error=216, 该版本的 %1 与你运行的 Windows 版本不兼容。请查看计算机的系统信息,然后联系软件发布者。 此问题发生 …
很多人在使用笔记本电脑时遇到过这个情况,可能是无意识下出现的,所以根本无从下手找根源。这里我们将进行分析下,首先无图无真象。 可能你会尝试着重装鼠标的驱动、换个鼠标等等,也许能短时间内解决,但 …
Linux下我们会遇到一个常见的问题,那就是如何修复 /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory 问题,这个问题发生的根源不是安装报出问题,而是平台兼容性问题。 怎么理解,就 …
A类:10.0.0.0-10.255.255.255 B类:172.16.0.0-172.31.255.255 C类:192.168.0.0-192.168.255.255
拿起手机扫一扫即可带走我!