サイトトップ

Director Flash 書籍 業務内容 プロフィール
Flash OOP ActionScript 3.0 for 3D ActionScript 3 Professional Guide ActionScript 3 Professional Guide
【Now on Sale!!】
Flash プロの現場の仕事術 CS5/CS4/CS3対応
【Now on Sale!!】
ActionScript 3.0による三次元表現ガイドブック
ActionScript 3.0プロフェッショナルガイド

マウスイベントにActionScript 2.0風のハンドラを設定する

Date: 2011年3月5日 Product: Flash Platform: All Viersion: CS4 and above/ActionScript 3.0

    index
  1. バブリングするイベントを捉える
  2. Stageオブジェクトのリスナーでインスタンスのマウスイベントを扱う
  3. スクリプトをドキュメントクラスとして定義する
  4. サンプルファイル (Flash CS4形式/ZIP圧縮/約41KB)


ボクシングでは「左を制する者は世界を制す」といわれるらしい。「左」つまり「ジャブ」の重要性を伝えることばだ。ActionScriptにおいては、「イベント」がその基礎を成す。ActionScript 3.0では、イベントの扱い方や考え方が、2.0/1.0とは大きく変わった。中でもマウスイベントは、イベントの流れとその扱いを知るのに適している。お題は「マウスイベントにActionScript 2.0風のハンドラを設定する」とした。

1. バブリングするイベントを捉える
MovieClipインスタンスに、ActionScript 2.0風のマウスイベントハンドラを設定できるようにしてみたい(図001)。今回は、onReleaseとonReleaseOutsideを加える。とくに後者は、ActionScript 3.0のマウスイベントには対応するイベントがない。

図001■MovieClipインスタンスにマウスイベントハンドラを設定する

ActionScript 3.0では、マウスイベントの多くが「バブリング」する。バブリングというのは、イベント(オブジェクト)が表示リストの階層を親に向かって順に伝わっていくことだ(図002)[*1]。つまり、子のインスタンスに起こったマウスイベントは、親インスタンスのイベントリスナーで扱うことができる。

図002■イベントのバブリング

すると、Stageオブジェクトにイベントリスナーを登録しておけば、バブリングするマウスイベントをすべて扱えることになる。イベントが起こったインスタンスとリスナーを登録した(呼出した)インスタンスは、リスナーの受取るイベントオブジェクトを通して、それぞれEventクラスのプロパティEvent.targetEvent.currentTargetで確かめられる(表001)。

表001イベントが起こったインスタンスとリスナーを呼出すインスタンス
Eventクラスのプロパティ 参照されるインスタンス
Event.target イベントが起こったインスタンス
Event.currentTarget イベントリスナーを呼出したインスタンス

[*1] イベントの流れとその扱いについては、[ActionScript 3.0開発ガイド] > [コアActionScriptクラス] > [イベント処理] > [イベントフロー]およびAdobeデベロッパーセンター「Action Script 3.0のイベント処理について」を参照。


2. Stageオブジェクトのリスナーでインスタンスのマウスイベントを扱う
バブリングするマウスイベントはStageオブジェクトのリスナーで捉えて、インスタンスへのマウス操作を扱ってみよう。イベントはInteractiveObject.mouseDown(定数MouseEvent.MOUSE_UP)とInteractiveObject.mouseUp(定数MouseEvent.MOUSE_UP)を用いる。ふたつのイベントでEvent.targetプロパティの参照が同じだったら、インスタンスへのマウスクリックと認められる。

スクリプトはふたつのイベントリスナーで組立てる。まず、InteractiveObject.mouseDownイベントで、Event.targetプロパティのインスタンスを変数(_target)に納め、InteractiveObject.mouseUpイベントのリスナーを設定する。

つぎに、InteractiveObject.mouseUpイベントで、Event.targetプロパティの参照が変数に入れたインスタンスと同じかどうかを調べる。同じであれば、マウスクリックと認められる。異なれば、インスタンス外でマウスボタンを放したことになる。

そこで、インスタンスに設定されたハンドラ(onReleaseまたはonReleaseOutside)を取出し、関数があればそれを呼出す。そして忘れずに、変数とInteractiveObject.mouseUpイベントのリスナーは消し去る。

var _target:MovieClip;   // マウスイベントが起こったインスタンスを入れる変数
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(eventObject:MouseEvent):void {
  // 変数にMouseEvent.MOUSE_DOWNイベントが起こったインスタンスを入れる
  stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);   // リスナー登録
}
function mouseUpHandler(eventObject:MouseEvent):void {
  // MouseEvent.MOUSE_DOWNMouseEvent.MOUSE_UPイベントが同じインスタンスに起こったら
  // イベントハンドラを取出して呼出す
  // 変数の参照を消す
  stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);   // リスナー削除
}

フレームアクション全体は、後掲スクリプト001のとおりだ。ふたつのリスナー関数について簡単に説明する。まず、関数mouseDownHandler()だ(第3〜9行目)。

  1. function mouseDownHandler(eventObject:MouseEvent):void {
  2.   var target_mc:MovieClip = eventObject.target as MovieClip;
  3.   if (target_mc) {
  4.     _target = target_mc;
  5.     stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
  6.   }
  7. }

リスナー関数mouseDownHandler()は、Event.targetプロパティの参照を変数(_target)に納め、InteractiveObject.mouseUpイベントのリスナーを登録する(第6〜7行目)。ただし、プロパティのデータ型はObjectなので、キャストが必要だ(「rootプロパティでメインタイムラインの関数にアクセスできない」の「対処法」[2]「キャスト」参照)。このサンプルでは、データ型をMovieClipとした(第4行目)。キャストできないときは、処理は行わない(第5行目)。

つぎに、関数mouseUpHandler()が、InteractiveObject.mouseUpイベントで呼出される(スクリプト001第10〜23行目)。

  1. function mouseUpHandler(eventObject:MouseEvent):void {
  2.   var target_mc:MovieClip = eventObject.target as MovieClip;
  3.   var callback:Function;
  4.   if (target_mc == _target) {
  5.     callback = target_mc.onRelease;
  6.   } else {
  7.     callback = _target.onReleaseOutside;
  8.   }
  9.   if (Boolean(callback)) {
  10.     callback(eventObject);
  11.   }
  12.   _target = null;
  13.   stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
  14. }

Event.targetプロパティの参照が変数(_target)に納められたインスタンスと同じかどうかを確かめる。同じならそのonRelease、違えばonReleaseOutsideに設定された関数を変数(callback)に取出す(スクリプト001第11〜17行目)。そして、関数があれば、イベントオブジェクトを引数に渡して呼出す(第18〜20行目)。その後、変数(_target)の参照とInteractiveObject.mouseUpイベントのリスナーは消し去る。

スクリプト001■マウスイベントをActionScript 2.0風のハンドラで扱う
    // フレームアクション: メインタイムライン
  1. var _target:MovieClip;
  2. stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
  3. function mouseDownHandler(eventObject:MouseEvent):void {
  4.   var target_mc:MovieClip = eventObject.target as MovieClip;
  5.   if (target_mc) {
  6.     _target = target_mc;
  7.     stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
  8.   }
  9. }
  10. function mouseUpHandler(eventObject:MouseEvent):void {
  11.   var target_mc:MovieClip = eventObject.target as MovieClip;
  12.   var callback:Function;
  13.   if (target_mc == _target) {
  14.     callback = target_mc.onRelease;
  15.   } else {
  16.     callback = _target.onReleaseOutside;
  17.   }
  18.   if (Boolean(callback)) {
  19.     callback(eventObject);
  20.   }
  21.   _target = null;
  22.   stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
  23. }

後は、ボタンのMovieClipインスタンス(button_mc)をタイムラインに置いて、マウスイベントに対するハンドラを設定すればよい(前掲図001)。

button_mc.onRelease = function (eventObject:MouseEvent):void {
  trace(eventObject.target, "click");
};
button_mc.onReleaseOutside = function (eventObject:MouseEvent):void {
  trace(eventObject.target, "cancel");
};

[ムービープレビュー]を確かめると、インスタンスへのマウス操作に応じて、設定したハンドラが呼出される(図003)。なお、つぎのような警告は、イベントハンドラをActionScript 2.0と同じ名前にしたことによるもので、とくに問題はない。

Warning: 1090: 移行の問題 : ActionScript 3.0では、onReleaseイベントハンドラは Flash Playerによって実行時に自動的にトリガされません。最初に、このイベントハンドラをaddEventListener('click', callback_handler)を使用して登録する必要があります。
図003■インスタンスへのマウス操作に応じてイベントハンドラが呼出される


3. スクリプトをドキュメントクラスとして定義する
前掲スクリプト001をドキュメントクラスとして定義すれば(図004)、Flashムービー(FLA)ファイルのフレームアクションには、マウスイベントハンドラだけをActionScript 2.0のように記述できる(前掲図001参照)。参考までに、そのクラス定義(MouseEventHandlerCaller)をスクリプト002として掲げる。

図004■[プロパティ]インスペクタで[ドキュメント]に[クラス]を設定する

スクリプト002■マウスイベントをActionScript 2.0風のハンドラで扱うクラス定義
    // ActionScript 3.0クラス定義ファイル: MouseEventHandlerCaller.as
  1. package {
  2.   import flash.display.MovieClip;
  3.   import flash.events.MouseEvent;
  4.   public class MouseEventHandlerCaller extends MovieClip {
  5.     private var _target:MovieClip;
  6.     public function MouseEventHandlerCaller() {
  7.       stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
  8.     }
  9.     private function mouseDownHandler(eventObject:MouseEvent):void {
  10.       var target_mc:MovieClip = eventObject.target as MovieClip;
  11.       if (target_mc) {
  12.         _target = target_mc;
  13.         stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
  14.       }
  15.     }
  16.     private function mouseUpHandler(eventObject:MouseEvent):void {
  17.       var target_mc:MovieClip = eventObject.target as MovieClip;
  18.       var callback:Function;
  19.       if ((target_mc == _target)) {
  20.         callback = target_mc.onRelease;
  21.       } else {
  22.         callback = _target.onReleaseOutside;
  23.       }
  24.       if (Boolean(callback)) {
  25.         callback(eventObject);
  26.       }
  27.       _target = null;
  28.       stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
  29.     }
  30.   }
  31. }

なお、今回のお題は、マウスイベントを理解するために試みたスクリプトだ。マウス操作をすべてStageオブジェクトで扱うのは、設計として好ましいとはいえない。ラジオボタンのように、かぎられたインスタンスのマウスイベントをまとめて扱う場合に用いるべきだろう。マウスイベントの基本的な扱いや、ボタンのインスタンス外でマウスボタンを放すイベント(onReleaseOutside)の捉え方については、F-siteセミナー「イベントを制する者、ActionScript 3.0を制す」を参照してほしい。


作成者: 野中文雄
作成日: 2011年3月5日
ドラフト作成: 2011年3月3日


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