【C#】【Form】PictureBox [4] ~ PictureBox 内に文字列を描画する ~

■ はじめに

 * 以下について、考える

【1】 PictureBox 内に文字列を描画する
  【1-1】マウスクリックで文字列を描画
  【1-2】マウスクリックで文字列を描画(文字列を残す)
【2】 PictureBox 内に文字列をマウスで動かす
  【2-1】実装案1:GraphicsPath.AddString() を使う
  【2-2】Label を使う
  【2-3】DrawString()とInvalidate()を使う(【1-1】の発展版)

【1】 PictureBox 内に文字列を描画する

 * 実装方法として、DrawString() を使う

【1-1】マウスクリックで文字列を描画

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

namespace SampleForm
{
  public partial class Form2 : Form
  {
    private Point targetPoint;

    public Form2()
    {
      InitializeComponent();

      this.targetPoint = Point.Empty;
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      if (!MouseButtons.Left.Equals(e.Button))
      {
        return;
      }

      this.targetPoint = e.Location;

      var pictureBox = sender as PictureBox;
      pictureBox.Invalidate();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
      if (this.targetPoint.IsEmpty)
      {
        return;
      }

      var pictureBox = sender as PictureBox;
      e.Graphics.DrawString("Hello World!", this.Font, Brushes.Black, this.targetPoint.X, this.targetPoint.Y);
    }
  }
}

【1-2】マウスクリックで文字列を描画(文字列を残す)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    private List<Point> targetPoints = new List<Point>();

    public Form1()
    {
      InitializeComponent();
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      if (e.Button != MouseButtons.Left)
      {
        return;
      }

      var pictureBox = sender as PictureBox;
      this.PaintText(pictureBox, e.Location, "これはテストです");
      targetPoints.Add(e.Location);
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
      var pictureBox = sender as PictureBox;
      foreach (var targetPoint in this.targetPoints)
      {
        this.PaintText(pictureBox, targetPoint, "これはテストです");
      }
    }

    private void PaintText(PictureBox pictureBox, Point targetPoint, String targetText)
    {
      using (var font = new Font("メイリオ", 10))
      using (var graphics = pictureBox.CreateGraphics())
      {
        graphics.DrawString(targetText, font, Brushes.Blue, targetPoint);
      }
    }
  }
}

【2】 PictureBox 内に文字列をマウスで動かす

【2-1】GraphicsPath.AddString() を使う

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

namespace SampleForm
{
  public partial class Form1 : Form
  {
    private GraphicsPath graphicsPath = new GraphicsPath();
    private Point downPoint;
    private float dx;
    private float dy;
    private bool isDragging;

    public Form1()
    {
      InitializeComponent();

      this.graphicsPath.AddString("これはテストです", Font.FontFamily,
            (int)Font.Style, 10, new Point(10, 10), StringFormat.GenericDefault);
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      if (e.Button != MouseButtons.Left)
      {
        return;
      }
      this.downPoint = e.Location;
      if (this.graphicsPath.GetBounds(new Matrix(1, 0, 0, 1, this.dx, this.dy)).Contains(e.Location))
      {
        this.graphicsPath.Transform(new Matrix(1, 0, 0, 1, this.dx, this.dy));
        this.isDragging = true;
      }
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
      if (e.Button != MouseButtons.Left)
      {
        return;
      }

      if (this.isDragging)
      {
        this.dx = e.X - this.downPoint.X;
        this.dy = e.Y - this.downPoint.Y;
        pictureBox1.Invalidate();
      }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
      this.isDragging = false;
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
      e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
      this.graphicsPath.Transform(new Matrix(1, 0, 0, 1, this.dx, this.dy));
      e.Graphics.FillPath(Brushes.Red, this.graphicsPath);
      this.graphicsPath.Transform(new Matrix(1, 0, 0, 1, -dx, -dy));

    }

    private void button1_Click(object sender, EventArgs e)
    {
      // 文字を消す
      this.graphicsPath.Reset();
      this.pictureBox1.Refresh();
    }
  }
}

【2-2】Label を使う

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

namespace SampleForm
{
  public partial class Form1 : Form
  {
    private Point labelDownPoint;

    public Form1()
    {
      InitializeComponent();

      this.label1.BackColor = Color.Transparent;
      this.label1.Parent = this.pictureBox1;
    }

    private void button1_Click(object sender, EventArgs e)
    {
      this.label1.Visible = false;
    }

    private void label1_MouseDown(object sender, MouseEventArgs e)
    {
      if (e.Button == MouseButtons.Left)
      {
        this.labelDownPoint = e.Location;
      }
    }

    private void label1_MouseMove(object sender, MouseEventArgs e)
    {
      if (e.Button == MouseButtons.Left)
      {
        this.label1.Left += e.X - this.labelDownPoint.X;
        this.label1.Top += e.Y - this.labelDownPoint.Y;
      }
    }
  }
}

【2-3】DrawString()とInvalidate()を使う(【1-1】の発展版)

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

namespace SampleForm
{
  public partial class Form2 : Form
  {
    private Point targetPoint;
    private bool isDragging = false;
    private SizeF textSize;
    private int? dx;
    private int? dy;

    public Form2()
    {
      InitializeComponent();


      this.targetPoint = Point.Empty;
      this.isDragging = false;
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
      if (!MouseButtons.Left.Equals(e.Button))
      {
        return;
      }

      var mouseDownPoint = e.Location;
      this.isDragging = true;
      if (this.targetPoint.IsEmpty ||
        !this.IsOnTextArea(mouseDownPoint, this.targetPoint, this.textSize))
      {
        this.targetPoint = mouseDownPoint;
      }
      else
      {
        this.dx = this.targetPoint.X - mouseDownPoint.X;
        this.dy = this.targetPoint.Y - mouseDownPoint.Y;

        var x = mouseDownPoint.X + this.dx.Value;
        var y = mouseDownPoint.Y + this.dy.Value;
        this.targetPoint = new Point(x, y);
      }

      var pictureBox = sender as PictureBox;
      pictureBox.Invalidate();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
      if (this.targetPoint.IsEmpty)
      {
        return;
      }

      var pictureBox = sender as PictureBox;

      var text = "Hello World!";
      e.Graphics.DrawString(text, this.Font, Brushes.Black, this.targetPoint.X, this.targetPoint.Y);
      this.textSize = e.Graphics.MeasureString(text, this.Font);
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
      this.isDragging = false;
      this.dx = null;
      this.dy = null;
    }

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

      var pictureBox = sender as PictureBox;
      var mousePoint = e.Location;
      bool isOnTextArea = this.IsOnTextArea(mousePoint, this.targetPoint, this.textSize);
      if (isOnTextArea)
      {
        pictureBox.Cursor = Cursors.SizeAll;
      }
      else
      {
        pictureBox.Cursor = Cursors.Default;
      }

      if (!this.isDragging)
      {
        return;
      }

      if (this.dx == null || this.dy == null)
      {
        this.targetPoint = mousePoint;
      }
      else
      {
        var x = mousePoint.X + this.dx.Value;
        var y = mousePoint.Y + this.dy.Value;
        this.targetPoint = new Point(x, y);
      }
      pictureBox.Invalidate();
    }

    private bool IsOnTextArea(Point targetPoint, Point textPoint, SizeF textSize)
    {
      const int Margin = 5;
      var point = new Point(textPoint.X - Margin, textPoint.Y - Margin);
      var textArea = new Rectangle(point, textSize.ToSize());
      return textArea.Contains(targetPoint);
    }
  }
}

参考文献

【1】 PictureBox 内に文字列を描画する

【1-1】マウスクリックで文字列を描画
http://www.vbforums.com/showthread.php?461407-How-to-quot-move-quot-text-on-a-PictureBox

【2】 PictureBox 内に文字列をマウスで動かす

https://stackoverflow.com/questions/20312831/drag-string-on-picturebox-c-sharp

関連記事

Windows Form ~ 目次 ~

https://blogs.yahoo.co.jp/dk521123/8054245.html

Graphics ~ さまざまな描画 ~

https://blogs.yahoo.co.jp/dk521123/32877749.html

図形 ~ 矩形 / Rectangle ~

https://blogs.yahoo.co.jp/dk521123/37888274.html

PictureBox

PictureBox [1] ~ 画像を表示する ~
https://blogs.yahoo.co.jp/dk521123/23504075.html
PictureBox [2] ~ PictureBox を マウスで移動する ~
https://blogs.yahoo.co.jp/dk521123/37861699.html
PictureBox [3] ~ マウスホイール で画像の拡大・縮小する ~
https://blogs.yahoo.co.jp/dk521123/37866101.html
PictureBox [5] ~ PictureBox 内に画像を描画する ~
https://blogs.yahoo.co.jp/dk521123/37890873.html