flex---->事件

Flex事件概述

Flash/Flex中的事件是编写应用的基础,是和用户交互的基础。应用和用户之间的交互就是以事件为桥梁。

应用对用户动作的响应相当于应用和外界的交互,而应用之间也有需要响应的事情,这相当于内部的交互。举个例子来说,用户单击了某个按钮,程序就应该做某些事情,这就是用户和外界的交互;而应用中某个数据的改变,应用其他部分也要随其做相应的改变就是内部交互。

Flex事件机制

1.什么是事件机制
事件可以看作是一种触发机制,当满足了一定的条件后,会触发这个事件。比如MouseEvent就是指的当鼠标进行操作之后触发的一系列的事件。很多控件中都有click事件,这个事件就是一个MouseEvent的实例,当点击鼠标后,系统会自动抛出一个名称为click的MouseEvent事件。如果此时在click上注册一个方法,那么触发该事件时就会执行这个方法。

事件的机制包括注册事件、触发事件、事件的传递

事件注册:指将事件的处理函数指定给对象的一个事件,实际上是对该事件创建一个侦听器。事件被注册后,当事件发生后,就会调用注册的事件响应函数。

事件触发:注册到对象上的事件发生时,就是事件的触发。事件触发后会调用注册在该事件上的事件响应函数,同时创建事件对象的一个实例,该实例会包含事件的信息。一个事件的信息包括以下几种:

1)属性bubbles:布尔类型,显示该事件是否为冒泡事件;

2)属性cancelable:布尔类型,显示是否可以阻止与事件相关联的行为;

3)对象currentTarget:与当前事件相关联的对象。

4)属性eventPhase:无符号整数,指示当前事件在整个事件流中的阶段;

5)对象Target:触发事件的对象。也就是整个事件流的源头。在实际过程中使用currentTarget来处理事件的当前目标;

6)字符串type:当前事件的类型。如事件是click,那这个值就是click。

一个事件被触发后,一般经历3个阶段,第一阶段就是捕获阶段,Flex应用是一层一层的关系,比如顶级Application里面有一个容器Canvas,而Canvas里面有一个VBox,真正发生事件的是VBox里的一个按钮。当用户单击这个按钮时,实际上该事件会经历3个对象,第一个就是Application,第二个就是Canvas,第三个是VBox,最后才是事件注册的对象按钮。Click事件自上而下的进行查找点击对象的工作,这个过程就是捕获阶段。第二个阶段是目标锁定阶段,当自上而下找到事件注册并触发的对象时,Flex将会自动创建一个Event的实例。这个实例包括整个事件的相关信息。第三个阶段就是冒泡阶段,与前面捕获阶段相反冒泡阶段就是时间会向上一级传递。

事件传递:对于处理时间来说,事件的传递是关键。一个事件被触发后,事件就开始冒泡,形成了一个事件流。

Flex事件分发

最终继承自EventDispatcher的对象都会含有dispatchEvent这个方法,他有一个参数,事件对象。之前说到的事件注册通道,他只是一个通道,实际上事件是由这个方法来分发出去的,通道只是一个管道而已。他的作用就是分发一个事件对象,他的分发是没有目的的,一种广播形式的,Flex的事件监听线程会接收到各种各样的事件(我们称之为捕获事件,这在后面会介绍到),那么哪种才是你要的事件,标识就通过事件的type属性来区分。

1)Flex事件对象

在分发事件时,将会分发一个事件对象出去。不管是那个事件类,都是继承自flash.events.Event对象的,他包含一些比较重要的属性,type和bubbles。
type是事件的类型,事件监听通过这个参数来识别是否是自己所监听的事件。
bubbles是个布尔值,决定了该对象是否会向上传递。默认是false。什么意思呢,
比如说,当button组件分发click事件对象时,设置的bubbles为false,
dispatchEvent(newMouseEvent(“click”,false));
事件对象无法跨越组件本身,当然,除了之前讲到的注册通道(这样就很形象了吧)因此,如果没有注册通道,在Flex主应用中,就无法捕获到这个button组件分发出的事件。如果我们将Bubbles设为true,
这个事件可以跨过组件本身,到达Flex主应用里。不止这样,在帮助手册中明确说到,如果在传递过程中间一直没有被捕获的话,这个事件会逐层上传,直到最终的stage,那时如果还没被捕获,这个事件就会被销毁掉。这样一来,即使我们没有click的事件通道,只要我们在Flex主应用中添加Flex事件监听器(addEventListener)那么我们就可以获得到这个分发出的click事件了。

一、事件注册通道
通道是只能在mxml的代码提示中可以看到的,他的作用就是给mxml组件提供 事件触发时所执行的方法的注册通道,而且能在代码提示中可见,这样给组件提供了很大的抽象的好处,我们可以很清楚的告诉组件的使用者,组件里包含哪些事件给你调用。
Button的click事件是继承自核心类InteractiveObject,遗憾我们看不到他的源码,但是说明了“事件注册通道”是可以继承的。我们会在自定义事件中讲述到如何声明“事件注册通道”。


该示意图对应的Flex主应用的mxml代码

<mx:Script>
          <![CDATA[
                import mx.controls.Alert;        
                private function clickHandler(e:MouseEvent){
                      Alert.show(e.currentTarget.toString());
                }
          ]]>
</mx:Script>
<mx:Button id="testBtn" click="clickHandler(event)" label="测试">
</mx:Button>

 

1、设计视图下图所示,拖一个Panel、一个Textarea、两个按钮到设计界面。

2、源代码如下所示:

<?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()">

 <fx:Script>
 <![CDATA[
 import mx.utils.OnDemandEventDispatcher;
 import spark.components.TextArea; 
private function recordEvent(e:Event):void
 {
 writeLog(e.target.id + "被点击," + "当前对象" + e.currentTarget.id);
 e.stopPropagation();
 }
 private function writeLog(str:String):void
 {
 ta.text += str + "\n";
 }
 private function clear(e:Event):void
 {
 e.stopPropagation();
 ta.text = "";
 } 
]]>
 </fx:Script>

 <fx:Declarations>
 <!-- 将非可视元素(例如服务、值对象)放在此处 -->
 </fx:Declarations>
 <s:Panel width="204" height="231" click="recordEvent(event)" id="panel" x="15" y="15" title="事件触发与传递" fontSize="12">
 <s:TextArea x="17" y="7" id="ta" width="170"/>
 <s:Button x="17" y="164" label="点击" id="btn" click="recordEvent(event)"/>
 <s:Button x="117" y="164" label="清空" click="clear(event)"/>
 </s:Panel>

</s:Application>

3、编译运行,结果截图如下:

二、事件监听

在分发中,我们讲到,如果不是通过注册通道来调用触发事件,那么我们是需要一个监听来捕捉的。如何捕捉到分发出的事件,就是通过事件的type值。

<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml layout="absolute" xmlns:comp
      creationComplete='init()'
> 
<mx:Script>
                <![CDATA[
private function init(){
                    testBtn.addEventListener(“click”, clickHandler);
}

Flex的事件中都提供了一些静态常量,让我们调用,避免我们打错了。因此这句话可以这么写
testBtn.addEventListener(MouseEvent.CLICK,clickHandler);
我们看到,监听的回调方法中没有传递参数,是的,这和通道的写法有些不同,这里的回调方法(即clickHandler)只是个引用,并不是代表方法的执行,他的含义是,告诉eventLinstener,如果捕捉到click事件,那么就去找clickHandler,并执行它,event对象参数在执行时动态的传递。

三.绑定机制

 在我们了解了事件机制后,那么理解绑定就不难了。绑定其实也是事件机制的运用
1.  什么是绑定
绑定的原理就是事件,在被绑定的对象上增加了改变事件的监听,一旦某个被绑定对象改变后,就会分发一个“propertyChange”事件(默认的,也可以改变成自己定义的事件),在其他组件中,会有propertyChange的事件监听,当捕捉到该事件后,则会去更新组件的属性并显示。
绑定的作用在于,将Flex中的变量、类、方法等与组件的值进行绑定。例如,一个变量如果被绑定后,那么引用该变量的组件的相关属性也会发生改变。我们用一个实例来表示

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml layout="absolute" xmlns:comp
      >
      <mx:Script>
          <![CDATA[
                import mx.controls.Alert;            
                [Bindable]
                private var isSelected:Boolean;
                private function clickHandler(e:MouseEvent){
                //Alert.show(e.currentTarget.toString());
isSelected=isSelected?false:true; //这句话的意思是如果isSelected为true,改变它为false,如果它为false,改变它为true;
                      Alert.show(isSelected.toString());
                }
          ]]>
      </mx:Script>
      <mx:Button id="testBtn"  click="clickHandler(event)" label="测试" />
      <mx:CheckBox x="60" selected="{isSelected}" />
</mx:Application>

上述程序的效果就是,当点击button时,button不是直接改变checkbox的选中状态,而是改变isSelected这个变量,由于isSelected是被绑定了的,那么会关联的改变CheckBox的选中状态。
这样看起来有些多此一举,完全可以直接改变checkbox的selected属性,我只是为了演示一下效果。如果说你的checkbox是动态构造的上百个,你不会去一个个的改变他吧。
如果这个代码中取消了[Bindable]的声明,会怎么样?isSelected不会改变了吗?
isSelected会改变,我们alert出来的结果也会显示结果改变了,但是checkbox的选择状态不会改变,因为当一个组件由创建到最终显示出来时是经过很多方法的,比如addChild,commitProperties,updateDisplayList等,updataDisplayList则是类似刷新显示效果一样的方法。
仅仅改变属性,而不去更新显示效果那么组件不会因为属性的改变而发生任何变化。
  绑定的原理也是利用的事件分发。


四.  自定义事件的分发

1.  自定义事件 components/MyEventTest.as

package components
{
      import mx.events.FlexEvent;
      public class MyEventTest extends FlexEvent
      {
          public static const ONCHANGE:String = "onChange";
          public var eventInfo:String; //自定义的事件信息
          public function  MyEventTest(s:String){
                super(s); //如果在构造时不设bubbles,默认是false,也就是不能传递的。
                eventInfo="这个事件是:"+s;
          }
      }
}

          

2.        自定义组件 components/ComponentForEvent.as

package components
{
      import flash.events.EventDispatcher;
      //这个就是声明事件注册通道的方法了。name是事件对应的名称,也就是之前提到的type。Type是该事件的类
      [Event(name="onChange", type="components.MyEventTest")]
      public class ComponentForEvent extends EventDispatcher
      {
          private var name:String;
          public function changeName(newName:String){
                this.name=newName;
                dispatchEvent(new MyEventTest(MyEventTest.ONCHANGE) );
          }
      }
}

3.        App.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:comp
> 
<mx:Script>
<![CDATA[
import mx.controls.Alert;
private function  changeName(){
                    cfe.changeName("新名称");
}
                ]]>
</mx:Script>
<mx:Button id="testBtn"  click=" changeName ()" label="测试" />
<components:ComponentForEvent
id="cfe"  />
</mx:Application>



 

posted on 2012-08-27 21:51  小-强-斋-太  阅读(138)  评论(0编辑  收藏  举报

导航