Update a drawing without deleting the previous one
I created this within a drawing method
private void draws()
{
Bitmap bmp = new Bitmap(pictureBox17.Width, pictureBox17.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
//define area do pictureBox17 e preenche a branco
Brush brush = new SolidBrush(Color.White);
Rectangle area = new Rectangle(0, 0, pictureBox17.Width, pictureBox17.Height);
g.FillRectangle(brush, area);
//desenha as linhas do rectangulo
g.DrawLine(new Pen(Color.Black), esp, esp, esp, yWcorrigidoesp);
// some more lines
}
pictureBox17.Image = bmp;
}
And it draws exactly what i want. But imagine that after this i wanna update the exactly same drawing, ADDING a few lines, without having to draw all again, is this possible? Obviously i'm using the method
draws();
And then i wanna add something, any tips?
The way to do it is to create a DrawAction
class which holds all the data needed for the things you want to draw: The Point
data, the Pen
or Brush
etc.
Then you create and manage a List<DrawAction> drawActions
and then you have a choice:
-
You either do all the drawing 'live' in the
Paint
event of thePictureBox
or aPanel
(or any control with aPaint
event) by looping over the list.. -
..Or you add the new Actions into the
Bitmap Image
you are building up.
What is better really depends: do you expect to do dynamic drawing, say by user actions? Do you want an undo/redo option? Then live drawing onto the control surface is a little better suited.
Or is the list of things to do fixed or derive from a fixed set of data and meant to be eventually saved to disk. That sounds more like drawing into the bitmap.
Both can also be combined, maybe collect a number of actions while keeping the option of undoing (by removing the last list item) and offering an Apply button to pump them into the bitmap..
Note: The key to drawing stuff is to keep the drawing data ready in a list so you can use it when you need it again, expand and delete the list and even change it: It would be a simple two-liner to go over all the actions and to change the Color
or the Width
or the LineStyle
of the Pen
or shifting Points
a little etc etc!
When you create the DrawAction
class it helps if you can decide which actions you will need. If you can't you still can go for a more extended class with enough members to work with all the many options the Graphics
class offers: Drawxx
, Fillxxx
, Pen
properties, Colors
maybe even zoom..
For starters a Type, a List<Point>
a float PenWidth
and a Color
will do..
Here is an example with a simple class, the Paint
event, code to add a few test actions and both
:
- A button to do live drawing and..
- ..one to apply the action to the apply the actions to the bitmap
Image
of aPictureBox
.
The test data are one Line
and one set of Polylines
.
You should start improving on it by defining an Enum
with all the types of drawing actions you want to use! This will be much better and easier to understand the the cheapo character type I have coded ;-) The types could include Rectangle, FilledRectangle, Ellipse, FilledEllipse, Line, Lines, Polygon, FilledPolygon, Text, Curve, Curves
and then some. With a little extra you can also work with Image, GraphicsPath, Spline.. And other data could control Rotation, Scaling, Gradients, Transparency
etc..
List<DrawAction> actions = new List<DrawAction>();
public class DrawAction
{
public char type { get; set; } // this should be an Enum!
public Color color { get; set; }
public float penWidth { get; set; } // only one of many Pen properties!
public List<Point> points { get; set; } // use PointF for more precision
public DrawAction(char type_, Color color_, float penwidth_)
{
type = type_; color = color_; penWidth = penwidth_;
points = new List<Point>();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Draw(e.Graphics, actions);
}
public void Draw(Graphics G, List<DrawAction> actions)
{
foreach (DrawAction da in actions)
if (da.type == 'L' && da.points.Count > 1)
using (Pen pen = new Pen(da.color, da.penWidth))
G.DrawLine(pen, da.points[0], da.points[1]);
else if (da.type == 'P' && da.points.Count > 1)
using (Pen pen = new Pen(da.color, da.penWidth))
G.DrawLines(pen, da.points.ToArray());
// else..
}
private void button1_Click(object sender, EventArgs e)
{
AddTestActions();
pictureBox1.Invalidate();
}
private void button2_Click(object sender, EventArgs e)
{
AddTestActions();
Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height);
using (Graphics G = Graphics.FromImage(bmp)) Draw(G, actions);
pictureBox1.Image = bmp;
}
void AddTestActions()
{
actions.Add(new DrawAction('L', Color.Blue, 3.3f));
actions[0].points.Add(new Point(23, 34));
actions[0].points.Add(new Point(23, 134));
actions.Add(new DrawAction('P', Color.Red, 1.3f));
actions[1].points.Add(new Point(11, 11));
actions[1].points.Add(new Point(55, 11));
actions[1].points.Add(new Point(55, 77));
actions[1].points.Add(new Point(11, 77));
}
The result for both looks the same:
Update Another, maybe more appropriate design would be to have a Draw (Graphics g)
method in the DrawAction class. Then in a Paint event this would do: foreach (DrawAction da in drawActionList) da.Draw(e.Graphics);
Try creating the Bitmap outside of the function to preserve it, the way you are doing it now disposes of the Bitmap element after the function has completed.
you could then do something like
Bitmap bmp = new Bitmap(pictureBox17.Width, pictureBox17.Height);
private void draws()
{
if (bmp ==null)
using (Graphics g = Graphics.FromImage(bmp))
{
//define area do pictureBox17 e preenche a branco
Brush brush = new SolidBrush(Color.White);
Rectangle area = new Rectangle(0, 0, pictureBox17.Width, pictureBox17.Height);
g.FillRectangle(brush, area);
//desenha as linhas do rectangulo
g.DrawLine(new Pen(Color.Black), esp, esp, esp, yWcorrigidoesp);
}
else {
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawLine(new Pen(Color.Black), esp, esp, esp, yWcorrigidoesp);
}
// some more lines
}
pictureBox17.Image = bmp;
}
Just to get you started.. :)
Alternatively you can pass the bmp into the draw function if you use this method to draw multiple bmp at different times