WinFormsでアイコンエディタを作る5。「新規作成」

コンピュータ

プロジェクトの作成

mkdir IconE
cd IconE
dotnet new winforms
code .

ソース

ファイル名:Form1.cs

namespace IconE;

public partial class Form1 : Form
{
    const int MENUBAR_HEIGHT = 48;
    const int ROW_MAX = 32;
    const int COLUMN_MAX = 32;
    const int CELL_WIDTH = 16;
    const int CELL_HEIGHT = 16;
    const int CELL_MARGIN = 2;
    bool _mouseDownFlag = false;
    bool _eraseFlag = false;
    Color _currentColor = Color.Blue;
    Bitmap _currentBmp = new Bitmap(ROW_MAX, COLUMN_MAX);
    PictureBox[,] picBoxs = new PictureBox[ROW_MAX, COLUMN_MAX];
    PictureBox pictureBoxPreview = new PictureBox();

    string _iconFile = "";

    public Form1()
    {
        InitializeComponent();

        this.Load += Form1_Load;
        this.MouseDown += Form1_MouseDown;
        this.MouseUp += Form1_MouseUp;
    }
    void Form1_Load(object? sender, EventArgs e)
    {
        this.SuspendLayout();

        this.Size = new Size(1280, 720);

        for(int i = 0; i < ROW_MAX; i++)
        {
            for(int j = 0; j < COLUMN_MAX; j++)
            {
                picBoxs[i, j] = new PictureBox
                {
                    Name = String.Format("PICS_{0}_{1}", i, j),
                    Size = new Size(CELL_WIDTH, CELL_HEIGHT),
                    Location = new Point
                    (
                        CELL_WIDTH+(CELL_MARGIN+CELL_WIDTH)*i,
                        MENUBAR_HEIGHT+CELL_HEIGHT+(CELL_MARGIN+CELL_HEIGHT)*j
                    ),
                    BorderStyle = BorderStyle.FixedSingle,
                    BackColor = Color.Empty,
                };
                picBoxs[i, j].MouseUp += Form1_MouseUp;
                picBoxs[i, j].MouseDown += Form1_MouseDown;
                picBoxs[i, j].MouseMove += PicBoxs_MouseMove;
                picBoxs[i, j].BackColorChanged += PicBoxs_BackColorChanged;
                this.Controls.Add(picBoxs[i, j]);
            }
        }
        var groupBox1 = new GroupBox
        {
            Name = "GROUP_BOX_1",
            Size = new Size(140, 140),
            Location = new Point(
                CELL_WIDTH*2+(CELL_MARGIN+CELL_WIDTH)*COLUMN_MAX,
                MENUBAR_HEIGHT+CELL_HEIGHT
            ),
            Text = "モード",
        };
        var radioButtonErase = new RadioButton
        {
            Name = "RADIO_BUTTON_ERASE",
            Size = new Size(120, 60),
            Location = new Point(
                CELL_WIDTH,
                CELL_HEIGHT
            ),
            Text = "消去",
        };
        var radioButtonDraw = new RadioButton
        {
            Name = "RADIO_BUTTON_DRAW",
            Size = new Size(120, 60),
            Location = new Point(
                CELL_WIDTH ,
                CELL_HEIGHT + radioButtonErase.Height
            ),
            Text = "描画",
            Checked = true,
        };
        groupBox1.Controls.Add(radioButtonErase);
        groupBox1.Controls.Add(radioButtonDraw);
        this.Controls.Add(groupBox1);
        radioButtonErase.CheckedChanged += RadioButtonErase_CheckedChanged;

        var buttonColorEdit = new Button
        {
            Name = "BUTTON_COLOR_EDIT",
            Size = new Size(120, 60),
            Location = new Point(
                CELL_WIDTH*3+(CELL_MARGIN+CELL_WIDTH)*COLUMN_MAX+groupBox1.Width ,
                MENUBAR_HEIGHT+CELL_HEIGHT
            ),
            Text = "色選択",
        };
        this.Controls.Add(buttonColorEdit);

        var pictureBoxCurrent = new PictureBox
        {
            Name = "PICTUREBOX_CURRENT",
            Size = new Size(120, 60),
            Location = new Point(
                CELL_WIDTH*3+(CELL_MARGIN+CELL_WIDTH)*COLUMN_MAX+groupBox1.Width ,
                MENUBAR_HEIGHT+CELL_HEIGHT*2+buttonColorEdit.Height
            ),
            BackColor = Color.Blue,
            BorderStyle = BorderStyle.Fixed3D,
        };
        this.Controls.Add(pictureBoxCurrent);

        buttonColorEdit.Click += (o, e) =>
        {
            var colorDialog = new ColorDialog();
            colorDialog.Color = _currentColor;
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {
                _currentColor = colorDialog.Color;
                pictureBoxCurrent.BackColor = _currentColor;
            }
        };

        var label1 = new Label
        {
            Size = new(120, 60),
            Location = new Point(
                CELL_WIDTH*3+(CELL_MARGIN+CELL_WIDTH)*COLUMN_MAX+groupBox1.Width ,
                MENUBAR_HEIGHT+CELL_HEIGHT*2+pictureBoxCurrent.Location.Y + pictureBoxCurrent.Height
            ),
            Text = "プレビュー",
        };
        this.Controls.Add(label1);
        

        if (pictureBoxPreview != null) pictureBoxPreview.Dispose();
        pictureBoxPreview = new PictureBox
        {
            Size = new(ROW_MAX, COLUMN_MAX),
            Location = new Point(
                label1.Location.X,
                label1.Location.Y + label1.Height
            ),
            BorderStyle = BorderStyle.FixedSingle,
        };
        this.Controls.Add(pictureBoxPreview);
        pictureBoxPreview.Image = _currentBmp;

        // メニューバーの初期化
        var menubar = new MenuStrip{ Height = MENUBAR_HEIGHT, };
        var menuFile = new ToolStripMenuItem  { Text = "ファイル(&F)", };            
        menubar.Items.Add(menuFile);

        var menuOpen = new ToolStripMenuItem { Text = "開く", };
        menuOpen.ShortcutKeys = Keys.Control | Keys.O;
        menuOpen.ShowShortcutKeys = true;
        menuOpen.Click += (s, e) =>
        {
            var dialog = new OpenFileDialog
            {
                Filter = "ICOファイル(*.ico)|*.ico|すべてのファイル(*.*)|*.*",
                FilterIndex = 1,
                RestoreDirectory = true,
                CheckFileExists = true,
                CheckPathExists = true,
            };
            if (dialog.ShowDialog() != DialogResult.OK) return;

            _iconFile = dialog.FileName;

            using(var bmp = new Bitmap(_iconFile))
            {
                for (int y = 0; y < ROW_MAX; y++)
                {
                    for (int x = 0; x < COLUMN_MAX; x++)
                    {
                        var color = bmp.GetPixel(x, y);

                        if (color.A == 0)
                        {
                            picBoxs[x, y].BackColor = color;
                            picBoxs[x, y].BorderStyle = BorderStyle.FixedSingle;
                        }
                        else
                        {
                            picBoxs[x, y].BackColor = color;
                            picBoxs[x, y].BorderStyle = BorderStyle.None;
                        }
                    }
                }
            }
        };
        menuFile.DropDownItems.Add(menuOpen);

        var menuNew = new ToolStripMenuItem { Text = "新規作成" };
        menuNew.ShortcutKeys = Keys.Control | Keys.N;
        menuNew.ShowShortcutKeys = true;
        menuNew.Click += (s, e) =>
        {
            _iconFile = "";
            for (int y = 0; y < ROW_MAX; y++)
            {
                for (int x = 0; x < COLUMN_MAX; x++)
                {
                    picBoxs[x, y].BackColor = Color.Empty;
                    picBoxs[x, y].BorderStyle = BorderStyle.FixedSingle;
                }
            }
        };
        menuFile.DropDownItems.Add(menuNew);

        var menuSave = new ToolStripMenuItem { Text = "保存", };
        menuSave.ShortcutKeys = Keys.Control | Keys.S;
        menuSave.ShowShortcutKeys = true;
        menuSave.Click += (s, e) =>
        {
            var dialog = new SaveFileDialog
            {
                Filter = "ICOファイル(*.ico)|*.ico|すべてのファイル(*.*)|*.*",
                FilterIndex = 1,
                RestoreDirectory = true,
                CheckFileExists = false,
                CheckPathExists = true,
            };
            if (_iconFile != "" && System.IO.File.Exists(_iconFile))
            {
                dialog.InitialDirectory = System.IO.Path.GetDirectoryName(_iconFile);
                dialog.FileName = System.IO.Path.GetFileName(_iconFile);
            }

            if (dialog.ShowDialog() != DialogResult.OK) return;

            _iconFile = dialog.FileName;

            var bmp = (Bitmap)pictureBoxPreview.Image;
            using (var icon = System.Drawing.Icon.FromHandle(bmp.GetHicon()))
            using (var fs = new System.IO.FileStream(_iconFile, System.IO.FileMode.Create, System.IO.FileAccess.Write))
            {
                icon.Save(fs);
            }
        };
        menuFile.DropDownItems.Add(menuSave);

        this.Controls.Add(menubar);

        this.ResumeLayout();

    } // Form1_Load

    void Form1_MouseDown(object? sender, MouseEventArgs e)
    {
        _mouseDownFlag = true;

        PicBoxs_MouseMove(sender, e);
    }
    void Form1_MouseUp(object? sender, MouseEventArgs e)
    {
        _mouseDownFlag = false;
    }
    void PicBoxs_MouseMove(object? sender, MouseEventArgs e)
    {
        if (sender == null || _mouseDownFlag == false) return;

        var c = sender as PictureBox;
        if (c == null) return;

        if (_eraseFlag == true)
        {
            c.BackColor = Color.Empty;
            c.BorderStyle = BorderStyle.FixedSingle;
        }
        else
        {
            c.BorderStyle = BorderStyle.FixedSingle;
            c.BackColor = _currentColor;
            c.BorderStyle = BorderStyle.None;
        }
    }
    void RadioButtonErase_CheckedChanged(object? sender, EventArgs e)
    {
        if (sender == null) return;
        var radioButton = sender as RadioButton;
        if (radioButton == null) return;

        _eraseFlag = radioButton.Checked;
    }
    void PicBoxs_BackColorChanged(object? sender, EventArgs e)
    {
        var bmp = new Bitmap(COLUMN_MAX, ROW_MAX);
        for (int y = 0; y < ROW_MAX; y++)
        {
            for (int x = 0; x < COLUMN_MAX; x++)
            {
                if (picBoxs[x, y].BorderStyle == BorderStyle.None)
                {
                    bmp.SetPixel(x, y, picBoxs[x, y].BackColor);

                }
                else
                {
                    bmp.SetPixel(x, y, Color.FromArgb(0, 0, 0, 0));
                }
            }
        }
        if (pictureBoxPreview.Image != null) pictureBoxPreview.Image.Dispose();
        pictureBoxPreview.Image = bmp;
    }
}

実行

dotnet run

現在の機能

  • 32×32のセル(PictureBox)上でマウスボタンを押すとするとセルが青色に変化する。
  • マウスボタンを押した状態でマウスを移動すると、移動先のセルが青色に変化します。
  • セルの色を消去する機能
  • セルに描画する色を選択する機能
  • アイコン画像のプレビュー機能
  • アイコン形式で保存する機能
  • アイコンファイルを読み込む機能
  • メニューに新規作成を追加

コメント