25 February 2007
ページ ツール |
初級
ActionScriptのイベント処理方法は、Flash Playerの新しいリリースごとに大きく変化してきました。ActionScript 3.0の導入においても、この傾向は続いています。ActionScript 3.0を使用すると、イベントの操作時に、さらに詳細に制御できるようになりました。
この記事では、ActionScript 3.0のイベント処理に関する新機能について取り上げます。具体的には、特にマウスイベントの使用に関し、新しいEventDispatcherクラスがどのように機能するかを説明します。さらに、イベントの伝達やEventオブジェクト、独自のカスタムイベントの作成方法についても説明します。
ActionScript 3.0のイベント処理は、EventDispatcherクラスに大きく依存します。このクラスはActionScriptで以前から使用されていますが、今回初めてActionScript言語の主要なクラスに含まれました。V2コンポーネントの使用時に、JavaScriptまたはActionScript 2.0のEventDispatcherを使用した経験がある方もいるでしょう。V2コンポーネントでは、EventDispatcherクラスの外部バージョンを使用してコンポーネントイベントを処理していました。このバージョンは、ActionScript 3.0の内部で使用されるEventDispatcherのバージョンとは若干異なります。
EventDispatcherについてご存じないユーザのために、基本的な概念をここで説明します。まず、様々なイベントに対応するための関数、すなわちイベントハンドラを作成します。次に、addEventListener()メソッドを使用してこれらの機能をイベントに関連付けます。このメソッドは、イベントを受け取るオブジェクトから呼び出されます。これは、ActionScript 2.0における通常のコアプロセスと似ていますが(EventDispatcherは使用しません)、ActionScript 2.0ではイベントを受け取るオブジェクト内にイベントハンドラを定義し、受け取るイベントの名前を関数に指定する点が異なります。例えば、ActionScript 2.0でsubmitButtonという名前のボタンの「onPress」イベントに対応するには、次のように指定します。
submitButton.onPress = function() { ... }
EventDispatcherを使用する場合も、同じ要素(イベントを受け取るオブジェクト、イベント名、およびイベントに対応する関数)が関与しますが、プロセスだけ若干異なります。EventDispatcherを使用したコードは次のようになります。
function pressHandler(){ ... }
submitButton.addEventListener("onPress", pressHandler);
このプロセスでは余分な手順が追加されているように見えますが、それによって柔軟性が向上しています。ターゲットオブジェクト自体に直接イベントハンドラを定義する代わりに、関数を使用してイベントハンドラを追加しているので、1つのイベントを「リッスン」するハンドラをいくつでも追加できます。
ActionScript 2.0でのイベントの削除は、以下のように、ハンドラを削除することを意味していました。
delete submitButton.onPress;
EventDispatcherでは、removeEventListener()を使用します。このメソッドは、addEventListenerで使用されている定義(3番目のパラメータまで)に一致するイベントリスナーを削除します。
submitButton.removeEventListener("onPress", pressHandler);
上述のコードスニペットでは、EventDispatcherが明示的に参照されていないことに気づかれたことと思います。実のところ、コード内でEventDispatcherを直接使用することはまれです。ActionScript 3.0のEventDispatcherは、実際には基本クラスであり、他のクラスはこの基本クラスを拡張してaddEventListenerや他のEventDispatcherメソッドにアクセスします。ActionScript 2.0では、EventDispatcherはmixinクラスでした。
つまり、これらのメソッドを他のオブジェクトに渡すには、EventDispatcher.initialize()を使用してEventDispatcherから目的のオブジェクトにメソッドをコピーしていました。ActionScript 3.0では、EventDispatcherを拡張することでクラスがメソッドを継承します。便利なことに、MovieClipや他のDisplayObjectsなど、ActionScript 3.0でEventDispatcherを使用する必要があるほとんどのクラスで、すでにEventDispatcherが拡張されているので、アクセス可能であり、簡単に使用できるようになっています(ただし、上級ユーザはコードを作成してEventDispatcher機能を含めることもできます)。
ActionScript 3.0におけるEventDispatcherのメソッドを以下にまとめます。これらのメソッドの多くはActionScript 2.0バージョンのメソッドと類似しています。
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):voidremoveEventListener(type:String, listener:Function, useCapture:Boolean = false):voiddispatchEvent(event:Event):BooleanhasEventListener(type:String):BooleanwillTrigger(type:String):BooleanActionScript 2.0を使用した経験があれば、hasEventListenerおよびwillTriggerという2つの新しいメソッドに気づかれたでしょう。また、ActionScript 3.0のaddEventListenerでは、リスナーとして関数のみを使用でき、オブジェクトは使用できなくなりました(以前のバージョンではオブジェクトをリスナーとして使用できました)。ActionScript 3.0ではメソッドがそのインスタンスにバインドされるので、基本的にリスナーにオブジェクトを使用する必要がありません。つまり、関数内のthisキーワードは、取得先のインスタンスを常に正しく参照するようになりました。また、ActionScript 2.0のDelegateクラスを使用する必要もなくなりました。
addEventListenerを使用してリスナーリストに追加されたイベントハンドラを削除します。正しいハンドラを削除するには、addEventListenerで使用した最初の3つの引数と同じものをremoveEventListenerでも使用する必要があります。hasEventListenerとよく似ていますが、このメソッドでは現在のオブジェクトに加えて、イベントの伝達によって影響を受ける可能性のあるオブジェクトをすべてチェックします。これらのメソッドやActionScript 3.0言語の他の関数やメソッドについては、『ActionScript 3.0 リファレンスガイド』にも記載されています。
簡単な例として、画面上の「box」という四角形のインスタンスをクリックする場合を検討してみましょう(図1を参照)。この例の目的は、マウスでboxをクリックしたときに「click」というテキストが出力パネルでトレースされるようにイベントを処理することです。
このテストムービーを作成するには、次の手順を実行します。
function clickHandler(event:MouseEvent):void {
trace("click");
}
box.addEventListener(MouseEvent.CLICK, clickHandler);
<?xml version="1.0" encoding="utf-8"?>
"mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="initApp()""
<mx:Script>
"![CDATA[
public function clickHandler(event:MouseEvent):void {
trace("click");
}
public function initApp():void {
box.addEventListener(MouseEvent.CLICK, clickHandler);
}
]]"
</mx:Script>
<mx:Canvas id="box" width="200" height="200" backgroundColor="#800000">
</mx:Canvas>
</mx:Application>
スクリプトを見てみましょう。最初の手順では、イベントハンドラ(リスナー関数)を定義します。すべてのイベントと同様に、これによって、イベントディスパッチャから呼び出されたときに関数に自動的に渡される1つのイベントインスタンスが、パラメータリスト内に配置されます。その後、関数はboxインスタンスのリスナー、つまり基本的なaddEventListener呼び出しを使用してMouseEvent.CLICKイベントをリッスンするイベントディスパッチャとして設定されます(これはFlexではinitAppメソッドで発生します)。boxはMovieClipのインスタンス(FlexではCanvas)なので、EventDispatcherから継承し、addEventListenerをはじめとするすべてのEventDispatcherメソッドにアクセスできます。
MouseEvent.CLICKは、MouseEventクラスで定義される定数で、イベントの文字列を指定し、MouseEvent.CLICKは、「click」になります。他のイベントタイプも、他のイベント関連クラスと同様に、MouseEventクラスの類似の定数に格納されます。これらの多くが、ActionScript 2.0の対応する項目と比べて変わっていることに注意してください。例えば、ActionScript 2.0ではonPressイベントを使用しますが、ActionScript 3.0ではMouseEvent.MOUSE_DOWN(または「mouseDown」)を使用します。これらの相違点に関する詳細は、イベントパッケージの『ActionScript 3.0 リファレンスガイド』と、パッケージ内のそれぞれのEventクラスに記載されています。
ここに示す例では、MouseEvent.CLICKの代わりに単に「click」を使用することもできますが、定数を使用することで、コード内のスペルミスを検出しやすくなります。例えば、文字列「click」のスペルを誤って入力しても、Flashには文字列の内容が正しいかどうかを判定する手段がないので、コンパイルエラーは発生しません。一方、MouseEvent.CLICKのスペルを誤って入力した場合は、Flashによってエラーが認識され、コンパイルエラーが発生します。ほとんどのEventクラスには、そのイベントタイプ文字列に関連するこれらの定数があります。そのため、実際の文字列をそのまま使用するのではなく、これらの定数を使用してください。
ムービーをテストすると、クリックできるboxが表示され、クリックすると、「click」という単語がトレースされます。
注意:FlexではムービーはDebugを使用してテストし、トレース出力をFlex Builderでキャプチャできるようにしてください。
前の例でお気づきにならなかったかもしれませんが、boxをクリックして発生したイベントは、クリックしたオブジェクトだけでなく、多くの様々なオブジェクトにも影響を及ぼします。ActionScript 3.0のイベント処理における重要な新機能に、イベントの伝達のサポートがあります。イベントの伝達とは、1つのイベントが複数のオブジェクトに適用される転移現象です。これらの各オブジェクトは、イベントが発生したオブジェクトだけでなく、イベントも受け取ります。
ActionScript 2.0では、このようなイベントの伝達は行われませんでした。実際には、独自のイベントハンドラを持つ別のオブジェクト内で、特定のイベントハンドラが関連付けられているオブジェクトを扱うことさえできませんでした。例えば、ActionScript 2.0では、ボタンを含むウィンドウオブジェクトにonPressイベントハンドラを割り当てた場合、ボタンに割り当てられているonPress(または類似の)イベントハンドラは機能せず、イベントも受け取りません。ActionScript 3.0では、このような問題はなくなりました。イベントは、インスタンスやその親の間を伝達されるようになりました。
イベントの伝達には、3つの「段階」があります(図2を参照)。各段階は、イベントに関連する表示オブジェクトを介してFlashでイベントが処理される際の、イベントの経路または場所を表します。イベントの3つの段階は、キャプチャ、ターゲットおよびバブリングです。
ただし、伝達されるイベントがすべて各段階を通過するわけではなく、すべてのイベントが伝達されるとも限りません。例えば、Stageオブジェクトがイベントを受け取った場合は、キャプチャ段階やバブリング段階が発生するために必要な、stageより下位のオブジェクトが存在しないので、ターゲット段階のみが発生します。
注意:Flexの階層は、rootとboxのCanvasインスタンス(図では省略)との間にApplicationインスタンスが含まれているので、若干異なります。
イベントが各段階と段階にある各オブジェクトを通過していくとき、そのイベントのために追加されたリスナー関数がすべて呼び出されます。つまり、boxをクリックすると、イベントはboxだけでなく、stageにも渡されます。stageは、イベントを2回受け取ります。1回はキャプチャ段階で受け取り、もう1回はバブリング段階で受け取ります(図3を参照)。
この例にリスナーを追加していくと、流れがより明確にわかるようになります。
マウスで1回クリックすると、表示リスト階層内の多くのオブジェクトに伝達されていく様子を確認するため、影響を受ける各オブジェクトについてイベントを受け取るリスナーを追加します。この例ではイベントのすべての段階にリスナーを追加するので、addEventListenerの3番目のパラメータである、useCaptureパラメータを利用する必要があります。
addEventListenerのuseCaptureパラメータを使用すると、リスナーがキャプチャ段階でリッスンするかどうかを指定できます。キャプチャ段階でリッスンしない場合は、ターゲット段階またはバブリング段階でイベントをリッスンします。ターゲット段階とバブリング段階でリッスンするため、リスナーにはデフォルト値falseが設定されています。true値を渡すと、キャプチャ段階でイベントをリッスンできます。すべての段階でイベントをリッスンするには、addEventListenerを2回使用します。1つはuseCaptureをfalseに設定するか、または省略し、もう1つはuseCaptureをtrueに設定します。
この例(図4を参照)では、stage、root、boxに対してリスナーを追加します。stageとrootに対しては、useCaptureパラメータを交互に使用するイベントリスナーを追加します。
function boxClick(event:MouseEvent):void {
trace("box click");
}
function rootClick(event:MouseEvent):void {
trace("root click");
}
function stageClick(event:MouseEvent):void {
trace("stage click");
}
box.addEventListener(MouseEvent.CLICK, boxClick);
root.addEventListener(MouseEvent.CLICK, rootClick);
root.addEventListener(MouseEvent.CLICK, rootClick, true);
stage.addEventListener(MouseEvent.CLICK, stageClick);
stage.addEventListener(MouseEvent.CLICK, stageClick, true);
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="initApp()">
<mx:Script>
<![CDATA[
public function boxClick(event:MouseEvent):void {
trace("box click");
}
public function rootClick(event:MouseEvent):void {
trace("root click");
}
public function stageClick(event:MouseEvent):void {
trace("stage click");
}
public function initApp():void {
box.addEventListener(MouseEvent.CLICK, boxClick);
root.addEventListener(MouseEvent.CLICK, rootClick);
root.addEventListener(MouseEvent.CLICK, rootClick, true);
stage.addEventListener(MouseEvent.CLICK, stageClick);
stage.addEventListener(MouseEvent.CLICK, stageClick, true);
}
]]>
</mx:Script>
<mx:Canvas id="box" width="200" height="200" backgroundColor="#800000">
</mx:Canvas>
</mx:Application>
注意:FlexではapplicationCompleteイベントを必ず使用して、Applicationスクリプト内のstageおよびrootにアクセスできるようにしてください。stageとrootには、creationCompleteイベント内ではアクセスできません。
このムービーをテストし、いろいろな場所をクリックして結果を確認します。boxをクリックすると、以下の出力が表示されます。
stage click
root click
box click
root click
stage click
この出力は、stageオブジェクトとrootオブジェクトがイベントのキャプチャ段階とバブリング段階でそれぞれ1回ずつ、イベントを2回受け取ったことを示しています。一方、イベントのターゲットであるboxは、ターゲット段階で1回だけイベントを受け取っています。stage上のbox以外の場所をクリックしてみると、Flashを使用している場合は以下の出力が表示されます。
stage click
stageはFlashムービーの階層の最上位に位置するので、stageベースのイベントの段階は、ターゲット段階のみになります。
Flexで、stageをクリックすると、以下のような出力が表示されます。
stage click
root click
root click
stage click
これは、stageの領域全体を包含するグラデーション背景を含む中間のApplicationインスタンス(Application.application)の結果です。stageをクリックすることは、実際にはstage自体ではなく、リスナーを持たないこのインスタンスをクリックすることになります。中間のApplicationインスタンスが存在しない場合は、stageのリスナーのみが呼び出されます。
イベントの伝達はマウスイベントで最も頻繁に発生しますが、キーボードイベントなどの他のイベントでも発生します。イベントの伝達は、DisplayObjectContainerインスタンス内の追加イベントや削除イベントでも使用されます。この場合は、子オブジェクトがその表示リストに追加されるか、表示リストから削除されます。
Flashではマウスクリックなどのすべてのイベントは、イベントのターゲット化プロセスから始まります。これは、どのオブジェクトがイベントのターゲットであるか(イベントがどのオブジェクトで発生するか)をFlashが特定するプロセスです。前の例では、boxまたはstageがクリックされたかどうかをFlashがどのように特定するかを見てきました。あらゆるマウスイベントにおいて、イベントは1つのオブジェクトを参照します。このオブジェクトは、イベントを受け取ることのできる最上位のオブジェクトです(図5を参照)。
この動作はActionScript 2.0を使用した場合とほとんど同じです。例えば、ActionScript 2.0では、重なっている2つのボタンを一度クリックすると(どちらのボタンにもイベントハンドラが割り当てられている場合)、上部のボタンのみがイベントを受け取ります。この動作はActionScript 3.0でも同じです。クリックしたときどちらのボタンもマウスのカーソルの下に位置していますが、上部のボタンがイベントのターゲットのオブジェクトなので、上部のボタンのみがイベントを受け取ります。
ActionScript 3.0での相違点は、すべての表示オブジェクトが、デフォルトにより、マウスイベントを受け取ることができることです。つまり、イベントハンドラが特定の表示オブジェクトに割り当てられていない場合でも、クリックするとイベントのターゲットとなり、その下にあるオブジェクトがイベントを受け取ることはありません。この点がActionScript 2.0では異なりました。ActionScript 2.0では、onPressなどのイベントハンドラが割り当てられている場合にのみ、ムービークリップインスタンスはイベントを受け取ることができます。このようなハンドラがないインスタンスにはイベントのターゲット化は行われず、代わりにその下にあるインスタンスがターゲット化の候補になります。
この動作をActionScript 3.0で実現するには、InteractiveObject mouseEnabledプロパティを使用します。このプロパティをfalseに設定すると、対話型オブジェクトインスタンスがマウスイベントを受け取らなくなり、その下にある他のインスタンスがマウスイベントのターゲットになります。
myInteractiveObject.mouseEnabled = false;
Eventオブジェクトは、イベントの発生時に呼び出されたときに、リスナー関数が引数として受け取るオブジェクトです。ActionScript 3.0のEventオブジェクトは、ActionScript 2.0バージョンのEventDispatcherクラスで使用されるオブジェクトと似ています。主な違いは、ActionScript 3.0のEventオブジェクトには独自のクラス(Eventクラス)があるので多少構造化されていることと、処理するイベントを記述するためのプロパティが追加されたことです。
リスナー関数が受け取るEventオブジェクトは、常にイベントタイプですが、Eventインスタンスとして指定されていない、Eventのサブクラスも含まれます。一般的なサブクラスには、マウスに関連付けられているイベントのMouseEventや、キーボードに関連付けられているイベントのKeyboardEventがあります。各クラスには、関連するイベントをリッスンするためのイベントタイプの定数も含まれています。この定数の例としてMouseEvent.CLICKなどがあります。
stageは、コード内で参照可能なオブジェクトという意味では、ActionScript 3.0に新たに導入された概念です。stageは、Flashムービー内のすべての表示オブジェクトの最上位コンテナを表します。これは、ActionScript 2.0の_rootとほぼ同じものですが、ActionScript 3.0では、root(アンダースコアを含まず、DisplayObjectのrootプロパティを経由してアクセス)はstageオブジェクト内に存在します。
さらに、マウスイベントのstageのターゲット化は、他のオブジェクトの場合と同様に、stageのコンテンツに依存しません。boxの例で見ると、stage>root>boxという基本的な階層が存在します(Flexでは階層はstage>root>application>box)。boxをクリックし、このboxをクリックイベントのターゲットにするには、boxを構成している形状をクリックする必要があります。同様に、rootオブジェクトをクリックするには、そのコンテンツまたはboxインスタンスをクリックする必要があります。rootはboxのみで構成されているので、他の場所をクリックしてもrootはクリックされません。ただしstageの場合は、stageに他のコンテンツが存在しなくても、ムービーの一貫した背景としてstageがあらゆる場所に存在するので、ムービーの任意の場所をクリックすることで、stageをクリックできます。場合によっては(mouse upイベントやmouse moveイベントなど)、stageでムービーの外部のマウス動作を検出できます。この動作は、後の節で示すように、ActionScript 3.0で一部のタスクを行う際に重要になります。
一般的なEventプロパティの基本的な内容は以下のとおりです。
type:StringeventPhase:uintbubbles:Booleancancelable:Booleantarget:ObjectcurrentTarget:Objectこの他のプロパティはサブクラスに適用されます。例えば、MouseEventインスタンスには、特に現在のイベントに関連する表示オブジェクト(現在のroll overイベントに到達するために通過した表示オブジェクトなど)を記述するrelatedObjectプロパティなどもあります。
一部のプロパティは見覚えがあるでしょう。前述のプロパティについて、以下に説明します。
addEventListenerで使用する最初のパラメータと同じです。例えば、MouseEvent.CLICKなどです。EventPhase.CAPTURING_PHASE、EventPhase.AT_TARGETおよびEventPhase.BUBBLING_PHASEに関連する数値として指定されます。TextEvent.TEXT_INPUT)をリッスンしているリスナーは、これらのイベントを認識し、デフォルトの動作をキャンセルできます。このような場合、cancelableプロパティの値はtrueになります。これらのプロパティは、様々なイベントに対して実行する必要のあるアクションを特定する際に役立ちます。
ActionScript 3.0イベントの短所の1つに、ActionScript 2.0のonReleaseOutsideイベントに相当するイベントが存在しないことが挙げられます。ActionScript 3.0にはmouse downイベントとmouse upイベントはありますが、クリックしたオブジェクトの外でのイベントの解放を処理できるイベントはありません。オブジェクトがクリックされた後、オブジェクトの外でマウスが解放された場合を特定するには、stageに固有の動作を利用した回避策を使用する必要があります。
これを行うには、2つのアプローチがあります。最も簡単な方法は以下のとおりです。
targetプロパティをチェックして、ターゲットがクリックされた元のオブジェクトであるかどうかを確認します。元のオブジェクトである場合は、元のターゲットでマウスが解放されています。元のオブジェクトでない場合は、オブジェクトの外でマウスが解放されています。stageではすべてのマウスイベントをキャプチャするので、すべてのmouse upイベントがstageに受け取られると見なすことができます。mouse upリスナーをターゲットオブジェクトのmouse downリスナー内のstageに追加することで、次にマウスが解放されたとき、クリックされた元のオブジェクトの上で行われたmouse upか、オブジェクトの外で行われたmouse upか(mouse up outsideイベント)がわかります。
function boxDown(event:MouseEvent):void {
trace("box down");
stage.addEventListener(MouseEvent.MOUSE_UP, boxUpOutside);
}
function boxUpOutside(event:MouseEvent):void {
if (event.target != box) {
trace("box up outside");
}
stage.removeEventListener(MouseEvent.MOUSE_UP, boxUpOutside);
}
box.addEventListener(MouseEvent.MOUSE_DOWN, boxDown);
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="initApp()">
<mx:Script>
<![CDATA[
public function boxDown(event:MouseEvent):void {
trace("box down");
stage.addEventListener(MouseEvent.MOUSE_UP, boxUpOutside);
}
public function boxUpOutside(event:MouseEvent):void {
if (event.target != box) {
trace("box up outside");
}
stage.removeEventListener(MouseEvent.MOUSE_UP, boxUpOutside);
}
public function initApp():void {
box.addEventListener(MouseEvent.MOUSE_DOWN, boxDown);
}
]]>
</mx:Script>
<mx:Canvas id="box" width="200" height="200" backgroundColor="#800000">
</mx:Canvas>
</mx:Application>
ムービーをテストし、boxをクリックします。マウスをboxの上に重ねたまま、クリックして解放してみます。次に、マウスをクリックしてドラッグし、カーソルをboxの外に置いてマウスボタンを解放してみます。boxをクリックすると「box down」と表示され、boxをクリックしてboxの外で解放すると「box down」と「box up outside」の両方が表示されます。Flash Playerウィンドウの外でマウスを解放した場合も「box down」と「box up outside」が表示されます(stageに関連付けられているmouse upイベントに固有の動作です)。
Eventオブジェクトに関連する便利なメソッドの一部を次に紹介します。
stopPropagation()stopImmediatePropagation()preventDefault()isDefaultPrevented()プロパティと同様に、Eventサブクラスには追加のメソッドがある場合があります。例えば、KeyboardEventおよびMouseEventインスタンスには、updateAfterEvent()メソッドもあります。このメソッドを使用すると、イベントの完了後に画面を再描画できます。
これらのEventメソッドが実行できる内容について次に説明します。
stopPropagationとよく似た動作ですが、stopPropagationでは現在のオブジェクト内での他のイベントの呼び出しは停止されない点が異なります(同じオブジェクト内で同じイベントをリッスンしているリスナーが複数存在する場合)。
preventDefaultが現在のイベントに対して呼び出されているかどうかに応じて、trueまたはfalseを返します。前述のように、マウスイベントは、ActionScript 3.0内のすべての対話型オブジェクトに対して継承的に有効です。マウス動作を無効にするには、mouseEnabledプロパティをfalseに設定します。また、そのオブジェクトのすべての子に対してマウスイベントを無効にできる、mouseChildrenという表示オブジェクトコンテナ用の類似のプロパティもあります。mouseChildrenをfalseに設定すると、表示オブジェクトコンテナ内のすべてのインスタンスに対して、マウスが有効になるのを効果的に防ぐことができます。
ただし、コンテナ内のオブジェクトのコレクションに対して特定のマウスイベントのみを無効にする場合は、別のアプローチを使用する必要があります。このような状況では、無効にするイベントをリッスンしているターゲットの親インスタンス内のイベントリスナーを使用して、このリスナーがそのイベントを伝達しないようにします。これにより、コンテナ内のオブジェクトに対応しているリスナーが呼び出されなくなります。
次の例では、コンテナウィンドウに2つのボタンを作成します。これらのボタンのクリックアクションは、コンテナの外部にある別のボタンから有効または無効に設定します。3番目の外部のボタンは、クリックイベントがキャプチャ段階で検出されたときコンテナがクリックイベントの伝達を停止するかどうかを判断するプロパティを設定します。
var clickEnabled:Boolean = true;
function clickHandler(event:MouseEvent):void {
trace("click: " + event.currentTarget.name);
}
function toggleEnabled(event:MouseEvent):void {
clickEnabled = !clickEnabled;
}
function disableClickHandler(event:MouseEvent):void {
if (clickEnabled == false) {
event.stopPropagation();
}
}
window.button1.addEventListener(MouseEvent.CLICK, clickHandler);
window.button2.addEventListener(MouseEvent.CLICK, clickHandler);
window.addEventListener(MouseEvent.CLICK, disableClickHandler, true);
enabler.addEventListener(MouseEvent.CLICK, toggleEnabled);
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="initApp()">
<mx:Script>
<![CDATA[
public var clickEnabled:Boolean = true;
public function clickHandler(event:MouseEvent):void {
trace("click: " + event.currentTarget.name);
}
public function toggleEnabled(event:MouseEvent):void {
clickEnabled = !clickEnabled;
}
public function disableClickHandler(event:MouseEvent):void {
if (clickEnabled == false) {
event.stopPropagation();
}
}
public function initApp():void {
button1.addEventListener(MouseEvent.CLICK, clickHandler);
button2.addEventListener(MouseEvent.CLICK, clickHandler);
container.addEventListener(MouseEvent.CLICK, disableClickHandler, true);
enabler.addEventListener(MouseEvent.CLICK, toggleEnabled);
}
]]>
</mx:Script>
<mx:Panel width="250" height="250" layout="absolute" id="window">
<mx:Button x="30" y="25" label="Button" id="button1"/>
<mx:Button x="30" y="55" label="Button" id="button2"/>
</mx:Panel>
<mx:Button label="Enabler" id="enabler"/>
</mx:Application>
ムービーをテストし、「Enabler」ボタンがclickEnabled変数を使用して、コンテナ内のボタンによるクリックイベントの受け取りを無効または有効にする様子を確認します。この方法では、clickEnabled変数はクリックイベントのみを無効にするので、roll overなどのマウスイベントはウィンドウ内のボタンに対して一貫して機能します。roll overマウスイベントは、mouseChildrenプロパティがコンテナに対してfalseに設定されている場合には機能しません。
ActionScript 3.0では、EventDispatcherを使用してイベントをキャプチャできます。EventDispatcherを使用して独自のイベントを作成することもできます。この作業には、新規または既存のイベントの送り出し、新しいタイプのイベントの作成、イベントをリッスンするイベントハンドラに渡すインスタンスを持つ新しいEventクラスの定義(Eventクラスに基づく)が含まれます。
イベントを手動で送り出すには、EventDispatcherのdispatchEventメソッドを使用します。dispatchEventを呼び出すときは、送り出すイベントを記述したEventオブジェクトを渡します。このイベントは、すべての有効なターゲット(伝達される場合は複数)に伝わり、これらのターゲットにリスナーとして割り当てられているイベントハンドラが呼び出されます(その特定のタイプのイベントをリッスンしている場合)。ハンドラが呼び出されると、各ハンドラはdispatchEventに渡されるEventオブジェクトを受け取ります。
target.dispatchEvent(new Event("type"));
新しいイベントインスタンスは、typeパラメータと、オプションのbubblesパラメータおよびcancelableパラメータを指定して作成されます。デフォルトでは、少なくともEventクラスのbubblesパラメータとcancelableパラメータは、trueとして明示的に渡されない限り、falseになっています。MouseEventなどのEventクラスのサブクラスは、さらに多くのパラメータを受け取ります。MouseEventクラスの場合、bubblesのデフォルト設定はtrueです。MouseEventおよび他のEventクラスの使用について詳しくは、『ActionScript 3.0 リファレンスガイド』を参照してください。
独自のEventクラスを作成するには、コアのEventクラスを拡張します。これらのカスタムサブクラスは、独自のカスタムイベントの送り出しに使用でき、ユーザが選択した独自のプロパティがあります。ただし、Eventクラスを拡張する際は、デフォルトのメソッドを上書きし、独自のclone()メソッドを確実に実装できます。すべての状況で必要なわけではありませんが、cloneメソッドはイベントインスタンスをコピーするためにFlash内部で使用されることがあります。cloneメソッドによってクローン作成の対象となるイベントインスタンスの正確なコピーが作成されない場合は、エラーが発生します。
カスタムイベントは、Flash Player内で継承的に認識されないイベントを示す場合に役立ちます。独自のEventクラスを作成すると、カスタムイベントに関連する追加情報を指定して、これらのイベントのハンドラを用意できます。ここに示す例では、BounceEventカスタムクラスを使用します。このクラスはバウンスイベントとともに使用され、画面上のboxが画面の端でバウンスしたことを示します。
BounceEventクラスは、ActionScript 2.0のクラスと同様に、外部のActionScriptファイルで定義します。Eventクラスを拡張することで自動的に継承される通常のEventプロパティに加えて、BounceEventクラスにはsideプロパティがあり、バウンスしたオブジェクトが画面のどの端から発生したかを判断できます。
カスタムプロパティに加えて、イベントに使用する様々なタイプに対応するタイプ定数(MouseEvent.MOUSE_DOWNなど)をカスタムEventクラスに指定することをお勧めします。BounceEventクラスでは、BOUNCE定数に格納される、「bounce」という名前のイベントのタイプを使用します。クラス定義は次のとおりです。
package {
import flash.events.Event;
public class BounceEvent extends Event {
public static const BOUNCE:String = "bounce";
private var _side:String = "none";
public function get side():String {
return _side;
}
public function BounceEvent(type:String, side:String){
super(type, true);
_side = side;
}
public override function clone():Event {
return new BounceEvent(type, _side);
}
}
}
clone関数もBounceEvent定義に含まれていることに注目してください。返された値はBounceEventインスタンスであって、Eventインスタンスではありませんが、BounceEventはEventを拡張し、そのタイプがEventになるので許容されます(overrideは上書きする元のメソッドと同じ関数シグネチャを持つ必要があるので、clone関数の戻り型はEventである必要があります)。
これでこのクラスを使用して、boxがバウンスしたときに送り出されるイベントインスタンスを作成できます。バウンスイベントをリッスンしているイベントハンドラは、そのイベントに関連するBounceEventsを受け取ることができます。
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
var velocityX:Number = 5;
var velocityY:Number = 7;
var padding:Number = 10;
function bounceHandler(event:BounceEvent):void {
trace("Bounce on " + event.side + " side");
}
function moveBox(event:Event):void {
box.x += velocityX;
box.y += velocityY;
var limitLeft:Number = padding;
var limitRight:Number = stage.stageWidth - box.width - padding;
var limitTop:Number = padding;
var limitBottom:Number = stage.stageHeight - box.height - padding;
if (box.x <= limitLeft) {
velocityX = Math.abs(velocityX);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "left"));
}else if (box.x >= limitRight){
velocityX = -Math.abs(velocityX);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "right"));
}
if (box.y <= limitTop) {
velocityY = Math.abs(velocityY);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "top"));
}else if (box.y >= limitBottom){
velocityY = -Math.abs(velocityY);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "bottom"));
}
}
box.addEventListener(Event.ENTER_FRAME, moveBox);
addEventListener(BounceEvent.BOUNCE, bounceHandler);
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" width="300" height="300"
applicationComplete="initApp()">
<mx:Script>
<![CDATA[
public var velocityX:Number = 5;
public var velocityY:Number = 7;
public var padding:Number = 10;
public function bounceHandler(event:BounceEvent):void {
trace("Bounce on " + event.side + " side");
}
public function moveBox(event:Event):void {
box.x += velocityX;
box.y += velocityY;
var limitLeft:Number = padding;
var limitRight:Number = stage.stageWidth - box.width - padding;
var limitTop:Number = padding;
var limitBottom:Number = stage.stageHeight - box.height - padding;
if (box.x <= limitLeft) {
velocityX = Math.abs(velocityX);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "left"));
}else if (box.x >= limitRight){
velocityX = -Math.abs(velocityX);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "right"));
}
if (box.y <= limitTop) {
velocityY = Math.abs(velocityY);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "top"));
}else if (box.y >= limitBottom){
velocityY = -Math.abs(velocityY);
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "bottom"));
}
}
public function initApp():void {
box.addEventListener(Event.ENTER_FRAME, moveBox);
addEventListener(BounceEvent.BOUNCE, bounceHandler);
}
]]>
</mx:Script>
<mx:Canvas width="20" height="20" x="20" y="20" backgroundColor="#800000" id="box">
</mx:Canvas>
</mx:Application>
ムービーをテストしてみます。boxがstageの端でバウンスすると、次の出力が表示されます。
Bounce on bottom side
Bounce on right side
Bounce on top side
Bounce on left side
Bounce on bottom side
...
これは、各バウンスイベントでbounceHandlerイベントハンドラ関数が呼び出された結果です。dispatchEventメソッドを使用してboxインスタンスに新しい方向が指定されるたびに、moveBox関数(enter frameイベントのイベントハンドラ)内でバウンスイベントが送り出されます。例えば、次のコード行を見てみましょう。
box.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "left"));
この行は、新しいバウンスイベントをboxインスタンスからすべてのリスナーに送り出します。これらのリスナーは、渡されたEventオブジェクトのsideカスタムプロパティを使用して、バウンスした端が「左」であったことを判断できます。
イベントがboxから送り出されたものであっても、bounceHandler(boxインスタンスのリスナーではない)はイベントを受け取ることができます。これは、BounceEvent定義では、コンストラクタ内のsuper()の呼び出し(Eventコンストラクタを実行する)に、イベントのバブルを示す2番目の引数trueが指定されているためです。それによって、bounceHandlerがリッスンしていたもの(Flashではroot、Flexではapplication)も含め、boxのすべての親にイベントを渡す伝達が可能になります。
ActionScript 3.0を初めてお使いになる場合や、ActionScript 2.0イベントに慣れている場合は、新しいイベントシステムの動作に慣れるのに時間がかかるかもしれません。しかし次第に慣れて、使用できるコントロールの水準の高さに満足していただけると思います。ここでは、ActionScript 3.0でイベントを操作する際のヒントや注意事項について補足します。
eventPhaseプロパティを確認すると、役に立つフィードバックが得られ、不要なイベントの伝達を防ぐことができます。eventPhaseがEventPhase.AT_TARGETである場合は、イベントのターゲットを判断できます。MouseEvent.ROLL_OVERおよびMouseEvent.ROLL_OUTと、MouseEvent.MOUSE_OVERおよびMouseEvent.MOUSE_OUTという2種類のイベントタイプがあります。これらの相違点は、ロールイベントはバブルしないことです。つまり、オブジェクトの子から伝達されるmouse overイベントとmouse outイベントを混同することがなくなります。他のイベントの場合は、mouseChildrenプロパティを使用して、マウスイベントに関する伝達の競合を避けることができます。mouseEnabledプロパティをfalseに設定します。stageプロパティは、アクティブな表示リスト内、または、stageに添付されていて、画面に表示されている表示リスト内にあるときに、表示オブジェクトからのみアクセスできます。表示オブジェクトがこのような表示リストに含まれていない場合、そのstageプロパティはNullです。同じ動作がrootプロパティにも適用されます。Event.ADDEDおよびEvent.REMOVED)は、マウスイベントと同じようにバブルしますが、キャプチャとバブリングは親のみに伝達され、子には伝達されないことを覚えておいてください。インスタンスの子は親のイベントを受け取りません。つまり、コンテナの子にとって、そのコンテナ(またはその親のいずれか)がアクティブな表示リストに追加されており、DisplayObjectのstageおよびrootプロパティにこれらの子が付与されているかどうかを簡単に判断できる方法はありません。この問題のソリューションとして、Flash Playerバージョン9,0,28,0(2006年11月14日リリース)に追加されたEvent.ADDED_TO_STAGEイベントとEvent.REMOVED_FROM_STAGEイベントの使用があります。これらのイベントは、表示オブジェクトがアクティブな表示リストに対して追加されたり削除されたりすると、それを表示オブジェクトに伝えるので、stageおよびrootにアクセスできるかどうかがわかります。MouseEvent.MOUSE_MOVE)は、イベントを受け取っているオブジェクトの上にマウスが位置しているときにのみ呼び出されます。このイベントを使用して画面上のオブジェクトを移動したりドラッグしたりする場合、マウスを誤ってオブジェクトの外に動かすと、イベントが失われます。確実にmouse moveイベントを維持するには、リスナーをstageに追加してください。addEventListenerの4番目のパラメータを使用して、リスナーの優先順位を設定します。この方法はstopImmediatePropagation()を利用している場合に役立ちます。最も高い優先順位を持つリスナーが常に最初に呼び出されます。新しい開発方法を理解するには、このチュートリアルに含まれている例のように、小さなテストファイルを作成すると便利です。機能を分離し、様々な値をパラメータに渡してみて、ActionScript 3.0でイベントが制御され、キャプチャされる様子を理解してください。オブジェクトを重ねて配置するなど、様々なシナリオを試して、新しいイベント処理方法がActionScript 2.0とはどのように異なるかを確認してください。結果を出力パネルでトレースすると、受け取られたイベントに関するフィードバックを直ちに確認できます。
新しいEventDispatcherの動作に慣れたら、Eventクラスを拡張し、独自のカスタムクラスを外部のActionScriptファイルに定義して作成できます。カスタムサブクラスを作成し、一意のプロパティを持つ独自のカスタムイベントの送り出しを試してください。独自のEventクラスを作成すると、デフォルトのパラメータを使用して、Flash Playerで現在処理されていないカスタムイベントの新しいハンドラを用意できます。この手段は、画面に対するオブジェクトの位置を特定し、上級ユーザインタラクティビティを実現する上で非常に役立ちます。ActionScript 3.0の新しいイベント処理機能の使用方法を習得すると、数多くの新しい開発の可能性を見い出し、入力情報の追跡をより詳細に制御することができるでしょう。
このチュートリアルの冒頭で提供されているサンプルファイルをぜひダウンロードして、ここで説明している概念を確認してみてください。また、『ActionScript 3.0 リファレンスガイド』で説明されているイベント関連クラスとイベント処理情報について理解しておくことをお勧めします。