新手教程-Flex事件讲解

新手教程-Flex事件讲解

关于flex事件的讲解

一.引

很多新人对Flex的事件机制都不太熟悉,在使用过程中难免会出现各种问题,这是一个非常普遍的问题,为了更快更好的帮助大家,将介绍一下Flex中事件的各种机制和用法。

Flex的精髓之一就是事件和绑定机制,了解之后,能帮助大家更灵活的设计程序,也对新手上路有一定的帮助。

讲解可能不太系统,也不全面,有很多没有深入。如果高手看到后有疑问,欢迎指正。当然各位也可以提出自己的看法,或者经验分享,谢谢。

二.事件机制介绍

1.      什么是事件机制

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

大致示意图

 附件: 您所在的用户组无法下载或查看附件

该示意图对应的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>


在我们写代码时,编辑器的代码补全提示列表中,有很多不同的图标,如图

 附件: 您所在的用户组无法下载或查看附件
那些带有闪电的就是事件,三个小块的就是样式,空心圆圈的是属性,实心圆点的是公有方法,还有一个是效果。

我们能在这个列表中看到的事件,我把它称之为事件注册通道。(官方仍然称它为事件,但是它又和普通的事件含义不同。关于事件注册通道会再下面讲述到)

2.      事件注册通道

上面说到了,这些通道是只能在mxml的代码提示中可以看到的,他的作用就是给mxml组件提供 事件触发时所执行的方法的注册通道,而且能在代码提示中可见,这样给组件提供了很大的抽象的好处,我们可以很清楚的告诉组件的使用者,组件里包含哪些事件给你调用。
为什么把他区别对待?除了代码提示外,他还有一些实现上的不同。

Button的click事件是继承自核心类InteractiveObject,遗憾我们看不到他的源码,但是说明了“事件注册通道”是可以继承的。

我们会在自定义事件中讲述到如何声明“事件注册通道”。

3.      事件触发方法

注册通道中如果填入了函数,那么就代表触发该事件时,会执行这个方法。

click="clickHandler(event)"

我们看到这个方法有一个event对象作为参数传入,新人可能会问到,这个event对象哪里来的?我也没声明这个变量啊。他实际上是注册通道传给他的,默认变量名就是event。我们如果想在事件触发时传其他的参数,可以通过自定的事件对象来实现。

这个对象就是这个组件分发的事件对象,即type为“click”的MouseEvent的一个实例。

这个event对象包含了触发该事件时的各种信息,比如触发事件对象是哪个,监听对象是哪个,触发时鼠标点在哪里等等,不同的event类会包含不同的属性,比如KeyboardEvent包含了键盘点击了哪个键。

我们也可以通过自定义一个事件类,来传递我们自己想要的各种信息。(这在后面将介绍到)

4.      事件分发(重点了)

最终继承自EventDispatcher的对象都会含有dispatchEvent这个方法,他有一个参数,事件对象。

之前说到的事件注册通道,他只是一个通道,实际上事件是由这个方法来分发出去的,通道只是一个管道而已。

他的作用就是分发一个事件对象,他的分发是没有目的的,一种广播形式的,Flex的事件监听线程会接收到各种各样的事件(我们称之为捕获事件,这在后面会介绍到),那么哪种才是你要的事件,标识就通过事件的type属性来区分。

1)事件对象
在分发事件时,将会分发一个事件对象出去。不管是那个事件类,都是继承自flash.events.Event对象的,他包含一些比较重要的属性,type和bubbles。
type是事件的类型,事件监听通过这个参数来识别是否是自己所监听的事件。
bubbles是个布尔值,决定了该对象是否会向上传递。默认是false。什么意思呢?画个图就明白了。
比如说,当button组件分发click事件对象时,设置的bubbles为false,那么他的分发是这样的

示意代码
dispatchEvent(new MouseEvent( “click” , false ));

 附件: 您所在的用户组无法下载或查看附件

事件对象无法跨越组件本身,当然,除了之前讲到的注册通道(这样就很形象了吧)

因此,如果没有注册通道,在Flex主应用中,就无法捕获到这个button组件分发出的事件。

如果我们将Bubbles设为true,他看起来就是这样
dispatchEvent(new MouseEvent( “click” , true ));

 附件: 您所在的用户组无法下载或查看附件

可以看到,这个事件可以跨过组件本身,到达Flex主应用里。不止这样,在帮助手册中明确说到,如果在传递过程中间一直没有被捕获的话,这个事件会逐层上传,直到最终的stage,那时如果还没被捕获,这个事件就会被销毁掉。

这样一来,即使我们没有click的事件通道,只要我们在Flex主应用中添加事件监听器(addEventListener)那么我们就可以获得到这个分发出的click事件了。

那么,注册通道不是没用了吗?不是,之前说到过,注册通道是现式的,可见的,因此如果你的组件要给其他人使用,那么就非常一目了然,而不必知道你源码中究竟分发了什么事件。但是,不要监听和注册同一个事件,这样会重复执行的。(后面将讲到)

5.      事件监听

在分发中,我们讲到,如果不是通过注册通道来调用触发事件,那么我们是需要一个监听来捕捉的。如何捕捉到分发出的事件,就是通过事件的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对象参数在执行时动态的传递。(如果熟悉ajax的朋友这里应该很容易懂了)

他作用起来就是这样

 附件: 您所在的用户组无法下载或查看附件

如果你又注册了click的事件通道,那么这两个都会生效,显然这是多余的。

      6.  关于异步和执行顺序

以前的说法有误,as里是不存在线程概念的,在远程请求时,结果事件、错误事件都是异步的。如果你需要处理结果,需要利用监听,并在回调中获取你的远程数据。
而在处理本地事件时,他们仍然是同步的。(谢谢ltian 的指正)

异步示意图

 附件: 您所在的用户组无法下载或查看附件

上图可以看出,回调方法执行的顺序甚至还不如dispatchEvent之后的方法。如果接下来的方法依赖于事件回调,那么把接下来的方法写到回调方法中去

 附件: 您所在的用户组无法下载或查看附件

三.绑定机制

      在我们了解了事件机制后,那么理解绑定就不难了。绑定其实也是事件机制的运用

      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是动态构造的上百个,你不会去一个个的改变他吧。

因此,我们多数会将一个数据源进行绑定声明,这样引用了这个数据源的控件,比如datagrid,在数据源发生了改变时,即使你不重新设置dataProvider,列表的数据也会刷新。当然,还有很多应用等待你去尝试。

如果这个代码中取消了[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>


附件是该讲解的doc文档,有代码色彩高亮

附件附件:

您所在的用户组无法下载或查看附件

最后编辑cimmicola 最后编辑于 2008-06-16 12:35:47
Protoss拥有高度的文明、先进的科技和强大的精神力量。但是由于长达千年的寿命,种群数量稀少,消耗不过繁殖能力出众的Zerg,险些被Zerg给灭族。
 

回复:新手教程-Flex事件讲解

恩 辛苦LZ的 学习了
 

回复:新手教程-Flex事件讲解

很好,支持一个!
 

回复:新手教程-Flex事件讲解

斑竹辛苦了!
 

回复:新手教程-Flex事件讲解

很好,很强大
作为新手教程相当好,居然还配了图,LZ辛苦,我拿去给公司的人做培训了^ ^
不过指出小瑕疵一个:flex中是没有线程概念的,它的基本机制类似于磁带播放.
不过瑕不掩瑜,感谢LZ做的工作
 

回复:新手教程-Flex事件讲解

之前关于异步时我也提到过,是类似js那样的异步,当然js也是没线程的。纠正一下,以免大家误解,说成线程是为了更好的理解异步。
不过没有线程是针对开发者来说的,他是不支持多线程的处理。
Protoss拥有高度的文明、先进的科技和强大的精神力量。但是由于长达千年的寿命,种群数量稀少,消耗不过繁殖能力出众的Zerg,险些被Zerg给灭族。
 

回复:新手教程-Flex事件讲解

这样的帖子 不顶对不起自己,对不起党和人民:D
 

回复:新手教程-Flex事件讲解

楼主再写几个吧,flex component, flex binding, flex draganddrop, flex ****, 然后直接拿过来就能出版Flex 第二步了。 hoho.
强烈支持技术贴

补充一下,其实Event一开始不是从自身开始往根目录搜索listener,参照Flex官方文档,当一个Event被触发后, 有三个步骤
First, capturing
Next, targeting
Finally, bubbling
所以,第一步其实是从根目录开始往这个Event开始检索。不过 capturing的初始值是false,并且很少有人使用。Flex2_devguide 114页这么写:
By default, no container listens during the capturing phase. The default value of the
use_capture argument is false. The only way to add a listener during this phase is to pass
true for the use_capture argument when calling the addEventListener() method, as the
following example shows:
myPanel.addEventListener(MouseEvent.MOUSE_DOWN, clickHandler, true);
If you add an event listener inline with MXML, Flex sets this argument to false; you cannot
override it.
If you set the use_capture argument to true—in other words, if an event is propagated
through the capturing phase—the event can still bubble, but capture phase listeners will not
react to it. If you want your event to traverse both the capturing and bubbling phases, you
must call addEventListener() twice: once with use_capture set to true, and then again
with use_capture set to false.
The capturing phase is very rarely used, and it can also be computationally intensive. By
contrast, bubbling is much more common.
最后编辑wabjtanm 最后编辑于 2007-11-24 00:17:11
 

回复:新手教程-Flex事件讲解

很不错,真的很不错
 

回复:新手教程-Flex事件讲解

好文章,先下再看!
 

回复:新手教程-Flex事件讲解

看了
学习中~~~
 

回复:新手教程-Flex事件讲解

写得很好,帮我梳理了基础知识
 

回复:新手教程-Flex事件讲解

谢了啊!
:'(
 

回复:新手教程-Flex事件讲解

下载了先看看!但是对诸如具体的dispatchEvent,Bindable是起什么样的作用还是不大明白。
因为需要!所以学习!
 

回复:新手教程-Flex事件讲解

太感谢了
 

回复:新手教程-Flex事件讲解

super(s);????????????????????????????????????????
这个怎么理解啊???S哪里来的?
 

回复:新手教程-Flex事件讲解

UP!!!!!!!!!!!!!!!!!!!!!!!!
 

回复: 新手教程-Flex事件讲解

不错!
支持,过几天要做一个FLEX2的工程,不错的入门!
 

回复:新手教程-Flex事件讲解

LZ辛苦了,讲解的很详细,对我们初学者很有用,谢谢
 

回复:新手教程-Flex事件讲解

谢谢分享
 
1  /  4  页   1234 跳转

版权所有 riachina.com   Sitemap

Powered by Discuz!NT 2.1.202    Copyright © 2001-2008 Comsenz Inc.
Processed in 0 second(s) (Cached).
返顶部