Flex事件講解

          關于flex事件的講解

          一.引

          很多新人對Flex的事件機制都不太熟悉,在使用過程中難免會出現各種問題,這是一個非常普遍的問題,為了更快更好的幫助大家,將介紹一下Flex中事件的各種機制和用法。

          Flex的精髓之一就是事件和綁定機制,了解之后,能幫助大家更靈活的設計程序,也對新手上路有一定的幫助。

          講解可能不太系統,也不全面,有很多沒有深入。如果高手看到后有疑問,歡迎指正。當然各位也可以提出自己的看法,或者經驗分享,謝謝。

          二.事件機制介紹

          1.????? 什么是事件機制

          事件可以看作是一種觸發機制,當滿足了一定的條件后,會觸發這個事件。比如MouseEvent就是指的當鼠標進行操作之后觸發的一系列的事件。很多控件中都有click事件,這個事件就是一個MouseEvent的實例,當點擊鼠標后,系統會自動拋出一個名稱為click的MouseEvent事件(這種方法我們將在后面介紹到)。如果此時在click上注冊一個方法,那么觸發該事件時就會執行這個方法。

          大致示意圖
          ?
          image001.png (14.50 K)

          2007-11-23 15:28:46


          該示意圖對應的Flex主應用的mxml代碼


          [復制到剪貼板]
          CODE:
          <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>


          在我們寫代碼時,編輯器的代碼補全提示列表中,有很多不同的圖標,如圖
          ?
          image003.png (4.90 K)

          2007-11-23 15:28:46

          那些帶有閃電的就是事件,三個小塊的就是樣式,空心圓圈的是屬性,實心圓點的是公有方法,還有一個是效果。

          我們能在這個列表中看到的事件,我把它稱之為事件注冊通道。(官方仍然稱它為事件,但是它又和普通的事件含義不同。關于事件注冊通道會再下面講述到)

          2.????? 事件注冊通道

          上面說到了,這些通道是只能在mxml的代碼提示中可以看到的,他的作用就是給mxml組件提供 事件觸發時所執行的方法的注冊通道,而且能在代碼提示中可見,這樣給組件提供了很大的抽象的好處,我們可以很清楚的告訴組件的使用者,組件里包含哪些事件給你調用。
          為什么把他區別對待?除了代碼提示外,他還有一些實現上的不同。

          Button的click事件是繼承自核心類InteractiveObject,遺憾我們看不到他的源碼,但是說明了“事件注冊通道”是可以繼承的。

          我們會在自定義事件中講述到如何聲明“事件注冊通道”。

          3.????? 事件觸發方法

          注冊通道中如果填入了函數,那么就代表觸發該事件時,會執行這個方法。

          click="clickHandler(event)"

          我們看到這個方法有一個event對象作為參數傳入,新人可能會問到,這個event對象哪里來的?我也沒聲明這個變量啊。他實際上是注冊通道傳給他的,默認變量名就是event。我們如果想在事件觸發時傳其他的參數,可以通過自定的事件對象來實現。

          這個對象就是這個組件分發的事件對象,即name為“click”的MouseEvent的一個實例。

          這個event對象包含了觸發該事件時的各種信息,比如觸發對象是哪個,觸發時鼠標點在哪里等等,不同的event類會包含不同的屬性,比如KeyboardEvent包含了鍵盤點擊了哪個鍵。

          我們也可以通過自定義一個事件類,來傳遞我們自己想要的各種信息。(這在后面將介紹到)

          4.????? 事件分發(重點了)

          最終繼承自EventDispatcher的對象都會含有dispatchEvent這個方法,他有一個參數,事件對象。

          之前說到的事件注冊通道,他只是一個通道,實際上事件是由這個方法來分發出去的,通道只是一個管道而已。

          他的作用就是分發一個事件對象,他的分發是沒有目的的,一種廣播形式的,Flex的事件監聽線程會接收到各種各樣的事件(我們稱之為捕獲事件,這在后面會介紹到),那么哪種才是你要的事件,標識就通過name來區分。

          1)事件對象
          在分發事件時,將會分發一個事件對象出去。不管是那個事件類,都是繼承自flash.events.Event對象的,他包含一些比較重要的屬性,name和bubbles。
          Name是這個對象在被捕捉到時的憑證。
          Bubbles是個布爾值,決定了該對象是否會向上傳遞。什么意思呢?畫個圖就明白了。
          比如說,當button組件分發click事件對象時,設置的bubbles為false,那么他的分發是這樣的

          示意代碼
          dispatchEvent(new MouseEvent( “click” , false ));
          ?
          image005.png (20.82 K)

          2007-11-23 15:28:46


          事件對象無法跨越組件本身,當然,除了之前講到的注冊通道(這樣就很形象了吧)

          因此,如果沒有注冊通道,在Flex主應用中,就無法捕獲到這個button組件分發出的事件。

          如果我們將Bubbles設為true,他看起來就是這樣
          dispatchEvent(new MouseEvent( “click” , true ));
          ?
          image007.png (25.61 K)

          2007-11-23 15:28:46


          可以看到,這個事件可以跨過組件本身,到達Flex主應用里。不止這樣,在幫助手冊中明確說到,如果在傳遞過程中間一直沒有被捕獲的話,這個事件會逐層上傳,直到最終的stage,那時如果還沒被捕獲,這個事件就會被銷毀掉。

          這樣一來,即使我們沒有click的事件通道,只要我們在Flex主應用中添加事件監聽器(addEventListener)那么我們就可以獲得到這個分發出的click事件了。

          那么,注冊通道不是沒用了嗎?不是,之前說到過,注冊通道是現式的,可見的,因此如果你的組件要給其他人使用,那么就非常一目了然,而不必知道你源碼中究竟分發了什么事件。但是,不要監聽和注冊同一個事件,這樣會重復執行的。(后面將講到)

          5.????? 事件監聽

          在分發中,我們講到,如果不是通過注冊通道來調用觸發事件,那么我們是需要一個監聽來捕捉的。如何捕捉到分發出的事件,就是通過事件的name值。

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


          Flex的事件中都提供了一些靜態常量,讓我們調用,避免我們打錯了。因此這句話可以這么寫

          testBtn.addEventListener(MouseEvent.CLICK,clickHandler);


          我們看到,監聽的回調方法中沒有傳遞參數,是的,這和通道的寫法有些不同,這里的回調方法(即clickHandler)只是個引用,并不是代表方法的執行,他的含義是,告訴eventLinstener,如果捕捉到click事件,那么就去找clickHandler,并執行它,event對象參數在執行時動態的傳遞。(如果熟悉ajax的朋友這里應該很容易懂了)

          他作用起來就是這樣
          ?
          image009.png (40.46 K)

          2007-11-23 15:28:46


          如果你又注冊了click的事件通道,那么這兩個都會生效,顯然這是多余的。

          ????? 6.? 關于異步和執行順序

          可以看到,事件的分發,和事件捕獲的回調(clickHandler)并不是同步的,因為在dispatchEvent之后,該線程不會停下來,等待listener捕捉,而是繼續做自己的事。

          當你分發了click事件后,仍然會繼續執行click之后的操作,Lintenser是一個獨立的線程,他至始至終都在工作,當他捕捉到你add的事件后,則會去調用回調的函數。分發任何事件都是這樣。

          異步示意圖
          ?
          image011.png (6.01 K)

          2007-11-23 15:28:46


          上圖可以看出,回調方法執行的順序甚至還不如dispatchEvent之后的方法。如果接下來的方法依賴于事件回調,那么把接下來的方法寫到回調方法中去
          ?
          image013.png (6.54 K)

          2007-11-23 15:28:46


          三.綁定機制

          ????? 在我們了解了事件機制后,那么理解綁定就不難了。綁定其實也是事件機制的運用

          ????? 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;
          ????? //這個就是聲明事件注冊通道的方法了。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=">
          <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 2009-12-31 15:53 飛熊 閱讀(259) 評論(0)  編輯  收藏 所屬分類: Flex

          <2009年12月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          統計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          收藏夾

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 宽甸| 花莲县| 屏东市| 巩留县| 汾西县| 于田县| 金溪县| 玛纳斯县| 方山县| 沅江市| 五台县| 明水县| 汝城县| 盐津县| 留坝县| 车致| 北安市| 台安县| 建阳市| 靖宇县| 宿州市| 津南区| 平塘县| 广宁县| 平湖市| 玛纳斯县| 遵义县| 呼玛县| 盐池县| 许昌市| 彩票| 公安县| 鄂温| 宣恩县| 嘉义市| 南安市| 新野县| 红河县| 子长县| 芮城县| 武城县|