ホーム >> 左脳ActionScript3 >> アクションスクリプト3 >> TextFieldクラス >> マウスドラッグを可能にする
マウスドラッグを可能にする
スクロールボタンを、マウスでドラッグし表示領域を自由にコントロール出来る様にしましょう。

以下前回から変更のあったルーチン。「マウスボタン押下イベント」の監視をする指定が追加されました。

//  水平スクロールバー初期化
private function scrH_init():void 
{
    //  水平スクロールバー領域
    scrH    =   new Sprite();
    scrH.x  =   txt_input.x;
    scrH.y  =   txt_input.y +   txt_input.height;
    addChild(scrH);
    //  水平スクロールバーボタン
    scrHB   =   new Sprite();
    scrHB.x =   0;
    scrHB.y =   0;
    scrHB.visible   =   false;  //  スクロールバーボタンを見えない状態にする
    scrH.addChild(scrHB);
    //  マウスボタン押下(スクロールボタンのドラッグ開始)の監視
    scrHB.addEventListener(MouseEvent.MOUSE_DOWN, scrH_dragStart);
    //
    scrH_draw();
}

「マウスボタン押下イベント」監視に伴い、そのルーチンの記述が追加されました。

//  水平スクロールバーボタンのドラッグ開始
private function scrH_dragStart(e:MouseEvent):void 
{
    //  マウス移動ベント監視
    stage.addEventListener(MouseEvent.MOUSE_MOVE, scrH_darging);
    //  マウスボタンアップ(ドラッグ終了)イベント監視
    stage.addEventListener(MouseEvent.MOUSE_UP, scrH_dragEnd);
    //  マウス移動の始点を保存
    scrH_draging    =   scrH.mouseX;
}
//  ドラッグ用変数
private var scrH_draging:Number;
//  水平スクロールバーボタンのドラッグ移動
private function scrH_darging(e:MouseEvent):void 
{
    //  移動量算出
    var v:Number    =   scrH.mouseX -   scrH_draging;
    scrH_draging    =   scrH.mouseX;
    //  スクロールバーボタンの移動最大値
    var scrH_max:Number =   scrH.width  -   scrHB.width;
    //  新しいボタンの位置
    var newPos:Number   =   scrHB.x +   v;
    //  はみ出ないよう位置調整
    newPos  =   (newPos < 0) ?   0   :   newPos;
    newPos  =   (newPos > scrH_max)  ?   scrH_max    :   newPos;
    //  スクロールバーの位置を更新
    scrHB.x =   newPos;
    //  スクロールバーの位置から、テキスト表示位置を換算する
    var bar:Number  =   newPos  *   Number(txt_input.maxScrollH)    /   scrH_max;
    //  テキスト表示位置を更新
    txt_input.scrollH   =   bar;
}
//  水平スクロールバーボタンのドラッグ終了
private function scrH_dragEnd(w:MouseEvent):void 
{
    //  監視解除
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, scrH_darging);
    stage.removeEventListener(MouseEvent.MOUSE_UP, scrH_dragEnd);
}

Get Adobe Flash player
いかがでしょう?
スクロールバーのドラッグで、テキスト表示をスクロール出来る事が確認出来たでしょうか。

しかし・・・何かヘンです。ドラッグ自体はちゃんと動いていますが、ナニか変です。
何故か、左への移動と、右への移動に、差を感じませんか?
ゆっくりドラッグすると判りますが、どうも、「左へ移動し易い」という妙な傾向があるようです。


何故、このような事が起こるのでしょうか?

これは、テキストの表示位置を更新する箇所に問題があります。 実は「scrollHプロパティ、scrollVプロパティ」は、値が更新されるとイベントを起こします。 そのイベントは、Event.SCROLLイベント

ドラッグでテキスト表示位置が更新されると、Event.SCROLLイベントが発生。 そのまま、水平スクロールバーボタンの移動「scrH_move」が呼び出され、 更新された scrollHプロパティ に基づいた、スクロールバー位置の更新をしてしまうのです。

  1. スクロールバードラッグによる更新
    ↓ボタンの位置から、scrollHプロパティ を逆算。
  2. scrollHプロパティの更新
    Event.SCROLLイベント
  3. スクロールバー位置の更新

パラメータの算出という意味では、「数学的に一次変換を2回繰り返して戻しているだけ」なので、 問題ないように見えますが、「スクロールバーの位置」はNumber型と実数精度であるのに対し、 「scrollHプロパティ」はint型で整数精度である為、 ここで小数点以下が切り捨てられると言う桁落ちが発生してしまいます。

その為、座標の変換も等価でなくなってしまい、桁落ちで小数点が切り捨てられるという動作が、 左へ移動し易いと言う傾向に繋がっていたのです。



これを実証してみましょう。

以下、検証用のコード。青字の部分が検証用の小数点以下を補填するコードです。修正のあるルーチンのみ表示しています。

//  水平スクロールバーボタンの移動
private function scrH_move(e:Event):void 
{
    if (    txt_input.maxScrollH > 0    )
    {   //  水平のスクロール幅がゼロ以上の時、スクロールバーボタンが見えるようになる
        scrHB.visible   =   true;   //  スクロールバーボタンを見える状態にする
        //  スクロールバーボタンの移動最大値
        var scrH_max:Number =   scrH.width  -   scrHB.width;
        //  水平表示位置を取得する。最大値を上回る場合があるので、最大値以上になら無い様にする。
    //  var scrH_pos:Number =   (txt_input.scrollH > txt_input.maxScrollH)
    //                      ?   txt_input.maxScrollH : txt_input.scrollH;
        //  検証用:桁落ち分を補填する
        var scrH_pos:Number =   Number(txt_input.scrollH)   +   scrollH_pointUnder;
        scrH_pos    =   (scrH_pos > txt_input.maxScrollH)
                    ?   txt_input.maxScrollH : scrH_pos;

        //  今のテキスト表示位置をスクロールバーの位置に換算する
        var pos:Number  =   scrH_pos    *   scrH_max    /   txt_input.maxScrollH;
        //  スクロールバーボタンの位置を更新
        scrHB.x =   pos;
    }
    else
    {   //  水平のスクロール幅がゼロの時、スクロールバーボタンが見えなくなる
        scrHB.visible   =   false;  //  スクロールバーボタンを見えない状態にする
        /*  水平スクロール最大値がゼロなのに、表示位置がずれている場合があるので、
         *  画面内に戻す為に、強制的にゼロにする。この方が、自然な動作をする。 */
        txt_input.scrollH   =   0;
        //  検証用小数点以下数
        scrollH_pointUnder  =   0;
    }
}
//  水平スクロールバーボタンのドラッグ移動
private function scrH_darging(e:MouseEvent):void 
{
    //  移動量算出
    var v:Number    =   scrH.mouseX -   scrH_draging;
    scrH_draging    =   scrH.mouseX;
    //  スクロールバーボタンの移動最大値
    var scrH_max:Number =   scrH.width  -   scrHB.width;
    //  新しいボタンの位置
    var newPos:Number   =   scrHB.x +   v;
    //  はみ出ないよう位置調整
    newPos  =   (newPos < 0)    ?   0   :   newPos;
    newPos  =   (newPos > scrH_max) ?   scrH_max    :   newPos;
    //  スクロールバーの位置を更新
    scrHB.x =   newPos;
    //  スクロールバーの位置から、テキスト表示位置を換算する
    var bar:Number  =   newPos  *   Number(txt_input.maxScrollH)    /   scrH_max;
    //  テキスト表示位置を更新
    txt_input.scrollH   =   bar;
    //  検証用小数点以下数
    scrollH_pointUnder  =   bar -   Number(txt_input.scrollH);
}

//  検証用小数点以下数
private var scrollH_pointUnder:Number   =   0;

Get Adobe Flash player
いかがでしょう?
今度は、ゆっくりドラッグしても左右の差は感じ取れません。動きに関しては、相当改善したと言えます。


今回は、デフォルトで提供されているクラスのプロパティがint型で作られている為、 仕方ないながらもパッチ充ての如く小数点を補完する方式で改善をしました。

一見「ちゃんと動いているのだけれど、何か変」という場合、 このような桁落ちによるデータの精度落ちが関わってくる事があります。


今回、そもそも、

  1. スクロールバードラッグによる更新
    ↓ボタンの位置から、scrollHプロパティ を逆算。
  2. scrollHプロパティの更新
    Event.SCROLLイベント
  3. スクロールバー位置の更新

というシーケンスにおける、最後の「スクロールバー位置の更新」は無駄な手間なので、コレを省ければ小数点補完のパッチは要らなくなります。
ドラッグ処理の間だけ、Event.SCROLLイベントが起こらないようにすれば、解決できそうです。


以下、修正コード。検証用の修正を戻した状態から変更のあるルーチンのみ表示しています。

//  水平スクロールバーボタンのドラッグ開始
private function scrH_dragStart(e:MouseEvent):void 
{
    //  Event.SCROLLイベント監視解除
    txt_input.removeEventListener(Event.SCROLL, scrH_move);
    //  マウス移動ベント監視
    stage.addEventListener(MouseEvent.MOUSE_MOVE, scrH_darging);
    //  マウスボタンアップ(ドラッグ終了)イベント監視
    stage.addEventListener(MouseEvent.MOUSE_UP, scrH_dragEnd);
    //  マウス移動の始点を保存
    scrH_draging    =   scrH.mouseX;
}
//  水平スクロールバーボタンのドラッグ終了
private function scrH_dragEnd(w:MouseEvent):void 
{
    //  監視解除
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, scrH_darging);
    stage.removeEventListener(MouseEvent.MOUSE_UP, scrH_dragEnd);
    //  TextFieldからのEvent.SCROLLイベントで、スクロールバーの移動をする。
    txt_input.addEventListener(Event.SCROLL, scrH_move);
}

Get Adobe Flash player



イベントを抑制するだけでも、十分な動作をしています。

修正方法としては、「小数点補完」より簡単で、エレガントですね。



>> 垂直スクロールバーも追加してみる

トラックバック(0)

トラックバックURL: http://n-yagi.0r2.net/sanoupulurun/mt-tb.cgi/200

コメントする

ホーム >> 左脳ActionScript3 >> アクションスクリプト3 >> TextFieldクラス >> マウスドラッグを可能にする