【C#】【Form】PictureBox [8] ~ 画像比較スライダーをWindows Formで実装する ~

■ はじめに

https://blogs.yahoo.co.jp/dk521123/37846450.html
で、Windows Formで画像比較スライダーを実装したが
今回は、別解として、PictureBox 1つで画像比較スライダーを実装してみる。

■ サンプル

例1

using System;
using System.Drawing;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    private const int BorderWidth = 2;

    private int borderPosition = -1;
    private Bitmap srcImage = null;
    private Bitmap destinationImage = null;
    private Point mousePoint = Point.Empty;

    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      // 画像ファイルのImageオブジェクトを作成する
      this.srcImage = new Bitmap(@"C:\20161215052204.gif");
      //画像ファイルのImageオブジェクトを作成する
      this.destinationImage = new Bitmap(@"C:\20161215052204.png");

      this.borderPosition = srcImage.Width / 2;

      this.Draw(this.srcImage, this.destinationImage, this.borderPosition);
    }

    private void Form1_Resize(object sender, EventArgs e)
    {
      if (this.srcImage != null && this.destinationImage != null)
      {
        this.Draw(this.srcImage, this.destinationImage, this.borderPosition);
      }
    }

    private void Draw(Bitmap srcImage, Bitmap destinationImage, int borderPosition)
    {
      if (this.pictureBox1.Width <= 0 || this.pictureBox1.Height <= 0)
      {
        return;
      }

      if (this.pictureBox1.Image != null)
      {
        var oldImage = this.pictureBox1.Image;
        oldImage.Dispose();
        this.pictureBox1.Image = null;
      }

      var canvas = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height);

      // ImageオブジェクトのGraphicsオブジェクトを作成する
      using (var graphics = Graphics.FromImage(canvas))
      {
        // 画像を描画する
        graphics.DrawImage(srcImage, 0, 0);

        // 切り取る部分の範囲を決定
        var srcArea = new Rectangle(
           borderPosition, 0, destinationImage.Width - borderPosition, destinationImage.Height);
        // 描画する部分の範囲を決定
        var destinationArea = new Rectangle(borderPosition, 0, srcArea.Width, srcArea.Height);
        // 画像の一部を描画する
        graphics.DrawImage(destinationImage, destinationArea, srcArea, GraphicsUnit.Pixel);

        // 境界線描画
        var pen = new Pen(Color.Pink, 2);
        graphics.DrawRectangle
          (pen, borderPosition - (BorderWidth / 2), 0, BorderWidth, srcArea.Height);
      }

      // PictureBox1に表示する
      this.pictureBox1.Image = canvas;
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      if (this.srcImage == null ||
          this.destinationImage == null ||
          !e.Button.Equals(MouseButtons.Left))
      {
        return;
      }

      var mousePoint = e.Location;
      if (this.IsOnBorderArea(
            mousePoint, this.borderPosition, this.destinationImage.Height))
      {
        this.mousePoint = mousePoint;
      }
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
      if (this.srcImage == null || this.destinationImage == null)
      {
        return;
      }

      var mousePoint = e.Location;
      if (this.IsOnBorderArea(
            mousePoint, this.borderPosition, this.destinationImage.Height))
      {
        this.pictureBox1.Cursor = Cursors.VSplit;
      }
      else
      {
        this.pictureBox1.Cursor = Cursors.Default;
      }

      if (!this.mousePoint.IsEmpty)
      {
        this.borderPosition = mousePoint.X;
        this.Draw(this.srcImage, this.destinationImage, this.borderPosition);
        this.mousePoint = mousePoint;
        this.pictureBox1.Invalidate();
      }
    }

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

    private bool IsOnBorderArea(Point targetPoint, int borderPosition, int height)
    {
      var borderArea =
       new Rectangle(borderPosition - (BorderWidth / 2), 0, BorderWidth, height);
      return borderArea.Contains(targetPoint);
    }
  }
}

例2

全体表示した後に元に戻すと境界線を見失う時があるので、境界線の位置の保持を座標位置から座標位置の割合にする
using System;
using System.Drawing;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    private const int BorderWidth = 2;

    private double borderPositionRate = -1;
    private Bitmap srcImage = null;
    private Bitmap destinationImage = null;
    private Point mousePoint = Point.Empty;

    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      // 画像ファイルのImageオブジェクトを作成する
      this.srcImage = new Bitmap(@"C:\temp\20161215052204.gif");
      //画像ファイルのImageオブジェクトを作成する
      this.destinationImage = new Bitmap(@"C:\temp\20161215052204.png");

      this.borderPositionRate = 0.5;

      this.Draw(this.srcImage, this.destinationImage, this.borderPositionRate);
    }

    private void Form1_Resize(object sender, EventArgs e)
    {
      if (this.srcImage != null && this.destinationImage != null)
      {
        this.Draw(this.srcImage, this.destinationImage, this.borderPositionRate);
      }
    }

    private void Draw(Bitmap srcImage, Bitmap destinationImage, double borderPositionRate)
    {
      if (this.pictureBox1.Width <= 0 || this.pictureBox1.Height <= 0)
      {
        return;
      }

      if (this.pictureBox1.Image != null)
      {
        var oldImage = this.pictureBox1.Image;
        oldImage.Dispose();
        this.pictureBox1.Image = null;
      }

      var canvas = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height);

      // ImageオブジェクトのGraphicsオブジェクトを作成する
      using (var graphics = Graphics.FromImage(canvas))
      {
        // 画像を描画する
        graphics.DrawImage(srcImage, 0, 0);

        // 切り取る部分の範囲を決定
        int borderPosition = (int)Math.Round(
           this.pictureBox1.Width * borderPositionRate, MidpointRounding.AwayFromZero);
        var srcArea = new Rectangle(
           borderPosition, 0, destinationImage.Width - borderPosition, destinationImage.Height);
        // 描画する部分の範囲を決定
        var destinationArea = new Rectangle(borderPosition, 0, srcArea.Width, srcArea.Height);
        // 画像の一部を描画する
        graphics.DrawImage(destinationImage, destinationArea, srcArea, GraphicsUnit.Pixel);

        // 境界線描画
        var pen = new Pen(Color.Pink, 2);
        graphics.DrawRectangle
          (pen, borderPosition - (BorderWidth / 2), 0, BorderWidth, srcArea.Height);
      }

      // PictureBox1に表示する
      this.pictureBox1.Image = canvas;
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      if (this.srcImage == null ||
          this.destinationImage == null ||
          !e.Button.Equals(MouseButtons.Left))
      {
        return;
      }

      var mousePoint = e.Location;
      if (this.IsOnBorderArea(
            mousePoint, this.borderPositionRate, this.destinationImage.Height))
      {
        this.mousePoint = mousePoint;
      }
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
      if (this.srcImage == null || this.destinationImage == null)
      {
        return;
      }

      var mousePoint = e.Location;
      if (this.IsOnBorderArea(
            mousePoint, this.borderPositionRate, this.destinationImage.Height))
      {
        this.pictureBox1.Cursor = Cursors.VSplit;
      }
      else
      {
        this.pictureBox1.Cursor = Cursors.Default;
      }

      if (!this.mousePoint.IsEmpty)
      {
        var rate = mousePoint.X / (double)this.pictureBox1.Width;
        double minRate = BorderWidth / (double)this.pictureBox1.Width;
        double maxRate = (this.pictureBox1.Width - BorderWidth) / (double)this.pictureBox1.Width;
        if (rate >= minRate && rate < maxRate)
        {
          this.borderPositionRate = rate;
        }
        else if (rate >= maxRate)
        {
          this.borderPositionRate = maxRate;
        }
        else
        {
          this.borderPositionRate = minRate;
        }
        this.Draw(this.srcImage, this.destinationImage, this.borderPositionRate);
        this.mousePoint = mousePoint;
        this.pictureBox1.Invalidate();
      }
    }

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

    private bool IsOnBorderArea(Point targetPoint, double borderPositionRate, int height)
    {
      int borderPosition = (int)Math.Round(
        this.pictureBox1.Width * borderPositionRate, MidpointRounding.AwayFromZero);
      var borderArea =
       new Rectangle(borderPosition - (BorderWidth / 2), 0, BorderWidth, height);
      return borderArea.Contains(targetPoint);
    }
  }
}

■ 補足:ツールチップの実装

 * 上記のサンプルに、左側と右側で別のToolTip(ツールチップ)を表示するようには
   以下の関連記事を参照のこと。
Tooltip [2] ~ 1つのPictureBoxに複数のToolTipを表示するには... ~
https://blogs.yahoo.co.jp/dk521123/38052822.html


関連記事

Windows Form

Windows Form ~ 目次 ~
https://blogs.yahoo.co.jp/dk521123/8054245.html
Splitter ~ 画像比較スライダーをWindows Formで実装する ~
https://blogs.yahoo.co.jp/dk521123/37846450.html
Tooltip [2] ~ 1つのPictureBoxに複数のToolTipを表示するには... ~
https://blogs.yahoo.co.jp/dk521123/38052822.html