[Flex3]イベントフェーズについて その2

イベントフェーズについて その1では、3段階あるイベントフェーズの中で 「ターゲット段階」・「バブリング段階」 に着目し、その仕組みをサンプルアプリの結果を見ながら確認しました。

今回は、残りのイベントフェーズ 「キャプチャ段階」について、私が勘違いしてしまったポイントも交えながら確認していきたいと思います。

まずは、キャプチャ段階のイベントをリスナーでキャッチさせる為に addEventListener メソッドの3番目の引数である useCapture を true に設定します。
(useCapture はデフォルトでは false に設定されています。つまり、ここのスイッチを変えない限り通常のイベントリスナーではキャプチャ段階は無視されています)

Flex3 API はこんな感じに書かれています。

addEventListener.PNG

 

今回のサンプルアプリではキャプチャ段階もリスナー対象としたいので、前回サンプルコードのinnerBox・middleBox・outerBox に登録したイベントリスナーの useCapture を true にします。

            private function onCreationComplete():void{   
                innerBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher, true);
                middleBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher, true);
                outerBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher, true);
            }

これでキャプチャ段階の設定がわかったので、前回サンプリコードの上記部分だけを変更して 実行すると 「キャプチャ段階」・「ターゲット段階」・「バブリング段階」 のすべてでイベントをキャッチできる!  ・・・・・と思っていましたが、そうはいきませんでした。

実際の実行結果はこれです。

capturePhase_only.PNG

・・・いくらクリックしてもキャプチャ段階のイベントしかキャッチできていません。

 

Flex3 API の続きを読んでみるとちゃんと書いてありました。以下はAPI 説明からの引用です。

「useCapturetrue に設定すると、リスナーはキャプチャ段階のみでイベントを処理し、ターゲット段階またはバブリング段階では処理しません。 useCapturefalse に設定すると、リスナーはターゲット段階またはバブリング段階のみでイベントを処理します。 3 つの段階すべてでイベントを受け取るには、addEventListener() を 2 回呼び出します。useCapturetrue に設定して 1 回呼び出し、useCapturefalse に設定してもう 1 回呼び出します。」

ポイントとしては、イベントフェーズは3段階存在しているけれども、実際にはキャプチャー段階 と ターゲット段階+バブリング段階 の2種類でリスナー処理を登録してやらないといけないこと。 つまり3段階すべてでリスナー処理をさせるには、useCapture スイッチを切り替えた2つの addEventListener を発行してやらなければいけないみたいです。 なるほど。

 

以下が、私の勘違いを正した今回のサンプルアプリ用のコードです。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" horizontalAlign="center" backgroundColor="#FFFFFF"
     creationComplete="onCreationComplete()" >
     
    <mx:Script>
        <![CDATA[
            import mx.controls.Label;
       
            private var counter:int = 1;
           
            private function onCreationComplete():void{   
                innerBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher);
                innerBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher,true);
                middleBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher);
                middleBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher, true);
                outerBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher);
                outerBox.addEventListener(MouseEvent.CLICK, onCatchDispatcher, true);
            }
           
            private function onCatchDispatcher(e:MouseEvent):void{
                var lbl:Label = new Label();
                var phase:String = getPhase(e.eventPhase);
                lbl.text = counter + " : " + e.currentTarget.id + " [" + phase + "]";
                setLabelColor(lbl, e.currentTarget.id);
                eventList.addChild(lbl);
                counter++;
            }
           
            private function getPhase(eventPhase:int):String{   
                var phase:String;
                //EventPhase 1=キャプチャ段階, 2=ターゲット段階, 3=バブリング段階
                switch(eventPhase){
                    case 1:
                        phase = "キャプチャ段階";
                        break;
                    case 2:
                        phase = "ターゲット段階";
                        break;
                    case 3:
                        phase = "バブリング段階";
                        break;
                }
               
                return phase;
            }
           
            private function setLabelColor(lbl:Label, targetBox:String):void{       
                if(targetBox == "innerBox"){
                    lbl.setStyle("color", "#CC0000");
                }else if(targetBox == "middleBox"){
                    lbl.setStyle("color", "#00cc00");
                }else if(targetBox == "outerBox"){
                    lbl.setStyle("color", "#0000CC");
                }
            }

        ]]>
    </mx:Script>
    <mx:HBox>
        <mx:VBox id="outerBox" minHeight="150" minWidth="150" horizontalAlign="center" verticalAlign="middle" backgroundColor="#0000CC">
            <mx:VBox id="middleBox" minHeight="100" minWidth="100" horizontalAlign="center" verticalAlign="middle" backgroundColor="#00CC00">
                <mx:VBox id="innerBox" minHeight="50" minWidth="50" horizontalAlign="center" verticalAlign="middle" backgroundColor="#CC0000" />
            </mx:VBox>
        </mx:VBox>
        <mx:VBox id="eventList" fontWeight="bold" />
    </mx:HBox>

</mx:Application>

 

実際にサンプルアプリを動かしてみるとちゃんと3段階のイベントフェーズを確認することができました。

① 一番内側の innerBox をクリックした場合

innerBox.PNG

② 次に内側の middleBox をクリックした場合

middleBox.PNG

③ 一番外側の outerBox をクリックした場合

outerBox.PNG

 

イベント伝播の機能はとても便利ですが、ここには伝播して欲しくないないんだよなーという場合もあると思います。

次回は伝播の止め方について確認していきたいと思います。

このブログについて

このブログは吉祥寺にあるブレインチャイルド株式会社の社員で投稿しています。
業務ではまってしまったことや発見したこと。
自分達で新たに学習してみようと思って勉強し始めたことなどを綴っています。
こんな社員が働いているブレインチャイルドに興味がわいててきたなら、是非お問い合わせください。
会社案内
求人案内
先輩のコメント