サイトトップ

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

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

Buttonのthis

ID: FN0303004 Product: Flash

Platform: All
Version: MX and Above

Buttonインスタンスに設定したスクリプトで、ターゲットパスとしてthisを使用すると、その記述場所や使用したイベントハンドラ(アクション/メソッド)によって異なった扱いがされます。簡単なサンプルスクリプトで、その内容を見てみましょう。

1. Buttonアクション(onイベントハンドラアクション内)のthis参照
アニメーションするムービークリップシンボルの最初のフレームにButtonインスタンスを配置して、それがクリックされたらアニメーションを開始するというスクリプトを考えてみましょう。

まず、Buttonをクリックするまでは、アニメーションの再生をとめておく必要があります。そのためには、ムービークリップシンボルの第1フレームに、停止のフレームアクションを記述します。

// MovieClip: アニメーション用
// フレームアクション
this.stop();

つぎに、ムービークリップシンボルの第1フレームにButtonインスタンス配置したら、以下のButtonアクションを設定します。

// Button: 配置されたムービークリップのアニメーション開始用
// Buttonアクション
on (press) {
  this.play();   // thisは配置されたMovieClipを参照
}

「ムービープレビュー」を実行して、Buttonをクリックすると、アニメーションが開始します。Buttonアクションに記述した再生開始のステートメントthis.play()のthisは、スクリプトを記述したButtonインスタンス自身ではなく、配置されたアニメーション用のMovieClipを参照しているからです。MovieClipのイベントハンドラアクションの中では、thisがスクリプトを記述したMovieClipインスタンス自身を参照するのと異なる点です。

thisがスクリプトを設定したインスタンスを参照しないというのは、Buttonオブジェクトの場合にかぎった例外です。このような例外が定められたのは、Buttonがオブジェクトとして実装されていなかったFlash 5の仕様と互換性をもたせるためだと思われます(Flash 5では、Buttonはオブジェクトではなかったので参照のしようがなく、配置されたタイムライン(MovieClip)をその代わりにしたのでしょう)。

2. Buttonオブジェクトのイベントハンドラメソッドに記述したthis参照
Flash MXでは、イベントハンドラメソッドが採用されました。Buttonオブジェクトにも、マウス操作に対応したイベントハンドラメソッドがあります。on (press)に対応したイベントハンドラメソッドは、Button.onPressです。前述のButtonアクションを、このメソッドを使った記述に変更してみることにしましょう。Buttonアクションは、一旦削除します。

イベントハンドラメソッドには、別途定義したfunction名(参照)を指定するか、名前のないfunction(「名前のない関数(匿名関数/関数リテラル)」参照)を直接代入します。ステートメントは、多くの場合フレームアクションに記述します。しかし、ボタンシンボルには、フレームアクションが設定できません(記述したフレームアクションは無視されます)。そこで、Buttonインスタンスを配置したムービークリップシンボルのフレームアクションに、スクリプトを追加することにします。

Buttonを指定するためには、インスタンス名が必要です。ここでは、my_btnとしました。Buttonインスタンスはムービークリップシンボルに配置されていますので、this.my_btnというターゲットパスの指定で参照できます。このインスタンスに対して、Button.onPressメソッドを定義することになります。

// MovieClip: アニメーション用
// フレームアクション
this.stop();
// [追加] Buttonにイベントハンドラメソッドを定義
this.my_btn.onPress = function() {
  trace(this);   // テスト用
  this.play();
};

「ムービープレビュー」でButtonをクリックしても、MovieClipのアニメーションは再生されません。再生のためのステートメントthis.play()で、thisがMovieClipを参照していないからです。テスト用に追加してあるステートメントtrace(this)の出力結果を見ると、それが確認できます。なお、Buttonを内包したMovieClipのインスタンス名は、my_mcとしています。

//「出力」ウィンドウの結果
_level0.my_mc.my_btn

Buttonオブジェクトのイベントハンドラメソッドに定義したfunction中では、thisは定義されたインスタンス自身を指すのです。イベントハンドラメソッドはFlash MXからの実装なので、Flash 5との互換性を考慮する必要がなく、thisはインスタンス自身を参照するという原則が貫かれたのでしょう。

3. Buttonのイベントハンドラメソッドで配置されたタイムラインを参照するには
それでは、前述イベントハンドラメソッドに定義したfunctionは、どのように修正すればよいでしょうか。再生開始のステートメントthis.play()のターゲットパスを、正しく指定する必要があります。

Buttonインスタンスmy_btnのひとつ上の階層ですから、プロパティ_parentを使えばよさそうに思えます。しかし、これだけでは正しく動作しません。

// MovieClip: アニメーション用
// フレームアクション
this.stop();
whereAmI = "In this MovieClip ";   // テスト用変数設定
this.my_btn.onPress = function() {
  trace([this, _parent]);   // テスト用1
  trace(whereAmI);   // テスト用2
  _parent.play();
};

trace()ステートメントを使った確認用のステートメントを2行追加してあります。最初のステートメントは、this_parentの参照内容を出力します(配列アクセス[]を使用して2つの参照を格納したのは、2つのパスを1行で出力するためです)。2つ目のステートメントは、変数whereAmIの値を確認するものです。この変数は、イベントハンドラメソッドを定義する前のステートメントで値を設定しています。つまり、この変数はMovieClipインスタンスmy_mcのタイムライン変数です。「出力」ウィンドウの表示は、以下のようになります。

//「出力」ウィンドウの結果
_level0.my_mc.my_btn,_level0
In this MovieClip

thisがButtonインスタンスmy_btnを参照することは、前に確認したとおりです。その後に続く_parentの参照パスは、_level0つまりメインのタイムライン(_root)になってしまっています。ですから、MovieClipのアニメーションが再生されなかったのです。

_parentがメインのタイムラインを参照した理由は、2つ目のtraceステートメントの結果に隠されています。変数whereAmIの値として、"In this MovieClip"が出力されました。つまり、このMovieClipのタイムライン変数が参照されて、その値が表示されたのです。traceアクションの引数に指定した変数whereAmIには、参照先を指定するターゲットパスがありません。ターゲットパスがないと、デフォルト参照」[*1]としてスクリプトを記述したタイムラインが参照されるということです。

[*1] 筆者は、ターゲットを指定しないプロパティやメソッドの参照先を、「デフォルト参照」と呼んでいます。タイムラインに記述するスクリプト(フレームアクションやMovieClipアクション)では、多くの場合this参照とデフォルト参照とは一致します。したがって、そうした場合には、this参照を省略してもスクリプトの動作は変わりません。

しかし、イベントハンドラメソッドやコールバック関数など、インスタンスにfunctionを定義したときは、関数ブロック({})内からのthis参照とデフォルト参照とが分離します。this参照はfunctionを定義したインスタンスを指し、デフォルト参照はスクリプトを記述したタイムライン(MovieClip)になります。

デフォルト参照先は、ターゲットを指定しないObject.valueOf()メソッドによって確かめることができます。

// タイムライン: _root
// フレームアクション
// MovieClipインスタンス_root.my_mcを配置
this.my_mc.myFunction = function() {
  trace("デフォルト参照: "+valueOf());
  trace("this参照: "+this);
};
this.my_mc.myFunction();

// [出力]パネルの表示
デフォルト参照: _level0
this参照: _level0.my_mc

_parentはMovieClipのプロパティです。ですから、本来はターゲットパスを必要とします。ただ通常は、スクリプトを記述したタイムライン(MovieClip)の上位のMovieClipを参照するために使うので、ターゲットパスを指定しなくても問題はないのです。しかし、今回は事情が異なります。参照したいのは、functionを定義したButtonインスタンスが配置されているMovieClipです。ところが、ターゲットパスなしのデフォルトではスクリプトを記述したMovieClipが参照されます。そのデフォルトタイムラインmy_mcの_parentというと、MovieClipの配置されたメインのタイムライン(_level0)になってしまうのです。

Buttonインスタンスの配置されているタイムラインを参照したければ、_parentプロパティのターゲットパスを明示的に指定しなければなりません。つまり、以下のように修正すればよいのです[*2]。

// MovieClip: アニメーション用
// フレームアクション
this.stop();
this.my_btn.onPress = function() {
  this._parent.play();   //ターゲットパスthisを指定
};

_parentプロパティのターゲットパスとして、thisを指定しました。thisは、イベントハンドラメソッドに定義したfunction内では、メソッドを設定したButtonインスタンスを参照しました。ターゲットパスが指定されたので、_parentプロパティはその上位のタイムライン、つまりButtonインスタンスmy_btnを包含するMovieClipのmy_mcを参照することになるのです。

[*2] 再生のためのステートメントからターゲットパスを完全に削除し、単にplay()としてもMovieClipのアニメーションは開始します 。ターゲットパスなしのデフォルトでは、スクリプトを記述したタイムライン、つまり再生対象となるMovieClipのmy_mcが参照されるからです。ただし、ターゲットパスを省略すると、play()はMovieClipのメソッドでなく独立のグローバル関数として解釈されることに注意が必要です(なお、MovieClipのメソッドと独立のグローバル関数で動作が異なる場合については、「gotoAndPlay/gotoAndStopでシーンの移動ができない」参照)。

_____

作成者: 野中文雄
更新日: 2004年11月21日 レイアウトと字句の一部修正および註釈[*1]の追加
更新日: 2004年2月29日 字句の一部修正
作成日: 2003年3月9日


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