【C#】【Form】PictureBox [2] ~ PictureBox を マウスで移動する ~

■ はじめに

Windows Formで、以下の実装する。
仕様
[1] Panel内でマウス左をクリックし、Panel内のPictureBox をマウスで選択。その際、カーソルを変更。
[2] マウスを左クリックされている間は、そのPictureBox はPanel内を自由に移動する。
[3] マウスを左クリックを離すと、PictureBox の動きが止まり、カーソルもデフォルトに戻る。
[4] Panel外にPictureBox が出る場合、補正する。

別解:アフィン変換による実装

 * 以下の関連記事を参照。
https://blogs.yahoo.co.jp/dk521123/37866101.html

■ サンプル

ポイントは、pictureBoxの以下の3つのイベントを駆使して実装する
 1) MouseDownイベント ... 押されたポイントを覚えておく
 2) MouseMoveイベント ... 1)のポイントがあればドラッグ中なので移動。それ以外は無視。
 3) MouseUpイベント ... 1)のポイントをリセット

例1:AutoScrollPositionを利用する

 * 以下のサイトを参考。
http://codepanic.itigo.jp/cs/picturebox_scroll.html
 => AutoScrollPositionで、スクロールバーを利用する
コントロール構成
 + Panel (AutoScroll : True)
    + PictureBox (SizeMode : AutoSize ... PictureBoxコントロールのサイズを画像の実サイズにする)
コード
using System.Drawing;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    private Point startPoint = Point.Empty;

    public Form1()
    {
      InitializeComponent();
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      this.startPoint = e.Location;
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
      if (this.startPoint.IsEmpty)
      {
        return;
      }

      var movementPoint = new Point(e.Location.X - this.startPoint.X, e.Location.Y - this.startPoint.Y);
      this.panel1.AutoScrollPosition = new Point(
          -panel1.AutoScrollPosition.X - movementPoint.X,
          -panel1.AutoScrollPosition.Y - movementPoint.Y);
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
      this.startPoint = Point.Empty;
    }
  }
}

例2

 * 以下のサイトを参考。
https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/89b37ead-59d5-4cdc-b605-7486e6aae8f2/12500124631248112515125401250812483124631247312398312272120565?forum=csharpgeneralja
https://code.i-harness.com/ja/q/8b4d6
コントロール構成
 + Panel (Background : Black)
    + PictureBox
コード
using System.Drawing;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    // クリック時点の座標
    private Size startSize = Size.Empty;
    // ドラッグされているか
    public bool IsDragging
    {
      get
      {
        return this.startSize != Size.Empty;
      }
    }

    public Form1()
    {
      InitializeComponent();
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      var pictureBox = sender as PictureBox;
      if (pictureBox == null)
      {
        return;
      }

      if (e.Button != MouseButtons.Left)
      {
        return;
      }

      this.startSize = new Size(e.X, e.Y);
      this.Cursor = Cursors.Hand;
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
      var pictureBox = sender as PictureBox;
      if (pictureBox == null)
      {
        return;
      }

      if (e.Button != MouseButtons.Left || !this.IsDragging)
      {
        return;
      }

      // 画面座標をクライアント座標(コントロール上の座標)に変換する
      // https://dobon.net/vb/dotnet/control/pointtoclient.html
      // http://www.atmarkit.co.jp/fdotnet/dotnettips/377screentoclient/screentoclient.html
      Point currentPoint = this.panel1.PointToClient(Cursor.Position);

      // 画像を動かすポイントを算出
      //  Point.Subtract
      //   https://docs.microsoft.com/ja-jp/dotnet/api/system.drawing.point.subtract?view=netframework-4.7.2
      Point movingPoint = Point.Subtract(currentPoint, this.startSize);

      pictureBox.Location = this.CorrectPosition(movingPoint, pictureBox.Size, this.panel1);
    }

    private Point CorrectPosition(Point point, Size pictureBoxSize, Panel panel)
    {
      int x;
      if (point.X <= 0)
      {
        x = 0;
      }
      else if (point.X >= (panel.Width - pictureBoxSize.Width))
      {
        x = panel.Width - pictureBoxSize.Width;
      }
      else
      {
        x = point.X;
      }
      int y;
      if (point.Y <= 0)
      {
        y = 0;
      }
      else if (point.Y >= (panel.Height - pictureBoxSize.Height))
      {
        y = panel.Height - pictureBoxSize.Height;
      }
      else
      {
        y = point.Y;
      }
      return new Point(x, y);
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
      var pictureBox = sender as PictureBox;
      if (pictureBox == null)
      {
        return;
      }

      this.startSize = Size.Empty;
      this.Cursor = Cursors.Default;
    }
  }
}


関連記事

Windows Form

Windows Form ~ 目次 ~
https://blogs.yahoo.co.jp/dk521123/8054245.html
PictureBox [1] ~ 画像を表示する ~
https://blogs.yahoo.co.jp/dk521123/23504075.html
PictureBox [3] ~ マウスホイール で画像の拡大・縮小する ~
https://blogs.yahoo.co.jp/dk521123/37866101.html