- ベストアンサー
スライダをドラッグして変数を吐き出させる方法
- MacOSX FlashMX2004環境で、オリジナルのスクロールバーを製作し、ドラック位置によって変数を吐き出す仕組みを作りたい
- スライダを右にドラッグすると上にある別のMCが動き、pNumという変数にスライダが動かした分の数字を吐き出す
- スライダは左端から右端まで130pxのみ動かし、スライダを使わずに上にある別のMCと連動させたい
- みんなの回答 (1)
- 専門家の回答
質問者が選んだベストアンサー
いろいろな方法がありますが、割合(比でもできます)で考えていくと汎用的なスクロールバーも作れます。 スクロールバーはスライダがレールのようなもの(トラック)の中を移動するナビゲーションで、スライダ自身の大きさを考慮しなければなりません。 トラックの長さが 150 px、スライダが 20 px だとして、スライダのある1点、仮に左端としましてこれに注目しますと、左端が移動できる距離は自分自身の大きさを差し引いた 130 px です。 つまり、左端の座標を移動可能な距離 130 px で割ると、スライダがトラック内のどのあたりの割合にあたる位置にあるのかが分かります。 一般的なスクロールバーは 0 を基準に考えます。 とりあえず 0 を基点に考えると、スライダが左端にある時 0、右端にある時 150 を返すようなスクロールバーでは、値の範囲は 150 - 0 = 150 となります。 スライダが位置している場所が、この 150 の範囲の中ではどこに相当するのか、これを求められればいいわけです。 例えば、スライダの左端が 13 px の位置にある時、トラック内の移動可能領域 130 px のどのあたりの位置に相当するかというと、 13 ÷ 130 = 0.1 で、1割( 10 %)にあたる位置です。 返す値の範囲は 150 です。150 の1割に当たるのは 150 × 0.1 = 15 ですから、返す値は 15 ということになります。 式にしてみますと 返す値=スライダの位置÷スライダが移動可能な距離×値の範囲 となります。 ところで、スクロールバーは 0 から値を返したい時ばかりとは限りません。 例えば再生するフレームに直接対応させたい時などは、スライダが左端にある時には 1 や他の数字など 0 以外の数字を最小値として返してくれた方が便利です。 最小値が 0 でない時は基点がズレているだけの話なので、先の式に最小値を加算すると簡単に修正できます。 公式のように書くなら、 返す値=スライダの位置÷スライダが移動可能な距離×値の範囲+値の最小値 です。 **************************************** もう1つ、逆に指定された値からスライダの位置を求める方法を考えてみましょう。 同様に割合で考えます。 値の最小値が 0、最大値が 150 だとすると、範囲は 150 です。 今、15 の位置を指定したいとします。 これは 150 の範囲内では1割にあたります。 スクロールバーのトラックが 150 px でスライダは 20 px の大きさとすると、移動可能な距離は 130 px です。 指定された値が 15 で全体の1割という情報を表すためには、移動可能な距離である 130 px の1割にあたる位置にスライダを移動すればいいということです。 もし最小値が 0 でない時は、この分を修正して考えます。 例えば値が 100 ~ 500 の間で返す場合、値の範囲は 400 です。 この場合は、500 が指定された時は 10 割( 100 %)と計算できなければなりません。 これは指定の数から返す値の最小値を予め引いておいて、範囲で割ると修正できます。 つまり、式にすると スライダの位置=(指定の値-値の最小値)÷値の範囲×スライダが移動可能な距離 となります。 ------------------------------------------------------------------ どうせ設計するなら、いちいちスライダの位置や値を座標などから計算で求めなければならない不便なものではなく、これらを関数にして呼び出すだけにした方が保守も簡単です。 (更に言うならクラスにでもするのが理想的ですけれど、それなら最初からコンポーネントを利用した方が早いです) UIScrollBar コンポーネントほど高機能で堅牢ではありませんが、この設計を真似して少しだけ汎用的に作ってみましょう。 スクロールバーの位置を監視して、値が変わった時にイベントを起こして指定の関数を呼ぶ機能も付けちゃいます。 まずはムービークリップの作成から。 スクロールバーを作る時は基準点の位置が大切です。 横のスクロールバーは左端からスタートしますから、何事も左端を 0 として扱えるようにすると楽です。 スライダを基準点を左上にしたムービークリップで作ります。(左端でさえあれば上・中・下のどこでも構いませんが、ここでは左上に統一します) トラックも同様に、基準点を左上にしてムービークリップにします。 この2つを、新しいシンボル内の X = 0 ・ Y = 0 の位置に配置します。 すると、この2つのムービークリップの_x と _y には親の基準点を原点とする座標が入るので、ステージに置く時の座標に関係なく常に左端を 0 として考えられるようになります。 とりあえず親シンボルのシンボル名を”スクロールバーもどき”、子のインスタンス名を” sc_slider ”と” sc_track ”と付けたとします。 **************************************** スクリプトは次のように考えます。 本物のスクロールバーのコンポーネントには、setScrollProperties というメソッドがあります。 その引数は、1ページあたりの表示量(スライダの大きさに関係します)と、返す値の最小・最大値の3つです。 今回はスライダの大きさが変わる機能までは考えず、最小値と最大値だけを受け取る関数を1つ、用意します。 この関数で受け取った値を元に値の最小/最大値と範囲を決め、スライダの位置から値(スクロールポジション)を返す関数と、逆にスクロールポジションからスライダの位置を決める関数を作ります。 イベントは Object クラスが持っている watch というメソッドを使って作ります。 紙面の都合上詳しくは説明できませんが、端的に言いますと、ある変数やプロパティの値を監視し、値が変更されようとした時に登録しておいた関数(処理)を呼び出してくれるというものです。 watch に登録する関数の中に、”予め決めておいた名前の変数(イベントハンドラ)に登録されている関数があればそれを呼び出す”という処理を加えておきます。 これで、ある変数の値が変わった時に何か関数が定義されていれば呼び出されるという、いわゆるイベントハンドラ風の処理を実装できます。 **************************************** ムービークリップシンボル”スクロールバーもどき”の( 0 , 0 )の位置に、基準点を左上に設定したスライダ” sc_slider ”とトラック” sc_track ”が配置されているものとします。 スクロールバー自体の処理に関するスクリプトは全て、”スクロールバーもどき”のタイムラインに書きます。 (↓各行頭に全角のスペースが入っています。コピーする際はご注意ください) //ドラッグ可能領域を設定 drag_min = sc_track._x; drag_max = sc_track._width - sc_slider._width; //移動範囲を設定 move_range = drag_max - drag_min; //スクロールポジションの最小/最大値を保持 var data_min , data_max; //値の範囲を保持 var data_range; //スクロールバーの位置(返す値)を保持 var scroll_pos; ////////////////////////////////////////////////////////////////// //スクロールバーのセットアップ //引数 min:返す値の最小値 max:返す値の最大値 ///////////////////////////////////////////////////////////////// function ScrollBar_SetUp( min:Number , max:Number ) { //スクロールポジションの最小/最大値を設定 data_min = min; data_max = max; //値の範囲を設定 data_range = data_max - data_min; //スクロールバーの位置(返す値)を保持 //初期値は最小値 scroll_pos = data_min; } //////////////////////////////////////////////////////////////// //スライダの位置やスクロールポジションを算出する関数 ///////////////////////////////////////////////////////////////// /*スライダの位置からスクロールポジションを算出*/ function Set_ScrollPosition() { var ratio:Number; //移動可能範囲のどのあたりにスライダがあるのかを算出 ratio = sc_slider._x / move_range; //この割合を元に値を設定 scroll_pos = Math.floor( data_range * ratio ) + data_min; } /*スクロールポジションからスライダを移動*/ function Set_Slider( pos:Number ) { var ratio; //現在のスクロールポジションがスクロール範囲のどのあたりにあたるかを算出 ratio = ( pos - data_min ) / data_range; //この割合を元にスライダの位置を決める sc_slider._x = Math.floor( move_range * ratio ); } ///////////////////////////////////////////////////////////////// //スライダの移動処理とスクロールポジションの変更 ///////////////////////////////////////////////////////////////// //ドラッグ中かどうかを保持するフラグ //ドラッグ中true、それ以外はfalse drag_flg = false; sc_slider.onPress = function() { //移動可能範囲内でドラッグ可能にする this.startDrag( true , drag_min , this._y , drag_max , this._y ); drag_flg = true; }; sc_slider.onRelease = function() { //ドラッグを終了 this.stopDrag(); drag_flg = false; }; sc_slider.onReleaseOutside = function() { this.stopDrag(); drag_flg = false; }; this.onMouseMove = function() { //ドラッグ中のみ、スクロールポジションを変更 if( drag_flg ) { Set_ScrollPosition(); updateAfterEvent(); } }; ///////////////////////////////////////////////////////////////// //スクロールポジションを監視し、イベントハンドラを作る ///////////////////////////////////////////////////////////////// function ScrollPos_Checker( id , old_val , new_val ) { //スクロール範囲外の値が入らないように修正 if( new_val < data_min ) { new_val = data_min; } else if( new_val > data_max ) { new_val = data_max; } //イベントハンドラが定義されていたら実行 if( this.onSliderMove != undefined ) { this.onSliderMove(); } //スライダを移動 Set_Slider( new_val ); //指定された値で更新 return( new_val ); } //scroll_posを監視 this.watch( "scroll_pos" , ScrollPos_Checker ); **************************************** 主な関数は次の通りです。 ・ ScrollBar_SetUp 返す値の最小値と最大値を設定します。 スクロールバーを使う前に、必ず呼び出してください。 ・ Set_ScrollPosition ・ Set_Slider スライダの位置から返す値を決める関数と、スクロールポジションからスライダの位置を決める関数です。 内部で使用しますので、外からは呼び出す必要はありません。 ・ ScrollPos_Checker スクロールポジションを保持する変数” scroll_pos ”が変更される時、Object クラスの watch メソッドにより呼び出されます。 設定される値がスクロールポジションの取り得る範囲外の値(不正な値)にならないように監視することと、この値を元にスライダの新しい位置を決めることが主な役目です。 また、イベントハンドラ” onSliderMove ”に何か関数が定義されていれば、それを呼び出します。 ------------------------------------------------------------------ 実際に利用する方法は次のようになります。 ステージに”スクロールバーもどき”のインスタンスを配置し、インスタンス名を付けてください。 仮に、” sc_bar ”とします。 ”スクロールバーもどき”に組み込まれているスクリプトは少々複雑で、メインのタイムラインのフレームに書いたスクリプトよりもわずかに実行されるタイミングが遅れることがあります。 念のためスクロールバーを先に出し、制御用のスクリプトは次のフレームに書くと万全です。 動かすムービークリップは、基準点を左端に設定し、何かのムービークリップの入れ子にして左端を 0 として扱えるようにすると考えやすくなります。 (スライダやトラックを他のムービークリップの入れ子にして、左端を 0 として扱えるようにするのと、同じ発想です) 移動していない状態の座標が原点からズレている分を考慮すればどのような位置でも構いませんが、少し分かりにくいかもしれません。 ここではさしあたって、ムービークリップ” holder ”の中に実際に動かすムービークリップ” clip ”が入っており、clip の基準点は左上で最初は holder の基準点に左端がある(つまり、clip の _x の初期値は0)ものとして話を進めます。 例えば clip の幅が 500 px で、そのうちの 200 px をマスクを利用して表示し、見えない部分はスクロールさせて表示するものとします。 clip の右端 200 px の部分を見せてスクロールをストップさせるには、スクロールバーからは 0 ~ 300 の値を受け取り、これとは逆の方に clip を動かせばいいことになります。 ステージに、holder の入れ子にしたムービークリップ clip(基準点は左上、初期配置は holder の X = 0 の位置)と、スクロールバーもどきのインスタンス sc_bar が配置されているものとします。 sc_bar のスライダの位置に応じて clip を動かすスクリプトは、次のようになります。 このスクリプトは、ムービークリップを登場させた次のフレームに設定してください。 例えばムービークリップがフレーム1から登場するなら、フレーム2です。 //スクロールバーが返してくる値を設定 sc_bar.ScrollBar_SetUp( 0 , 300 ); //スライダが動いた時に呼ぶ関数を定義 sc_bar.onSliderMove = function() { //ムービークリップを逆の位置に動かす holder.clip._x = -sc_bar.scroll_pos; }; //タイムラインはここで止める stop(); sc_bar が持っている” scroll_pos ”という変数に、スクロールバーが返す値であるスクロールポジションが記録されています。 書き換えることで、スライダの位置を変化させることもできます。 例えば、押している間スライダを右に自動で動かし、画像をスクロールさせるボタンのスクリプトは onClipEvent(enterFrame) { //ボタンが押されている間、画像をスクロール if( press_flg ) { _root.sc_bar.scroll_pos += 10; } } このような感じになります。 ( press イベント発生時に変数 press_flg に true 、release イベント発生時に false を入れる処理を加えてください。紙面の都合上、省略させていただきました) scroll_pos の値は watch (で呼び出される ScrollPos_Checker 関数)により監視されていて、ScrollBar_SetUp 関数で指定した数値の範囲内の値にしかなりません。 また、scroll_pos の値を書き換えた時は、sc_bar.onSliderMove で定義された関数が自動で呼び出されます。 今回 onSliderMove イベントハンドラに定義した関数の内容は、” scroll_pos の値を見て、反対の方向に clip を動かす”というものです。 ですから、clip の座標と scroll_pos の値を予め対応させておくと scroll_pos を書き換えるだけで clip も動きますし、スライダも同時に該当する位置に移動します。 ちなみに、スクロールバーのコンポーネントの setScrollProperties は、最小値に0未満の数値を設定できないようになっています。 これは、本来はテキストフィールドに簡単にスクロールバーを付けられるようにとの目的で設計されたコンポーネントで、テキストフィールドの行は0未満にはならないことから来ていると思われます。 今回の”スクロールバーもどき”の ScrollBar_SetUp 関数は値のチェックや矯正を何も行っていないので、最小値は負の数など0未満も設定できます。 ただし、これはスライダが左端にある時に最小値が返されるということです。 いわゆる0を中心に左側が負、右側が正といったナビゲーションを作る時は、続けて scroll_pos に 0 を入れると、中央を基点としたスクロールバーにすることもできます。 その際は、scroll_pos の位置から対象の位置を決める処理にも多少工夫が必要です。 まあ・・・UIScrollBar コンポーネントに比べると粗も目立ちますけれど、とりあえずこんなところでいかがでしょう。 長くなってすみませんでした。 不明な点がありましたら、補足してください。