自作アイコンエディタ
では長方形、直線、楕円、文字の挿入ができるようになりました。しかし長方形を書くときにエディタ上をドラッグしてもどこに長方形が作られるのかがわかりません。ドラッグしているときに図形が描画される部分がわかるようになると便利です。そこで範囲選択ができるようにしました。
まずラジオボタンで[範囲選択]の項目を追加しました。そのため、以下のメソッドが変更になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public partial class Form1 : Form { public CheckedRadioButton GetCheckedRadioButton() { if(radioButtonFree.Checked) return CheckedRadioButton.Free; else if(radioButtonRectangle.Checked) return CheckedRadioButton.Rectangle; else if(radioButtonLine.Checked) return CheckedRadioButton.Line; else if(radioButtonEllipse.Checked) return CheckedRadioButton.Ellipse; else if(radioButtonSelection.Checked) // 追加 return CheckedRadioButton.Selection; else return CheckedRadioButton.Free; } public enum CheckedRadioButton { Free = 0, Rectangle = 1, Line =2, Ellipse = 3, Selection = 4, // 追加 } } |
また選択されていることがわかるようにパネルの色を変えるので、もとの色がわかるようにXYクラスにフィールド変数を追加しています。
1 2 3 4 5 6 7 8 9 10 11 |
public class XY { public XY(int x, int y) { X = x; Y = y; } public Color oldColor = Color.Empty; // 追加 public int X = 0; public int Y = 0; } |
PanelExクラスには、範囲選択に対応するためのイベントを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
public class PanelEx : Panel { public event XYHandler BeginSelection; public event XYHandler EndSelection; public event XYHandler DragOverPanel; public PanelEx(int column, int row) { Column = column; Row = row; this.MouseDown += PanelEx_MouseDown; this.DragOver += PanelEx_DragOver; this.DragDrop += PanelEx_DragDrop; this.GiveFeedback += PanelEx_GiveFeedback; this.AllowDrop = true; } private void PanelEx_MouseDown(object sender, MouseEventArgs e) { Form1 f = (Form1)FindForm(); if(f.GetCheckedRadioButton() != Form1.CheckedRadioButton.Selection) if(f.GetCheckedRadioButton() == Form1.CheckedRadioButton.Free) if(f.GetCheckedRadioButton() == Form1.CheckedRadioButton.Rectangle) if(f.GetCheckedRadioButton() == Form1.CheckedRadioButton.Line) if(f.GetCheckedRadioButton() == Form1.CheckedRadioButton.Ellipse) // 前回と同じなので省略 if(f.GetCheckedRadioButton() == Form1.CheckedRadioButton.Selection) { BeginSelection?.Invoke(this, new XY(Column, Row)); DoDragDrop(0, DragDropEffects.All); EndSelection?.Invoke(this, new XY(-1, -1)); } } private void PanelEx_DragOver(object sender, DragEventArgs e) { e.Effect = DragDropEffects.All; Form1 f = (Form1)FindForm(); if(f.GetCheckedRadioButton() == Form1.CheckedRadioButton.Free) { this.BackColor = f.CurColor; } else DragOverPanel?.Invoke(this, new XY(Column, Row)); } private void PanelEx_DragDrop(object sender, DragEventArgs e) { Form1 f = (Form1)FindForm(); if(f.GetCheckedRadioButton() == Form1.CheckedRadioButton.Selection) { if(!f.isSizeChange) EndSelection?.Invoke(this, new XY(Column, Row)); else EndSelectSizeChange?.Invoke(this, new XY(Column, Row)); } } } |
DragOverPanelイベントが発生したときの処理ですが選択範囲を調べてパネルの色を変えるようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public partial class Form1 : Form { PanelEx CreateColorPanel(int i, int j) { // 省略 // イベントに対応できるようにする box.BeginSelection += Box_BeginSelection; box.EndSelection += Box_EndSelection; box.DragOverPanel += Box_DragOverPanel; // 省略 } } |
マウスが動いただけではドラッグオーバーされているパネルは同じかもしれません。そのときはなにもしないようにしています。前回ドラッグオーバーされていたパネルと今回ドラッグオーバーされているパネルが同じかどうかはフィールド変数(SelectionX、SelectionY)に値を保存してこれを比較することで判断しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
public partial class Form1 : Form { int SelectionX = -1, SelectionY = -1; List<XY> SelectionXYs = new List<XY>(); // 選択範囲のパネルの色を変える private void Box_DragOverPanel(object sender, XY e) { if(GetCheckedRadioButton() == CheckedRadioButton.Free) return; int oldSelectionX = SelectionX; int oldSelectionY = SelectionY; if(oldSelectionX != e.X || oldSelectionY != e.Y) { SelectionX = e.X; SelectionY = e.Y; Bitmap canvas = new Bitmap(32, 32); Graphics g = Graphics.FromImage(canvas); Point startPoint; Size size; GetStartPointSize(new Point(startX, startY), new Point(e.X, e.Y), out startPoint, out size); // 長方形(ただし直線が選択されているときとstartX == e.X || startY == e.Yのときは直線)を描く if(GetCheckedRadioButton() == CheckedRadioButton.Line) g.DrawLine(Pens.Black, startX, startY, e.X, e.Y); else if(startX == e.X || startY == e.Y) g.DrawLine(Pens.Black, startPoint.X, startPoint.Y, e.X, e.Y); else g.DrawRectangle(Pens.Black, startPoint.X, startPoint.Y, size.Width, size.Height); g.Dispose(); List<XY> xys = new List<XY>(); for(int i = 0; i < 32; i++) { for(int j = 0; j < 32; j++) { Color color = canvas.GetPixel(j, i); if(color.ToArgb() != 0) xys.Add(new XY(j, i)); } } List<XY> oldSelectionXYs = SelectionXYs.ToList(); foreach(var o in xys) SelectionXYs = xys; canvas.Dispose(); // いったん前の色に戻す foreach(var o in oldSelectionXYs) { panels[o.X, o.Y].BackColor = o.oldColor; } // 新たに選択されている範囲のパネルの色を変える foreach(var o in SelectionXYs) { o.oldColor = panels[o.X, o.Y].BackColor; panels[o.X, o.Y].BackColor = Color.Tan; } } } } |
また描画される直線、長方形、楕円が確定した場合は、範囲選択を解除する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class Form1 : Form { private void Box_EndRectangle(object sender, XY e) { ClearSelectionXYs(); // 以下、前回と同じなので省略 } // 直線、楕円の場合も同じ。 // 範囲選択をクリアするメソッド public void ClearSelectionXYs() { foreach(var o in SelectionXYs) { panels[o.X, o.Y].BackColor = o.oldColor; } SelectionXYs.Clear(); } } |
これは単に範囲選択が選択されているときの処理です。範囲選択の開始時にClearSelectionXYsメソッドでSelectionXYsの要素を空にするとともに、境界部分の色をもとの色に戻しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class Form1 : Form { private void Box_BeginSelection(object sender, XY e) { startX = e.X; startY = e.Y; SelectionX = e.X; SelectionY = e.Y; ClearSelectionXYs(); } private void Box_EndSelection(object sender, XY e) { // 今はすることはない。 } } |
これでどこに図形を描画されるかがわかるようになります。