C#でフリーハンドで線を引く2「ひとつ前に戻る機能をつける」

C#コンピュータ
C#

ペイントソフトなどにある「ひとつ前に戻る機能」がどの様なものか考え試作してみました。

namespace FreeHand2;

public class ImgObject : IDisposable
{
    public Bitmap Bitmap {get; set;} = new Bitmap(1,1);
    public Rectangle Rectangle {get; set;} = new Rectangle(0,0,1,1);
    public void Dispose()
    {
        Bitmap?.Dispose();
    }
}
public class MyCanvas : UserControl
{
    //  コンストラクタ
    public MyCanvas()
    {
        AutoScroll = true;// 自動スクロール
        bool isDrawing = false;
        Point lastMousePoint = new Point(-1, -1); // 前回マウスボタンを押した位置
        List<ImgObject> imgObjects = new(); // 画像オブジェクト

        // マウスボタン押すイベント
        _pictureBox.MouseDown += (s, e) =>
        {
            if (s == null) return;
            PictureBox o = (PictureBox)s;
            switch(e.Button)
            {
                case MouseButtons.Right:
                    // 右ボタン
                    int pos = imgObjects.Count - 1;
                    if (pos < 0) return;
                    imgObjects.RemoveAt(pos);
                    _pictureBox.Invalidate();
                    break;
                case MouseButtons.Left:
                    // 左ボタン
                    isDrawing = true;
                    lastMousePoint = e.Location;
                    Bitmap bmp = new(o.Image.Width, o.Image.Height);
                    using(var g = Graphics.FromImage(bmp))
                    {
                        g.Clear(Color.FromArgb(0,255,255,255));
                    }
                    ImgObject io = new()
                    {
                        Bitmap = bmp,
                        Rectangle = new Rectangle(0, 0, bmp.Width, bmp.Height),
                    };
                    imgObjects.Add(io);
                    break;
            }
        };
        // マウスボタン離すイベント
        _pictureBox.MouseUp += (s, e) =>
        {
            switch(e.Button)
            {
                case MouseButtons.Right:
                    // 右ボタン
                    break;
                case MouseButtons.Left:
                    // 左ボタン
                    isDrawing = false;
                    break;
            }
        };
        // マウス移動イベント
        _pictureBox.MouseMove += (s, e) =>
        {
            if (isDrawing == false) return;

            int pos = imgObjects.Count - 1;
            if (pos < 0) return;

            using(var g = Graphics.FromImage(imgObjects[pos].Bitmap))
            {
                g.DrawLine(Pens.Black, lastMousePoint, e.Location);                
            }
            lastMousePoint = e.Location;
            _pictureBox.Invalidate();
        };
        // ペイントイベント
        _pictureBox.Paint += (s, e) =>
        {
            var g = e.Graphics;

            g.Clear(Color.White);
            foreach(var io in imgObjects)
            {
                g.DrawImage(io.Bitmap, io.Rectangle);
            }
        };

        Controls.Add(_pictureBox);
    }
    PictureBox _pictureBox = new()
    {
        Image = new Bitmap(800, 600),
        SizeMode = PictureBoxSizeMode.AutoSize,
    };
}

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

        MyCanvas myCanvas = new()
        {
            Dock = DockStyle.Fill,
        };
        Controls.Add(myCanvas);
    }
}

マウスの右ボタンを押したまま移動すると線が引かれます。左ボタンを押すとひとつ前に戻ります。
プログラムの内容は1ストローク事透明な画像を用意し、そちらに線を描画しています。描画した画像をを配列にし、ピクチャボックスのペイントイベントで配列の要素をDrawImageで重ね合わせ処理をしています。相対位置やサイズを想定してRectangleプロパティ用意しましたが、今回は無用でした。

実際、ペイントソフトでどのような処理をしているかは不明ですが、描画の手順が配列化されていますので、直近追加した要素を削除すると、一つ前に戻る(undo)機能になります。
C#でフリーハンドで線を引く
線を引く機能とマウスの移動イベントを組み合わせると、ペイントソフトのフリーハンドで線を引く機能のようなものが作れるので試してみました。事前準備線を引くサンプルソースファイル名:drawline.csusing Sys...

コメント