サイトトップ

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

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

マウスイベントMouseEvent.MOUSE_OVERとMouseEvent.ROLL_OVERの違い

ID: FN1110008 Product: Flash CS3 and above Platform: All Version: 9 and above/ActionScript 3.0

マウスポインタがインスタンスにロールオーバーしたとき起こるマウスイベントには、InteractiveObject.mouseOver(定数MouseEvent.MOUSE_OVER)とInteractiveObject.rollOver(定数MouseEvent.ROLL_OVER)があります。しかし、その違いがわかりにくいようです。大まかにいえば、前者はイベントの細かい制御ができます。それに対して、後者はボタンやメニューなどのインターフェイスに手軽に使えます。本稿では、その具体的な内容を簡単にご説明します。

対となるロールアウトのマウスイベントは、それぞれInteractiveObject.mouseOut(定数MouseEvent.MOUSE_OUT)とInteractiveObject.rollOut(定数MouseEvent.ROLL_OUT)です。イベントの考え方はロールオーバーと基本的に変わりません。なお、マウスイベントの概要については、F-siteセミナーのレポート「イベントを制する者、ActionScript 3.0を制す」をお読みください。


01 イベントが起きるインスタンス
マウスイベントはひとつひとつの(InteractiveObject)インスタンスが受取るのを基本とします。インスタンスにイベントリスナーが登録されているかどうかは問いません。InteractiveObject.mouseOutイベントはこの基本にしたがいます。つまり、親インスタンスにイベントリスナーが登録されていても、子インスタンスをもてばイベントはそれらひとつひとつについて生じます。

けれど、単純なボタンのインターフェイスなどの場合、それでは困ることもあります。InteractiveObject.rollOutイベントは、リスナーを登録した親インスタンスがマウスイベントをまとめて受取り、子インスタンスひとつひとつを識別しません。

ふたつのイベントの違いを確かめるため、前出「イベントを制する者、ActionScript 3.0を制す」でご紹介したテスト用のスクリプトを試してみましょう(細かい内容はレポートをご参照ください)。タイムラインにふたつの子インスタンス(pen0_mcとpen1_mc)をもつ親MovieClipインスタンス(parent_mc)のフレームアクションとして書きます(図001)。以下にスクリプト001として再掲しました。親インスタンスのInteractiveObject.mouseOverInteractiveObject.rollOverイベントに同じリスナー関数(xTrace())を登録しています。

スクリプト001■InteractiveObject.mouseOverとInteractiveObject.rollOverイベントの両方にリスナー関数を設定
    // MovieClip: マウスイベントを処理するparent_mc
    // MovieClipインスタンスpen0_mcとpen1_mcを配置
    // 第1フレームアクション
  1. addEventListener(MouseEvent.MOUSE_OVER, xTrace);
  2. addEventListener(MouseEvent.ROLL_OVER, xTrace);
  3. function xTrace(eventObject:MouseEvent):void {
  4.   trace(eventObject.type, eventObject.target.name, eventObject.currentTarget.name);
  5. }

図001■ふたつの子インスタンスが含まれた親MovieClipシンボルにフレームアクションを記述

リスナー関数(xTrace())は、引数に受取ったEventオブジェクトの3つのプロパティtrace()関数で[出力]します(スクリプト001第4行目)。それぞれのプロパティの値は、下表001のとおりです。なお、インスタンスの参照はそのまま[出力]しても区別できませんので、DisplayObject.nameプロパティでインスタンス名を取出しています。

表001■Eventクラスのプロパティ
Eventクラスのプロパティ プロパティの値
currentTarget イベントリスナーを登録したインスタンス
target イベントが起こったインスタンス
type 起こったイベントを示す文字列

[ムービープレビュー]でひとつの子インスタンス(pen0_mc)にマウスポインタを重ねると、InteractiveObject.mouseOverInteractiveObject.rollOverのふたつのイベントがともに生じます。しかし、イベントが起こったインスタンス(Event.targetプロパティの値)が異なることにご注目ください。前述のとおりInteractiveObject.rollOverイベントでは、子インスタンスへのマウスインタラクションも親インスタンス(parent_mc)が受取るのです。

rollOver parent_mc parent_mc
mouseOver pen0_mc parent_mc

ふたつの子インスタンスの重なった部分をとおって、もうひとつのインスタンス(pen1_mc)にマウスポインタを重ねると、その子インスタンスに対してInteractiveObject.mouseOverイベントが起こります(前掲図001)。けれど、InteractiveObject.rollOverイベントでは子インスタンスをまとめてひとつの親インスタンスとみなしますので、新たなイベントは発生しません。

mouseOver pen1_mc parent_mc

InteractiveObject.mouseOverイベントを用いても、親インスタンスのDisplayObjectContainer.mouseChildrenプロパティfalseに設定すればイベントは親インスタンスに生じるようになります[*1]。たとえば、前掲スクリプト001につぎの1ステートメントを加えれば、ふたつのイベントは同じように起こります。重なり合った子インスタンスの間でマウスポインタを動かしても、新たなイベントは生じません。

  1. mouseChildren = false;

rollOver parent_mc parent_mc
mouseOver parent_mc parent_mc

[*1] 子インスタンスひとつひとつについてマウスイベント(などのインタラクティブなイベント)の対象から外したいときは、子インスタンスのInteractiveObject.mouseEnabledプロパティをfalseにします。すると、イベントは親インスタンスに発生します。ただし、子インスタンスがさらに孫(InteractiveObject)インスタンスを含んでいる場合は、それら孫インスタンスにマウスイベントが起こります。


02 イベントのバブリング
多くのマウスイベントは、表示リストの親インスタンスにも送られます。送られたイベントはバケツリレーのように表示リストの階層を順に遡り、頂点のStageオブジェクトまで届きます。このようにイベントが上っていくことを「バブリング」といいます。

あるマウスイベントがバブリングするかどうかは、そのイベントオブジェクトのEvent.bubblesプロパティ(読取り専用)で確かめられます。MouseEventクラスの定数でプロパティ値を調べると、下表002のとおりMouseEvent.MOUSE_OVERtrueでバブリングし、MouseEvent.ROLL_OVERfalseなのでバブリングしません。実際、定数MouseEvent.MOUSE_OVERで登録したリスナー関数が、子インスタンスに起こったInteractiveObject.mouseOverイベントを扱えるのは、親インスタンスにイベントがバブリングするからです。

表002■ロールオーバーのマウスイベントとEvent.bubblesプロパティの値
マウスイベント Event.bubblesプロパティの値
MOUSE_OVER true
ROLL_OVER false

バブリングするマウスイベントをうまく使った例は、ロールオーバーよりクリックの方が示しやすいです。そこでまた、前出「イベントを制する者、ActionScript 3.0を制す」からサンプルをひとつご紹介します(細かい内容はレポートをご参照ください)。クリックは、インスタンスのうえでマウスボタンを押して、同じインスタンスのうえで放したとき生じるイベントです。しかし、マウスボタンをインスタンスの外で放したときにも、何か処理を加えたい場合があります。

そこで、マウスイベントInteractiveObject.mouseDown(定数MouseEvent.MOUSE_DOWN)とInteractiveObject.mouseUp(定数MouseEvent.MOUSE_UP)を用います。どちらのマウスイベントもバブリングします。インスタンス上でマウスボタンを押してInteractiveObject.mouseDownイベントが起こったら、処理は始まります。続くマウスボタンを放すイベントInteractiveObject.mouseUpの発生が、インスタンス上か外かによって処理を分けるのがお題です。

以下にスクリプト002として再掲したフレームアクションを、ボタンにするMovieClipシンボルに書くと、まずインスタンス上でマウスボタンを押したとき"press"の文字が[出力]されます。つぎに、マウスボタンを放すのが同じインスタンス上なら"release"、外なら"releaseOutside"と[出力]されます。

スクリプト002■インスタンス領域外まで含めたマウスクリック操作を処理する
    // MovieClip: マウスイベントを処理する
    // 第1フレームアクション
  1. addEventListener(MouseEvent.MOUSE_DOWN, xPress);
  2. function xPress(eventObject:MouseEvent):void {   // サーブを返す
  3.   trace("press");
      // ふたりでmouseUpを待つ
  4.   addEventListener(MouseEvent.MOUSE_UP, xRelease);
  5.   stage.addEventListener(MouseEvent.MOUSE_UP, xReleaseOutside);
  6. }
  7. function xRelease(eventObject:MouseEvent):void {   // 前衛がレシーブ
  8.   trace("release");
      // リセット
  9.   removeEventListener(MouseEvent.MOUSE_UP, xRelease);
  10.   stage.removeEventListener(MouseEvent.MOUSE_UP, xReleaseOutside);
  11. }
  12. function xReleaseOutside(eventObject:MouseEvent):void {   // 後衛がレシーブ
  13.   trace("releaseOutside");
      // リセット
  14.   removeEventListener(MouseEvent.MOUSE_UP, xRelease);
  15.   stage.removeEventListener(MouseEvent.MOUSE_UP, xReleaseOutside);
  16. }

処理の流れを前出「イベントを制する者、ActionScript 3.0を制す」は、テニスのダブルスに例えて説明しています。前衛がボタンのインスタンス、後衛はステージ(Stageオブジェクト)です。

  1. 前衛のボタン用インスタンスがコートに入り、サーブのmouseDown(マウスボタンの押す操作)をレシーブする。
  2. 前衛の呼びかけに応じて後衛のステージがコートに入り、ふたりでつぎに返されるmouseUp(マウスボタンの放す操作)を待つ。
  3. mouseUpが前衛の守備領域であるボタンのインスタンス上でなされれば、前衛が返し、ボタンのインスタンス上のクリックとなる。前衛が受けなかったmouseUpは、ボタンのインスタンス外の操作であり、後衛がレシーブする。
  4. リセットして、つぎのサーブを待つ。

マウスボタンを放したのがインスタンス上か外かは、条件判定によることなく、バブリングするマウスイベントの流れにより切り分けています。つまり、インスタンス上でマウスボタンを放したとき、そのリスナー関数(xRelease()スクリプト002第7〜11行目)内のステートメント(第10行目)でStageオブジェクトのリスナー関数(xReleaseOutside())を除いているために、バブリングするマウスイベントはStageオブジェクトでは扱われなくなるのです[*2]

このようにイベントのバブリングをうまく切り分けると、ActionScript 3.0に実装されていないインスタンス外でマウスボタンを放すというイベントもすっきりと加えられます。

[*2] イベントリスナーを除くのではなく、イベントの流れそのものを止めてしまうこともできます。詳しくは「Event.stopPropagation()とEvent.stopImmediatePropagation()メソッドの違い」をご覧ください。


03 ふたつのイベントの違い
以上をまとめると、InteractiveObject.mouseOverInteractiveObject.rollOverイベントには大きくふたつの違いがあります(表003)。第1に、子インスタンスに対するロールオーバーが、どのインスタンスのイベントとして発生するか。第2に、マウスイベントがバブリングするかどうかです。

表003■InteractiveObject.mouseOverとInteractiveObject.rollOverイベントのおもな違い
相違点 InteractiveObjectクラスのマウスイベント
mouseOver rollOver
子インスタンスに対するイベントの発生 子インスタンス自身 リスナーを加えた親インスタンス
マウスイベントのバブリング バブリングする バブリングしない

ボタンのような単純なインターフェイスであれば、多くの場合子インスタンスでイベントを受取ることも、表示リストの親インスタンスにイベントを送ることも要らないでしょう。そういうときには、InteractiveObject.rollOverイベントでロールオーバーを扱うのが簡単です。

マウスイベントを細かく扱ったり、表示リスト内のイベントの流れを制御したいときには、InteractiveObject.mouseOverイベントが適しています。前掲スクリプト002のように、独自のマウスイベントを加えることもできます。ただし、イベントが発生するインスタンスやイベントのバブリングを正しく扱わないと、無駄な負荷が生じたり、予期しない結果に陥るので注意しなければなりません[*3]

[*3] 表示リストの階層が深いと、イベントの発生したインスタンスを定め、親インスタンスにバブリングすることは負荷を高めます。DisplayObjectContainer.mouseChildrenプロパティ(前述01)、あるいはEvent.stopPropagation()Event.stopImmediatePropagation()メソッド(前出注[*2])などを適切に用いることが大切です。



作成者: 野中文雄
作成日: 2011年10月28日


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