サイトトップ

Director Flash 書籍 業務内容 プロフィール

Macromedia Flash非公式テクニカルノート

イベントの委譲 (Delegateクラス)

ID: FN0408001 Product: Flash

Platform: All
Version: Flash MX Professional 2004 7.2

Delegateクラスをスクリプトやクラスにimportすると、イベントを特定のスコープと関数に委譲(delegate)することができます。シンタックスは、つぎのとおりです。

import mx.utils.Delegate;
compInstance.addEventListener(イベント名, Delegate.create(スコープオブジェクト, 関数));

引数スコープオブジェクトは、引数に指定した関数を呼出すスコープを特定します。

Delegate.create()の呼出しには、一般にふたつの使い方があります。

  • 同一のイベントを、異なるふたつの関数に送ります。
    詳しくは、後述「1. イベントの関数への委譲」をご参照ください。

  • 関数をその定義されたスコープで呼出します。
    関数をaddEventListener()の引数として渡すと、その関数はメッセージを配信するコンポーネントインスタンスのスコープで実行され[*1]、関数を定義したオブジェクトのスコープでは呼出されません。詳しくは、後述「2. 関数のスコープの委譲」をご参照ください。

[*1]addEventListener()メソッドの第2引数に関数を指定すると、リスナー関数はイベントを配信するコンポーネントインスタンスのスコープで呼出されます。以下のサンプルスクリプトでは、リスナー関数clickHandlerがButtonコンポーネントインスタンスmy_btnのスコープで呼出されるので、関数ブロック({})内のthisはmy_btnを参照します。したがって、thisを参照してタイムライン上のプロパティにアクセスしようとすれば、undefinedが返されます。

// [出力]パネルの表示
_level0.my_btn,undefined,_level0.my_btn

// _root: フレームアクション
// Buttonコンポーネントインスタンスmy_btnを配置
import mx.controls.Button;
var my_btn:Button;
var nMyProperty:Number = 1;
function clickHandler(eventObject) {
  trace([this, this.nMyProperty, eventObject.target]);
}
my_btn.addEventListener("click", clickHandler);

もっとも、タイムライン上であれば、thisを参照せずデフォルト参照を使うことで対応できます。実際に問題になるのは、後述「2. 関数のスコープの委譲」のようにクラスでメソッド(関数)をリスナーに指定したい場合でしょう。

1. イベントの関数への委譲
Delegate.create()の呼出しが有効なのは、ふたつのコンポーネントがあって、それらが同名のイベントを配信する場合です。たとえば、CheckBoxとButtonコンポーネントがあり、switchステートメントを使ってeventObject.targetプロパティから取得した情報をもとに、どちらのコンポーネントがclickイベントを配信したのか判定したいとします。

以下のコードを試すには、myCheckBox_chbという名前のCheckBoxとmyButton_btnという名前のButtonコンポーネントインスタンスを、それぞれステージに配置します。ふたつのインスタンスを選択し、[F8]キーを押して[シンボルに変換]します。ダイアログボックスが[基本]表示でしたら[詳細]をクリックし、[ActionScriptに書出し]をチェックしたうえで、[AS 2.0クラス]にクラス名「Cart」を入力します。新しいシンボルのインスタンスには、任意のインスタンス名を[プロパティインスペクタ]で設定します。このシンボルはCartクラスに関連づけられ、インスタンスはCartクラスのインスタンスになります。

// import mx.utils.Delegate;  // [*2]
import mx.controls.Button;
import mx.controls.CheckBox;
class Cart {
  var myCheckBox_chb:CheckBox;
  var myButton_btn:Button;
  function onLoad() {
    myCheckBox_chb.addEventListener("click", this);
    myButton_btn.addEventListener("click", this);
  }
  function click(eventObj:Object) {
    switch (eventObj.target) {
    case myButton_btn :
      // メッセージを配信するインスタンス名と
      // イベントタイプを[出力]パネルに表示
      trace(eventObj.target+":"+eventObj.type);
      break;
    case myCheckBox_chb :
      trace(eventObj.target+":"+eventObj.type);
      break;
    }
  }
}


[*2]原文にはこのimprotステートメントの記述があります。しかし、Delecateクラスは使用していませんので、不要です。

以下は、同じクラスファイル(Cart.as)に対して、Delegateを使用するかたちに修正したものです。

import mx.utils.Delegate;
import mx.controls.Button;
import mx.controls.CheckBox;
class Cart {
  var myCheckBox_chb:CheckBox;
  var myButton_btn:Button;
  function onLoad() {
    myCheckBox_chb.addEventListener("click", Delegate.create(this, chb_onClick));
    myButton_btn.addEventListener("click", Delegate.create(this, btn_onClick));  // [*3]
  }
  // 同一のイベントを処理する異なったふたつの関数
  function chb_onClick(eventObj:Object) {
    // メッセージを配信するインスタンス名と
    // イベントタイプを[出力]パネルに表示
    trace(eventObj.target+":"+eventObj.type);
    // FLAファイルのなかのCartクラスが関連づけられたシンボルの
    // インスタンスへの絶対パスを[出力]パネルに表示
    trace(this);
  }
  function btn_onClick(eventObj:Object) {
    trace(eventObj.target+":"+eventObj.type);
    trace(this);
  }
}


[*3]Delegateクラスを使って作成・登録したリスナーを、イベントを配信するインスタンスから削除するには、予めリスナーへの参照を取得しておく必要があります。なお、Delegate.create()メソッドは、関数(Function型データ)を返します。

// ActionScript 2.0クラス定義ファイル: Cart.as
// ButtonコンポーネントインスタンスmyButton_btnを配置
import mx.utils.Delegate;
import mx.controls.Button;
class Cart {
  var myButton_btn:Button;
  var myDelegateFunc:Function;
  function onLoad() {
    myDelegateFunc = Delegate.create(this, btn_onClick);
    myButton_btn.addEventListener("click", myDelegateFunc);
  }
  function btn_onClick(eventObj:Object) {
    trace(eventObj.target+":"+eventObj.type);
    myButton_btn.removeEventListener("click", myDelegateFunc);
    trace(this);
  }
}

2. 関数のスコープの委譲
addEventListener()メソッドには、ふたつの引数があります。イベント名とリスナーへの参照です。リスナーは、オブジェクトか関数のいずれかになります。オブジェクトを渡すと、オブジエクトに設定されたコールバック関数が、オブジェクトのスコープで実行されます。しかし、関数が渡されると、関数はaddEventListener()メソッドを呼出したコンポーネントインスタンスのスコープで実行されることになります。詳しくは、「リスナー内のスコープについて」をご参照ください。

関数はイベントを配信するインスタンスのスコープで実行されるので、関数本体のthisキーワードはそのイベント配信インスタンスを参照することになります。したがって、関数が実装されたクラスのプロパティやメソッドにはアクセスできません。Delegateクラスを使うと、関数のスコープを、その関数が実装されたクラスに委譲することができます。すると、その関数を宣言したクラスのプロパティやメソッドにアクセスすることが可能になります。

以下のサンプルは、前節「イベントの関数への委譲」と同じ内容で、Cart.asクラスファイルを異なるスタイルにしました。

import mx.controls.Button;
import mx.controls.CheckBox;
class Cart {
  var myCheckBox_chb:CheckBox;
  var myButton_btn:Button;
  // chb_onClick関数からアクセスする変数を定義
  var i:Number = 10;
  function onLoad() {
    myCheckBox_chb.addEventListener("click", chb_onClick);
  }
  function chb_onClick(eventObj:Object) {
    // 変数iにアクセスして10が出力できるように思えます
    // しかし[出力]バネルにはundefinedが表示されます
    // 関数のスコープがiを定義したCartインスタンスではないからです
    trace(i);
  }
}

Cartクラスのプロパティとメソッドにアクセスできるようにするには、つぎのようにDelegate.create()を呼出してaddEventListener()の第2引数に指定します。

import mx.utils.Delegate;
import mx.controls.Button;
import mx.controls.CheckBox;
class Cart {
  var myCheckBox_chb:CheckBox;
  var myButton_btn:Button;
  // chb_onClick関数からアクセスする変数を定義
  var i:Number = 10;
  function onLoad() {
    myCheckBox_chb.addEventListener("click", Delegate.create(this, chb_onClick));
  }
  function chb_onClick(eventObj:Object) {
    // [出力]バネルには10が表示されます
    // 関数のスコープがCartインスタンスに指定されているからです
    trace(i);
  }
}

出典
Flash MX 2004 7.2-E [Help] > [Using Components] > [Handling Component Events] > [Delegating events]より邦訳。

_____

作成者: 野中文雄
更新日: 2004年9月8日 訳者註[*3]を追加
作成日: 2004年8月5日


Copyright © 2001-2006 Fumio Nonaka.  All rights reserved.