2016年11月10日木曜日

C#のPanelでマウスドラッグのスクロールを行う

Panel panel1にPictureBox pictureBox1が乗っている。panel1はAutoScrollがtrueになっており、pictureBox1にはMouseDown, MouseUp, MouseMoveイベントが登録されている。

bool MouseScrollButtonIsDown = false;
Point MouseScrollButton_DownPos;
const MouseButtons MouseScrollButton = MouseButtons.Middle;

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseScrollButton)
    {
        MouseScrollButtonIsDown = true;
        MouseScrollButton_DownPos = pictureBox1.PointToClient(Cursor.Position);
    }
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == MouseScrollButton)
    {
        MouseScrollButtonIsDown = false;
    }
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (MouseScrollButtonIsDown)
    {
        Point currentPos = pictureBox1.PointToClient(Cursor.Position);

        panel1.AutoScrollPosition = new Point(
            -panel1.AutoScrollPosition.X + MouseScrollButton_DownPos.X - currentPos.X,
            -panel1.AutoScrollPosition.Y + MouseScrollButton_DownPos.Y - currentPos.Y
            );
    }
}

簡単に説明しておくと、まずpictureBox1の上でマウスを押下するとMouseDownイベントが呼ばれる。この際に指定したボタン(今回はスクロールホイール)かどうかを確認し、一致する場合は押下フラグがセットされる。この時、マウスが押下された位置を変数に保存する。また、ボタンを離すとMouseUpイベントが呼ばれ、フラグがクリアされる。
次にマウスが動いた場合、MouseMoveイベントが呼ばれる。この際に先程の押下フラグを確認し、押下されていない場合は処理を行わない。
スクロールをする場合、現在のカーソル位置と、押下されたときに保存したカーソル位置の差分を取り、その値を現在のスクロール位置に加算する。AutoScrollPositionはgetは負数で、setは正数で与える必要がある。

処理の内容を考えると、マウスが押下された位置と現在の位置の差分を加算しては加速度的にスクロールしてしまうのでは、と思ってしまう。しかしPanelの挙動からするとこの処理が正しい。

PanelのAutoScrollは、マウスホイールで上下移動は可能だが、縦スクロール専用のマウスでは横方向の移動ができない。ということで自前でスクロール処理を追加してやる必要がある。
この実装では若干GUIから予想した挙動と違う動作になるが、あまり大きな問題になるほどではない。

0 件のコメント:

コメントを投稿