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 または AIR は以下のトレース出力を生成します。
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 または AIR は以下のトレース出力を生成します。
clickHandler detected an event of type: click
the this keyword refers to: [object ChildSprite]
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 キーワードで child という名前の ChildSprite インスタンスを参照し、プログラムから 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] となると考えられる場合でも、this キーワードはグローバルオブジェクトを参照します。動的なプロパティ名を addEventListener() に引数として渡す場合、Flash Player または AIR はバインドメソッドを作成できません。なぜなら、その場合に listener パラメーターとして渡されるのはリスナー関数の単なるメモリアドレスであり、Flash Player および AIR がそのメモリアドレスと myListenerObj インスタンスを結び付ける手段がないからです。