やりたいこと

お絵かきアプリを作りたい。Graphics.DrawRectangleを使って画像に四角形を描きたいが、そのまま画像に描写すると動きのあるアニメーションを入れた時もとに戻すことができない。

なので、オーバーレイ用の透明なPictureBoxを用意し入力が確定されるまでそこに図形を書き入れることにした。

実装

写真などを表示する層をpictureBox1とし、その上にpicturebox2を重ねて図形を描く。

PictureBox を2つ適当に配置する。

Form1.cs に以下を記述する

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

namespace WindowsFormsApp2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //重ねて表示するために両方の位置を(0,0)に設定
            pictureBox1.Location = new Point(0, 0);
            pictureBox2.Location = new Point(0, 0);

            //大きさを(500,500)に設定
            pictureBox1.ClientSize = new Size(500, 500);
            pictureBox2.ClientSize = new Size(500, 500);

            //pictureBox2の親要素をpictureBox1に設定する
            pictureBox2.Parent = pictureBox1;

            //pictureBox1に色を塗る(わかりやすくするため)
            pictureBox1.BackColor = Color.DeepSkyBlue;

            //pictureBox2を透過させる
            pictureBox2.BackColor = Color.Transparent;

            myDraw();
        }

        private void myDraw()
        {
            Bitmap overlay = new Bitmap(500, 500);
            Graphics graphics = Graphics.FromImage(overlay);

            //透明色で塗りつぶす
            graphics.Clear(Color.Transparent);

            //四角形の描写
            SolidBrush blueBrush = new SolidBrush(Color.Blue);
            graphics.FillRectangle(blueBrush, 50, 50, 70, 70);

            //graphicsの開放
            graphics.Dispose();

            pictureBox2.Image = overlay;
        }
    }
}

解説

Graphicsとbitmapについて

Graphicsは、直接PictureBoxに図形や線を書き入れることはできない。

なのでoverlayというbitmap画像にGraphicsで図形を書き入れ、それをPictureBox.Imageに設定するという少しややこしいことをする。

mydraw()では、500x500のBitmapの作成と作図、pictureBox.Imageへの挿入を行っている。

透過について

pictureBox1を背景画像として表示させるためには、pictureBox2とoverlay両方の透過が必要になる。

Color.Transparentは透明色を表す色の一種。

pictureBox2.BackColor = Color.Transparent;
graphics.Clear(Color.Transparent);

overlayの再描写

クリックした場所に四角形を動かしてみる。

まずは、pictureBox2を選択しカミナリアイコンを押した後、Clickのアクションをダブルクリック。

ユーザーがクリックしたときに呼ばれるPictureBox2_MouseClickという関数が作成されているはず。

以下のように書き換える。

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

namespace WindowsFormsApp2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //重ねて表示するために両方の位置を(0,0)に設定
            pictureBox1.Location = new Point(0, 0);
            pictureBox2.Location = new Point(0, 0);

            //大きさを(500,500)に設定
            pictureBox1.ClientSize = new Size(500, 500);
            pictureBox2.ClientSize = new Size(500, 500);

            //pictureBox2の親要素をpictureBox1に設定する
            pictureBox2.Parent = pictureBox1;

            //pictureBox1に色を塗る(わかりやすくするため)
            pictureBox1.BackColor = Color.DeepSkyBlue;

            //pictureBox2を透過させる
            pictureBox2.BackColor = Color.Transparent;
        }
        Bitmap overlay = new Bitmap(500, 500);
        private void pictureBox2_MouseClick(object sender, MouseEventArgs e)
        {
            Graphics graphics = Graphics.FromImage(overlay);

            //透明色で塗りつぶす
            graphics.Clear(Color.Transparent);

            //四角形の描写
            SolidBrush blueBrush = new SolidBrush(Color.Blue);
            graphics.FillRectangle(blueBrush, e.X, e.Y, 70, 70);

            //graphicsの開放
            graphics.Dispose();

            pictureBox2.Image = overlay;
        }
    }
}

背景がサイズの大きい画像の場合でも再描写が発生しないので高速だし、メモリの節約にもなる。

githubソース
https://github.com/kajikentaro/Overlay-PictureBox-Demo