前回の色を指定して直線を描画するでは直線の描画をしましたが、今回は矩形と楕円の描画をおこないます。
前回使用したクラスを少し変えるだけで矩形と楕円の描画は可能です。矩形と楕円の描画のための
DrawRectangle
FillRectangle
DrawEllipse
FillEllipse
4つのクラスをDrawLineクラスを継承して作成します。
DrawLineクラスとの違いは直線を引くか矩形・楕円を描くかの違いであり、始点と終点の情報から図形を描画することに関しては同じです。
Contents
DrawRectangleクラス
最初に矩形を描画するためのDrawRectangleクラスを示します。
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 |
public class DrawRectangle: DrawLine { public DrawRectangle(ImageEditPictureBox imageEditPictureBox, Point startPoint, Color color, int width, int rate) : base(ImageEditPictureBox, startPoint, color, width, rate) { } protected Rectangle GetRectangle() { int x1 = StartPoint.X / CellSize; int y1 = StartPoint.Y / CellSize; int x2 = CurPoint.X / CellSize; int y2 = CurPoint.Y / CellSize; Point point = new Point(0 + Width / 2, 0 + Width / 2); Size size = new Size(Math.Abs(x2 - x1) - Width + 1, Math.Abs(y2 - y1) - Width + 1); return new Rectangle(point, size); } public void DrawTempRectangle(Graphics graphics) { Bitmap bitmap = new Bitmap(Math.Abs(CurPoint.X / CellSize - StartPoint.X / CellSize) + 1, Math.Abs(CurPoint.Y / CellSize - StartPoint.Y / CellSize) + 1); Graphics g = Graphics.FromImage(bitmap); Pen pen = new Pen(Color.Black, Width); g.DrawRectangle(pen, GetRectangle()); pen.Dispose(); g.Dispose(); DrawCells(bitmap, graphics); bitmap.Dispose(); } } |
FillRectangleクラス
次に内部が塗りつぶされた矩形を描画するためのFillRectangleクラスを示します。Graphics.DrawRectangleメソッドとGraphics.FillRectangleメソッドでは1ピクセルぶんの差がでるのでFillRectangleクラスではGraphics.DrawRectangleメソッドとGraphics.FillRectangleメソッドを両方実行しています。あとはDrawRectangleクラスと同じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class FillRectangle : DrawRectangle { public FillRectangle(ImageEditPictureBox imageEditPictureBox, Point startPoint, Color color, int width, int rate) : base(ImageEditPictureBox, startPoint, color, width, rate) { } public void FillTempRectangle(Graphics graphics) { Bitmap bitmap = new Bitmap(Math.Abs(CurPoint.X / CellSize - StartPoint.X / CellSize) + 1, Math.Abs(CurPoint.Y / CellSize - StartPoint.Y / CellSize) + 1); Graphics g = Graphics.FromImage(bitmap); Pen pen = new Pen(Color.Black, Width); SolidBrush solidBrush = new SolidBrush(Color.Black); g.DrawRectangle(pen, GetRectangle()); g.FillRectangle(solidBrush, GetRectangle()); solidBrush.Dispose(); pen.Dispose(); g.Dispose(); DrawCells(bitmap, graphics); bitmap.Dispose(); } } |
DrawEllipseクラス
次に楕円を描画するためのDrawEllipseクラスを示します。ドラッグが開始された座標と終了した座標から矩形を取得するのは完全に同じです。あとはGraphics.DrawRectangleメソッドのかわりにGraphics.DrawEllipseメソッドを実行するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class DrawEllipse : DrawRectangle { public DrawEllipse(ImageEditPictureBox imageEditPictureBox, Point startPoint, Color color, int width, int rate) : base(imageEditPictureBox, startPoint, color, width, rate) { } public void DrawTempEllipse(Graphics graphics) { Bitmap bitmap = new Bitmap(Math.Abs(CurPoint.X / CellSize - StartPoint.X / CellSize) + 1, Math.Abs(CurPoint.Y / CellSize - StartPoint.Y / CellSize) + 1); Graphics g = Graphics.FromImage(bitmap); Pen pen = new Pen(Color.Black, Width); g.DrawEllipse(pen, GetRectangle()); pen.Dispose(); g.Dispose(); DrawCells(bitmap, graphics); bitmap.Dispose(); } } |
FillEllipseクラス
FillEllipseクラスは塗りつぶされた楕円を描画するときに使います。Graphics.DrawEllipseといっしょにGraphics.DrawEllipseメソッドを呼び出しているのが唯一の違いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class FillEllipse : DrawRectangle { public FillEllipse(ImageEditPictureBox imageEditPictureBox, Point startPoint, Color color, int width, int rate) : base(imageEditPictureBox, startPoint, color, width, rate) { } public void FillTempEllipse(Graphics graphics) { Bitmap bitmap = new Bitmap(Math.Abs(CurPoint.X / CellSize - StartPoint.X / CellSize) + 1, Math.Abs(CurPoint.Y / CellSize - StartPoint.Y / CellSize) + 1); Graphics g = Graphics.FromImage(bitmap); Pen pen = new Pen(Color.Black, Width); SolidBrush solidBrush = new SolidBrush(Color.Black); g.DrawEllipse(pen, GetRectangle()); g.FillEllipse(solidBrush, GetRectangle()); solidBrush.Dispose(); pen.Dispose(); g.Dispose(); DrawCells(bitmap, graphics); bitmap.Dispose(); } } |
Form2クラスの処理
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 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 |
public partial class Form2 : Form { DrawLine DrawLine = null; DrawRectangle DrawRectangle = null; FillRectangle FillRectangle = null; DrawEllipse DrawEllipse = null; FillEllipse FillEllipse = null; DrawFreeLine DrawFreeLine = null; List<Cell> ChangeCells = new List<Cell>(); 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()) return; if (RadioButtonPoint.Checked) MouseDownForDrawPoint(e.X, e.Y); if (RadioButtonLine.Checked) MouseDownForDrawLine(e.X, e.Y); if (RadioButtonRectangle.Checked && !CheckBoxFill.Checked) MouseDownForDrawRectangle(e.X, e.Y); if (RadioButtonRectangle.Checked && CheckBoxFill.Checked) MouseDownForFillRectangle(e.X, e.Y); if (RadioButtonEllipse.Checked && !CheckBoxFill.Checked) MouseDownForDrawEllipse(e.X, e.Y); if (RadioButtonEllipse.Checked && CheckBoxFill.Checked) MouseDownForFillEllipse(e.X, e.Y); } void MouseDownForDrawPoint(int clientX, int clientY) { // ImageEditPictureBox.Imageの変更 Bitmap bitmap = (Bitmap)ImageEditPictureBox.Image; Graphics graphics = Graphics.FromImage(bitmap); SolidBrush solidBrush; if (SelectedColor != Color.Empty) solidBrush = new SolidBrush(SelectedColor); else solidBrush = new SolidBrush(Color.FromName("Control")); // clientXとclientYをCellSizeの整数倍にする int x = clientX / CellSize * CellSize; int y = clientY / CellSize * CellSize; graphics.FillRectangle(solidBrush, new Rectangle(x, y, CellSize, CellSize)); graphics.Dispose(); ImageEditPictureBox.Invalidate(); // 元のBitmapの変更 Bitmap sourceBitmap = PictureBoxUserControl.Bitmap; sourceBitmap.SetPixel(clientX / CellSize, clientY / CellSize, SelectedColor); PictureBoxUserControl.Bitmap = sourceBitmap; } void MouseDownForDrawLine(int clientX, int clientY) { DrawLine = new DrawLine(ImageEditPictureBox, new Point(clientX, clientY), SelectedColor, (int)numericUpDown1.Value, CellSize); } void MouseDownForDrawRectangle(int clientX, int clientY) { DrawRectangle = new DrawRectangle(ImageEditPictureBox, new Point(clientX, clientY), SelectedColor, (int)numericUpDown1.Value, CellSize); } void MouseDownForFillRectangle(int clientX, int clientY) { FillRectangle = new FillRectangle(ImageEditPictureBox, new Point(clientX, clientY), SelectedColor, 1, CellSize); } void MouseDownForDrawEllipse(int clientX, int clientY) { DrawEllipse = new DrawEllipse(ImageEditPictureBox, new Point(clientX, clientY), SelectedColor, (int)numericUpDown1.Value, CellSize); } void MouseDownForFillEllipse(int clientX, int clientY) { FillEllipse = new FillEllipse(ImageEditPictureBox, new Point(clientX, clientY), SelectedColor, 1, CellSize); } } |
マウスがドラッグされているときの処理
次にマウスがドラッグされているときの処理を示します。マウスがクリックされたときに生成したオブジェクトのCurPointプロパティに現在マウスが存在するクライアント座標をセットするだけです。あとはオブジェクト側でうまくやってくれます。
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 |
public partial class Form2 : Form { private void ImageEditPictureBox_MouseMove(object sender, MouseEventArgs e) { int x = e.X / CellSize; int y = e.Y / CellSize; CurrentLabel.Text = String.Format("{0}, {1}", x, y); if (ImageEditPictureBox.Capture) { if (RadioButtonLine.Checked && DrawLine != null) MouseMoveForDrawLine(e.X, e.Y); if (RadioButtonRectangle.Checked && DrawRectangle != null) MouseMoveForDrawRectangle(e.X, e.Y); if (RadioButtonRectangle.Checked && FillRectangle != null) MouseMoveForFillRectangle(e.X, e.Y); if (RadioButtonEllipse.Checked && DrawEllipse != null) MouseMoveForDrawEllipse(e.X, e.Y); if (RadioButtonEllipse.Checked && FillEllipse != null) MouseMoveForFillEllipse(e.X, e.Y); } } void MouseMoveForDrawLine(int clientX, int clientY) { DrawLine.CurPoint = new Point(clientX, clientY); } void MouseMoveForDrawRectangle(int clientX, int clientY) { DrawRectangle.CurPoint = new Point(clientX, clientY); } void MouseMoveForFillRectangle(int clientX, int clientY) { FillRectangle.CurPoint = new Point(clientX, clientY); } void MouseMoveForDrawEllipse(int clientX, int clientY) { DrawEllipse.CurPoint = new Point(clientX, clientY); } void MouseMoveForFillEllipse(int clientX, int clientY) { FillEllipse.CurPoint = new Point(clientX, clientY); } } |
ドラッグされているときに図形の描画
ImageEditPanel_Paint内で呼び出されるDrawProvisionalメソッドを示します。DrawTempXXXメソッドやFillTempXXXメソッドを適切に呼び出して確定前の図形の描画をおこないます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public partial class Form2 : Form { private void ImageEditPictureBox_Paint(object sender, PaintEventArgs e) { DrawProvisional(e.Graphics); DrawBorderOfCells(e.Graphics); // 縦横の直線を描画 } void DrawProvisional(Graphics graphics) { if (RadioButtonLine.Checked && DrawLine != null) DrawLine.DrawTempLine(graphics); if (RadioButtonRectangle.Checked && DrawRectangle != null) DrawRectangle.DrawTempRectangle(graphics); if (RadioButtonRectangle.Checked && FillRectangle != null) FillRectangle.FillTempRectangle(graphics); if (RadioButtonEllipse.Checked && DrawEllipse != null) DrawEllipse.DrawTempEllipse(graphics); if (RadioButtonEllipse.Checked && FillEllipse != null) FillEllipse.FillTempEllipse(graphics); } } |
マウスボタンが離されたあとの位置調整の処理
ドラッグが終了したあと再びクリックがされたときやEnterキーが押される前であれば方向キーで描画位置を変更するための処理を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public partial class Form2 : Form { protected override void OnKeyDown(KeyEventArgs e) { // Enterキーなら確定 if (e.KeyCode == Keys.Enter) DecisionDrawing(); // Shiftキー+方向キーは始点のみ移動 // Ctrlキー+方向キーは終点のみ移動 // 方向キーのみなら全体が移動 if (e.KeyCode == Keys.Left) MoveLeftDrawing(!e.Control, !e.Shift); if (e.KeyCode == Keys.Up) MoveUpDrawing(!e.Control, !e.Shift); if (e.KeyCode == Keys.Right) MoveRightDrawing(!e.Control, !e.Shift); if (e.KeyCode == Keys.Down) MoveDownDrawing(!e.Control, !e.Shift); base.OnKeyDown(e); } } |
左に移動させる処理を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form2 : Form { void MoveLeftDrawing(bool start, bool end) { if (RadioButtonLine.Checked && DrawLine != null) DrawLine.MoveLeft(start, end); if (RadioButtonRectangle.Checked && DrawRectangle != null) DrawRectangle.MoveLeft(start, end); if (RadioButtonRectangle.Checked && FillRectangle != null) FillRectangle.MoveLeft(start, end); if (RadioButtonEllipse.Checked && DrawEllipse != null) DrawEllipse.MoveLeft(start, end); if (RadioButtonEllipse.Checked && FillEllipse != null) FillEllipse.MoveLeft(start, end); } } |
上に移動させる処理を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form2 : Form { void MoveUpDrawing(bool start, bool end) { if (RadioButtonLine.Checked && DrawLine != null) DrawLine.MoveUp(start, end); if (RadioButtonRectangle.Checked && DrawRectangle != null) DrawRectangle.MoveUp(start, end); if (RadioButtonRectangle.Checked && FillRectangle != null) FillRectangle.MoveUp(start, end); if (RadioButtonEllipse.Checked && DrawEllipse != null) DrawEllipse.MoveUp(start, end); if (RadioButtonEllipse.Checked && FillEllipse != null) FillEllipse.MoveUp(start, end); } } |
右に移動させる処理を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form2 : Form { void MoveRightDrawing(bool start, bool end) { if (RadioButtonLine.Checked && DrawLine != null) DrawLine.MoveRight(start, end); if (RadioButtonRectangle.Checked && DrawRectangle != null) DrawRectangle.MoveRight(start, end); if (RadioButtonRectangle.Checked && FillRectangle != null) FillRectangle.MoveRight(start, end); if (RadioButtonEllipse.Checked && DrawEllipse != null) DrawEllipse.MoveRight(start, end); if (RadioButtonEllipse.Checked && FillEllipse != null) FillEllipse.MoveRight(start, end); } } |
下に移動させる処理を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form2 : Form { void MoveDownDrawing(bool start, bool end) { if (RadioButtonLine.Checked && DrawLine != null) DrawLine.MoveDown(start, end); if (RadioButtonRectangle.Checked && DrawRectangle != null) DrawRectangle.MoveDown(start, end); if (RadioButtonRectangle.Checked && FillRectangle != null) FillRectangle.MoveDown(start, end); if (RadioButtonEllipse.Checked && DrawEllipse != null) DrawEllipse.MoveDown(start, end); if (RadioButtonEllipse.Checked && FillEllipse != null) FillEllipse.MoveDown(start, end); } } |
以下は確定時の処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public partial class Form2 : Form { bool DecisionDrawing() { if (DrawLine != null) DecisionForDrawLine(); if (DrawRectangle != null) DecisionForDrawRectangle(); if (FillRectangle != null) DecisionForFillRectangle(); if (DrawEllipse != null) DecisionForDrawEllipse(); if (FillEllipse != null) DecisionForFillEllipse(); // 確定時の直線などの描画 return DrawConfirmed(); } } |
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 |
public partial class Form2 : Form { void DecisionForDrawLine() { ChangeCells = DrawLine.Cells; DrawLine = null; } void DecisionForDrawRectangle() { ChangeCells = DrawRectangle.Cells; DrawRectangle = null; } void DecisionForFillRectangle() { ChangeCells = FillRectangle.Cells; FillRectangle = null; } void DecisionForDrawEllipse() { ChangeCells = DrawEllipse.Cells; DrawEllipse = null; } void DecisionForFillEllipse() { ChangeCells = FillEllipse.Cells; FillEllipse = null; } } |