今回は自由曲線を描きます。自由曲線はまるごと移動させることはないはずなので、マウスボタンが離されたらすぐに反映させることにします。
Contents
DrawFreeLineクラス
自由曲線を描画するためのクラスを作成します。Paintと同じように線の太さは常に1とします。
マウスがドラッグされたらCurPointプロパティに座標がセットされます。これを元にして自由曲線を描画するのですが、その一つまえの座標を記憶しておき、同じものがセットされた場合は描画される内容は変わらないのでなにもしないことにします。あとはダミーのBitmapに描画して自由曲線の各点のピクセル座標を取得します。
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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
public class DrawFreeLine: DrawLine { public DrawFreeLine(ImageEditPictureBox imageEditPanel, Point startPoint, Color color, int width, int rate) : base(imageEditPanel, startPoint, color, width, rate) { int x = startPoint.X / CellSize; int y = startPoint.Y / CellSize; Cell newCell = new Cell(x, y, color); Cells.Add(newCell); LastCell = newCell; } Cell LastCell = null; new public Point CurPoint { set { int x1 = LastCell.X; int y1 = LastCell.Y; int x2 = value.X / CellSize; int y2 = value.Y / CellSize; // 同じセルからマウスが移動していない場合はなにもしない if (x1 == x2 && y1 == y2) return; Bitmap bitmap = new Bitmap(Math.Abs(x2 - x1) + 1, Math.Abs(y2 - y1) + 1); Graphics g = Graphics.FromImage(bitmap); int startX = 0; int startY = ((x1 <= x2 && y1 <= y2) || (x1 > x2 && y1 > y2)) ? 0 : Math.Abs(y2 - y1); int endX = Math.Abs(x2 - x1); int endY = (x1 <= x2 && y1 > y2) || (x1 > x2 && y1 <= y2) ? 0 : Math.Abs(y2 - y1); g.DrawLine(Pens.Black, new Point(startX, startY), new Point(endX, endY)); g.Dispose(); int x0 = x1 <= x2 ? x1 : x2; int y0 = y1 <= y2 ? y1 : y2; List<Point> points = new List<Point>(); for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { if (bitmap.GetPixel(x, y).ToArgb() == Color.Black.ToArgb()) points.Add(new Point(x + x0, y + y0)); } } bool isAdd = false; foreach (Point point in points) { Cell newCell = new Cell(point.X, point.Y, Color); if (!Cells.Any(cell => cell.X == newCell.X && cell.Y == newCell.Y)) { Cells.Add(newCell); isAdd = true; } } bitmap.Dispose(); // Cellsに追加されたときだけ if(isAdd) ImageEditPictureBox.Invalidate(); Cell newCell1 = new Cell(x2, y2, Color); LastCell = newCell1; } } new public void DrawTempLine(Graphics graphics) { SolidBrush solidBrush; if (Color != Color.Empty) solidBrush = new SolidBrush(Color); else solidBrush = new SolidBrush(Color.FromName("Control")); foreach (Cell cell in Cells) { graphics.FillRectangle( solidBrush, new Rectangle(cell.X * CellSize, cell.Y * CellSize, CellSize, CellSize)); } solidBrush.Dispose(); } } |
Form2でマウスボタンが押され、移動し、ボタンが離されたときの処理を示します。
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 |
public partial class Form2 : Form { private void ImageEditPictureBox_MouseDown(object sender, MouseEventArgs e) { if (DecisionDrawing()) return; if (RadioButtonFreeLine.Checked) MouseDownForDrawFreeLine(e.X, e.Y); } private void ImageEditPictureBox_MouseMove(object sender, MouseEventArgs e) { if (ImageEditPictureBox.Capture) { if (RadioButtonFreeLine.Checked && DrawFreeLine != null) MouseMoveForDrawFreeLine(e.X, e.Y); } } bool DecisionDrawing() { if (DrawFreeLine != null) DecisionForDrawFreeLine(); // 確定時の直線などの描画 return DrawConfirmed(); } private void ImageEditPictureBox_MouseUp(object sender, MouseEventArgs e) { if (DrawFreeLine != null) { DecisionDrawing(); } } } |
ステータスバーに次にするべき動作を表示する
それからステータスバーに現在どのような状態になっているのか、次に何をするのかを表示させたほうが親切設計だと思うので、このようにしてみるのはどうでしょうか?
ラジオボタンの状態が変更されたとき
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public partial class Form2 : Form { public Form2(PictureBoxUserControl control) { InitializeComponent(); this.RadioButtonRange.CheckedChanged += RadioButtonRange_CheckedChanged; RadioButtonPoint.CheckedChanged += RadioButtonPoint_CheckedChanged; RadioButtonLine.CheckedChanged += RadioButtonLine_CheckedChanged; RadioButtonRectangle.CheckedChanged += RadioButtonRectangle_CheckedChanged; RadioButtonEllipse.CheckedChanged += RadioButtonEllipse_CheckedChanged; RadioButtonFillConnectedColor.CheckedChanged += RadioButtonFillConnectedColor_CheckedChanged; RadioButtonFillEnclosedArea.CheckedChanged += RadioButtonFillEnclosedArea_CheckedChanged; RadioButtonFreeLine.CheckedChanged += RadioButtonFreeLine_CheckedChanged; // ここから下はこれまでと同じ } } |
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 66 67 68 69 70 71 72 73 74 |
public partial class Form2 : Form { private void RadioButtonRange_CheckedChanged(object sender, EventArgs e) { if (RadioButtonRange.Checked) { DecisionDrawing(); StatusLabel1.Text = "編集する範囲を指定してください"; } } private void RadioButtonPoint_CheckedChanged(object sender, EventArgs e) { if (RadioButtonPoint.Checked) { DecisionDrawing(); StatusLabel1.Text = "クリックされた点の色を変更します"; } } private void RadioButtonLine_CheckedChanged(object sender, EventArgs e) { if (RadioButtonLine.Checked) { DecisionDrawing(); StatusLabel1.Text = "直線:開始位置を選択してください"; } } private void RadioButtonRectangle_CheckedChanged(object sender, EventArgs e) { if (RadioButtonRectangle.Checked) { DecisionDrawing(); StatusLabel1.Text = "矩形:開始位置を選択してください"; } } private void RadioButtonEllipse_CheckedChanged(object sender, EventArgs e) { if (RadioButtonEllipse.Checked) { DecisionDrawing(); StatusLabel1.Text = "楕円:開始位置を選択してください"; } } private void RadioButtonFreeLine_CheckedChanged(object sender, EventArgs e) { if (RadioButtonFreeLine.Checked) { DecisionDrawing(); StatusLabel1.Text = "自由曲線:開始位置を選択してください"; } } private void RadioButtonFillConnectedColor_CheckedChanged(object sender, EventArgs e) { if (RadioButtonFillConnectedColor.Checked) { DecisionDrawing(); StatusLabel1.Text = "塗りつぶし:選択した点と同じ連続した点を塗りつぶします"; } } private void RadioButtonFillEnclosedArea_CheckedChanged(object sender, EventArgs e) { if (RadioButtonFillEnclosedArea.Checked) { DecisionDrawing(); StatusLabel1.Text = "塗りつぶし:選択された色で囲まれている部分を塗りつぶします"; } } } |
マウスボタンが押されたとき
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 |
public partial class Form2 : Form { private void ImageEditPictureBox_MouseDown(object sender, MouseEventArgs e) { ClickedLabel.Text = String.Format("{0}, {1}", e.X / CellSize, e.Y / CellSize); if (RadioButtonRange.Checked) { Bitmap sourceBitmap = PictureBoxUserControl.Bitmap; ClickedColor = sourceBitmap.GetPixel(e.X / CellSize, e.Y / CellSize); ClickedPictureBox.BackColor = ClickedColor; } if (DecisionDrawing()) { StatusLabel1.Text = "確定しました"; return; } if (RadioButtonPoint.Checked) MouseDownForDrawPoint(e.X, e.Y); if (RadioButtonLine.Checked) { MouseDownForDrawLine(e.X, e.Y); StatusLabel1.Text = "直線の終点を指定してください"; } if (RadioButtonRectangle.Checked && !CheckBoxFill.Checked) { MouseDownForDrawRectangle(e.X, e.Y); StatusLabel1.Text = "矩形の終点を指定してください"; } if (RadioButtonRectangle.Checked && CheckBoxFill.Checked) { MouseDownForFillRectangle(e.X, e.Y); StatusLabel1.Text = "矩形の終点を指定してください"; } if (RadioButtonEllipse.Checked && !CheckBoxFill.Checked) { MouseDownForDrawEllipse(e.X, e.Y); StatusLabel1.Text = "楕円の終点を指定してください"; } if (RadioButtonEllipse.Checked && CheckBoxFill.Checked) { MouseDownForFillEllipse(e.X, e.Y); StatusLabel1.Text = "楕円の終点を指定してください"; } if (RadioButtonFreeLine.Checked) { MouseDownForDrawFreeLine(e.X, e.Y); StatusLabel1.Text = "自由曲線を描画しています"; } if (this.RadioButtonFillConnectedColor.Checked) { MouseDownForFillConnectedColor(e.X, e.Y); StatusLabel1.Text = "塗りつぶし処理が完了しました"; } if (this.RadioButtonFillEnclosedArea.Checked) { MouseDownForFillEnclosedArea(e.X, e.Y); StatusLabel1.Text = "塗りつぶし処理が完了しました"; } } } |
マウスボタンが離されたとき
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 |
public partial class Form2 : Form { private void ImageEditPictureBox_MouseUp(object sender, MouseEventArgs e) { if (DrawFreeLine != null) { DecisionDrawing(); StatusLabel1.Text = "自由曲線:始点をクリックしてください"; return; } string str1 = "まだ確定していません。方向キーで移動 Shiftキー+方向キーで始点移動 Ctrlキー+方向キーで終点移動"; string str2 = "開始位置を選択してください"; if (RadioButtonLine.Checked) { if (DrawLine != null && DrawLine.Cells.Count > 0) StatusLabel1.Text = "直線:" + str1; else StatusLabel1.Text = "直線:" + str2; return; } if (RadioButtonRectangle.Checked && !CheckBoxFill.Checked) { if(DrawRectangle != null && DrawRectangle.Cells.Count > 0) StatusLabel1.Text = "矩形:" + str1; else StatusLabel1.Text = "矩形:" + str2; return; } if (RadioButtonRectangle.Checked && CheckBoxFill.Checked) { if (FillRectangle != null && FillRectangle.Cells.Count > 0) StatusLabel1.Text = "矩形:" + str1; else StatusLabel1.Text = "矩形:" + str2; return; } if (RadioButtonEllipse.Checked && !CheckBoxFill.Checked) { if (DrawEllipse != null && DrawEllipse.Cells.Count > 0) StatusLabel1.Text = "楕円:" + str1; else StatusLabel1.Text = "楕円:" + str2; return; } if (RadioButtonEllipse.Checked && CheckBoxFill.Checked) { if (FillEllipse != null && FillEllipse.Cells.Count > 0) StatusLabel1.Text = "楕円:" + str1; else StatusLabel1.Text = "楕円:" + str2; return; } } } |
Enterキーで確定したとき
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 |
public partial class Form2 : Form { bool DecisionDrawing() { if (DrawLine != null) { DecisionForDrawLine(); StatusLabel1.Text = "直線:開始位置を選択してください"; } if (DrawRectangle != null) { DecisionForDrawRectangle(); StatusLabel1.Text = "矩形:開始位置を選択してください"; } if (FillRectangle != null) { DecisionForFillRectangle(); StatusLabel1.Text = "矩形:開始位置を選択してください"; } if (DrawEllipse != null) { DecisionForDrawEllipse(); StatusLabel1.Text = "楕円:開始位置を選択してください"; } if (FillEllipse != null) { DecisionForFillEllipse(); StatusLabel1.Text = "楕円:開始位置を選択してください"; } if (DrawFreeLine != null) { DecisionForDrawFreeLine(); StatusLabel1.Text = "自由曲線:開始位置を選択してください"; } // 確定時の直線などの描画 return DrawConfirmed(); } } |