| ActionScript 3.0 のプログラミング > Flash Player API > イベントの処理 > イベントリスナー | |||
イベントリスナーとは、特定のイベントに応答して Flash Player により実行される関数のことであり、イベントハンドラとも呼ばれます。イベントリスナーを登録するには 2 つの手順を実行します。まず、目的のイベントに応答して Flash Player に実行させるための関数またはクラスメソッドを作成します。これは、リスナー関数またはイベントハンドラ関数と呼ばれることもあります。次に addEventListener() メソッドを使用して、そのリスナー関数を、イベントのターゲットまたは該当するイベントフローに含まれる任意の表示リストオブジェクトに登録します。
ActionScript 3.0 のイベントモデルのうち、リスナー関数の作成に関する部分は DOM イベントモデルに準拠していません。DOM イベントモデルでは、イベントリスナーとリスナー関数が明確に区別されています。イベントリスナーは EventListener インターフェイスを実装したクラスのインスタンスを意味し、リスナー関数はそのクラスが備える handleEvent() というメソッドを意味します。DOM イベントモデルにおいては、リスナー関数自体を登録するのではなく、リスナー関数を含んだクラスインスタンスを登録する形式をとります。
ActionScript 3.0 のイベントモデルには、イベントリスナーとリスナー関数との区別がありません。ActionScript 3.0 には EventListener インターフェイスがなく、リスナー関数はクラス内、クラス外のいずれに定義することもできます。また、リスナー関数の名前が handleEvent() である必要はなく、識別子として有効な任意の名前を付けることができます。ActionScript 3.0 においては、リスナー関数自体の名前を登録する形式をとります。
次のコードは、赤い正方形のシェイプを表示する単純な SWF ファイルです。クラス内にある clickHandler() というリスナー関数で、赤い正方形に対するマウスクリックイベントを受け付けます。
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
}
function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
この SWF ファイルで、ユーザーによって正方形がクリックされると、Flash Player は次のトレース出力を生成します。
clickHandler detected an event of type: click the this keyword refers to: [object global]
イベントオブジェクトが、clickHandler() にパラメータとして渡されています。これにより、リスナー関数の中でイベントオブジェクトを調べることができます。この例では、イベントオブジェクトの type プロパティを使用し、イベントがクリックイベントであることを確認しています。
また、この例では this キーワードの値も確認しています。this はグローバルオブジェクトを参照しています。なぜなら、リスナー関数をカスタムクラスやオブジェクトに属さない外部で定義しているからです。
次の例では、前出の例と同じく ClickExample クラスを定義していますが、clickHandler() 関数を ChildSprite クラスのメソッドとして定義している点が異なります。
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
private function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
}
この SWF ファイルで、ユーザーによって赤い正方形がクリックされると、Flash Player は次のトレース出力を生成します。
clickHandler detected an event of type: click the this keyword refers to: [object global]
this キーワードは child という ChildSprite インスタンスを参照しています。この点に関しては動作が変更されており、ActionScript 2.0 とは異なります。ActionScript 2.0 のコンポーネントでは、UIEventDispatcher.addEventListener() に対してクラスメソッドを指定した場合、リスナーメソッドのスコープは、メソッドが定義されているクラスではなくイベントをブロードキャストしたコンポーネントに基づいて決まるようになっていました。つまり、この例と同じテクニックを ActionScript 2.0 で使用したとすると、this キーワードは、ChildSprite インスタンスではなくイベントをブロードキャストしたコンポーネントを参照することになります。
この従来の仕様では、リスナーメソッドからそのメソッドがあるクラス内の他のメソッドやプロパティにアクセスできないため、場合によっては非常に大きな問題が生じていました。これを回避するために、ActionScript 2.0 には、mx.util.Delegate クラスを使用してリスナーメソッドのスコープを変更するという方法が用意されていました。ActionScript 3.0 では addEventListener() の呼び出し時にバインドメソッドが作成されるため、この回避策は不要です。結果として、this キーワードの参照先は ChildSprite インスタンス child となり、プログラムで ChildSprite クラス内の他のメソッドやプロパティにアクセスできるようになりました。
第 3 のテクニックとして、汎用オブジェクトを作成し、そのオブジェクトのプロパティによって動的にリスナー関数を割り当てる方法がありますが、これを使用することはお勧めできません。この方法を説明するのは、ActionScript 2.0 で一般的に使用されていたという理由からです。ActionScript 3.0 では使用しないでください。このテクニックでは this キーワードの参照先がリスナーオブジェクトではなくグローバルオブジェクトになるため、望ましくありません。
次の例では、前出の例と同じく ClickExample クラスを定義していますが、リスナー関数を myListenerObj という汎用オブジェクトの一部として定義している点が異なります。
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler);
}
}
var myListenerObj:Object = new Object();
myListenerObj.clickHandler = function (event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
トレースの結果は次のようになります。
clickHandler detected an event of type: click the this keyword refers to: [object global]
this の参照先は myListenerObj であるかのように見え、トレース出力も [object Object]
になっていますが、実際の参照先はグローバルオブジェクトです。動的なプロパティ名を addEventListener() のパラメータとして指定した場合、Flash Player はバインドメソッドを作成できません。なぜなら、その場合に listener パラメータとして渡されるのはリスナー関数の単なるメモリアドレスであり、Flash Player がそのメモリアドレスと myListenerObj インスタンスを結び付ける手段がないからです。
リスナー関数を管理するには、IEventDispatcher インターフェイスのメソッドを使用します。IEventDispatcher インターフェイスは、DOM イベントモデルにおける EventTarget インターフェイスの ActionScript 3.0 バージョンです。IEventDispatcher という名前からは、Event オブジェクトを送信 (送出) することが主な目的であるように思われますが、実際には、イベントリスナーを登録、確認、および削除する目的でメソッドを使用する機会が最も多いといえます。IEventDispatcher インターフェイスには、次のコードに示す 5 つのメソッドが定義されています。
package flash.events
{
public interface IEventDispatcher
{
function addEventListener(eventName:String,
listener:Object,
useCapture:Boolean=false,
priority:Integer=0,
useWeakReference:Boolean=false):Boolean;
function removeEventListener(eventName:String,
listener:Object,
useCapture:Boolean=false):Boolean;
function dispatchEvent(eventObject:Event):Boolean;
function hasEventListener(eventName:String):Boolean;
function willTrigger(eventName:String):Boolean;
}
}
Flash Player API では、EventDispatcher クラスに IEventDispatcher インターフェイスが実装されています。このクラスは、イベントフローの一部やイベントターゲットとして機能するすべてのクラスに対する基本クラスです。たとえば、DisplayObject クラスは EventDispatcher クラスを継承しています。このため、表示リスト内の任意のオブジェクトは IEventDispatcher インターフェイスのメソッドにアクセスできます。
addEventListener() は、IEventDispatcher インターフェイスで最もよく使用されるメソッドです。リスナー関数を登録する際にはこのメソッドを使用します。type および listener の 2 つのパラメータは必須です。type パラメータでは、イベントのタイプを指定します。listener パラメータでは、目的のイベントが発生したときに実行するリスナー関数を指定します。listener パラメータには、関数への参照またはクラスメソッドへの参照のいずれかを指定できます。
|
メモ |
|
|
addEventListener() メソッドの useCapture パラメータを使用すると、イベントフローのどの段階においてリスナーをアクティブにするかを制御できます。useCapture に true を指定すると、そのリスナーはイベントフローのキャプチャ段階でアクティブになります。useCapture に false を指定すると、そのリスナーはイベントフローのターゲット段階とバブリング段階でアクティブになります。イベントフローのすべての段階においてイベントを受け取るには、useCapture に true を指定した場合と、useCapture に false を指定した場合の両方について、合計 2 回 addEventListener() を呼び出す必要があります。
addEventListener() メソッドの priority パラメータは、DOM Level 3 イベントモデルの正式なパラメータではありません。これは、イベントリスナーをより柔軟に編成できるようにするため、ActionScript 3.0 で独自に提供されているパラメータです。addEventListener() を呼び出す際に priority パラメータに整数値を指定することで、イベントリスナーの優先度を設定できます。デフォルト値は 0 ですが、負の整数値または正の整数値を指定することができます。指定した数値が高いほど、イベントリスナーが早い順序で実行されます。同じ優先度で登録された複数のイベントリスナーがある場合、それらは登録順に実行されます。つまり、先に登録したイベントリスナーほど早く実行されます。
useWeakReference パラメータを使用すると、そのリスナー関数に対する参照を通常の参照にするか、弱参照にするかを指定できます。このパラメータに true を指定すると、リスナー関数が使用されなくなった後もメモリ上に残り続けるのを防ぐことができます。Flash Player では、"ガベージコレクション" というテクニックによって、使用されなくなったオブジェクトをメモリから削除します。あるオブジェクトに対して参照が 1 つも存在しなくなったとき、そのオブジェクトはもう使用されないと見なされます。弱参照はガベージコレクションのシステムで無視されるため、弱参照による参照しか受けていないリスナー関数はガベージコレクションの対象となります。
不要になったイベントリスナーを削除するには、removeEventListener() メソッドを使用します。不要になったリスナーは削除することをお勧めします。必須のパラメータは eventName および listener の 2 つで、addEventListener() メソッドの必須パラメータと同じです。前述したとおり、イベントフローのすべての段階においてイベントを受け取る場合は、useCapture に true を指定した場合と false を指定した場合の両方について、合計 2 回 addEventListener() を呼び出します。その後で両方のイベントリスナーを削除するには、useCapture に true を指定した場合と false を指定した場合の両方について合計 2 回 removeEventListener() を呼び出す必要があります。
dispatchEvent() メソッドは、独自のイベントオブジェクトをイベントフローに送出する場合に使用する上級開発者向けのメソッドです。このメソッドに指定できるパラメータは 1 つだけで、Event クラスまたはそのサブクラスのインスタンスを指定します。送出されたイベントオブジェクトの target プロパティには、dispatchEvent() が呼び出されたオブジェクトが設定されます。
IEventDispatcher インターフェイスが備える残り 2 つのメソッドは、イベントリスナーの存在に関する有用な情報を取得するために使用します。指定した表示リストオブジェクトに、指定したイベントタイプのイベントリスナーが登録されている場合、hasEventListener() メソッドは true を返します。willTrigger() メソッドも、指定した表示リストオブジェクトについてリスナーが登録されている場合に true を返します。ただし、willTrigger() では指定した表示オブジェクト自体を確認するだけでなく、イベントフローのすべての段階におけるその表示リストオブジェクトの祖先もすべて確認します。
エラー処理に関して、ActionScript 3.0 における最も重要なメカニズムはイベントではなく例外ですが、非同期の操作 (ファイルのロードなど) には例外処理を使用できません。非同期の操作を実行中にエラーが発生すると、Flash Player によりエラーイベントオブジェクトが送出されます。エラーイベントに対するリスナーを作成していない場合、デバッグ版の Flash Player では、発生したエラーに関する情報がダイアログボックスに表示されます。たとえば、ファイルのロード処理において無効な URL を指定すると、デバッグ版 Flash Player では、エラーを示すこのダイアログボックスが表示されます。
エラーイベントのほとんどは ErrorEvent クラスに基づいているため、Flash Player で表示するためのエラーメッセージを格納する text というプロパティがあります。ただし、StatusEvent クラスと NetStatusEvent クラスの 2 つはこれに該当しません。これらのクラスには level プロパティ (StatusEvent.level および NetStatusEvent.info.level) があります。level プロパティの値が "error" の場合、これらのイベントタイプはエラーイベントと見なされます。
エラーイベントが発生しても、それによって SWF ファイルの実行が停止することはありません。単に、デバッグ版のブラウザプラグインまたはスタンドアローンの Player ではダイアログボックスによって、オーサリング環境の Player では出力パネルのメッセージによって、また、Adobe Flex Builder 2 ではログファイルのエントリによって、エラーの情報が示されるだけです。リリース版の Flash Player では何も表示されません。
Flex 2.01