In VS 6.0 and in OpenGL, this is fairly simple, you just use the XOR
drawing mode, which draws a line normally the first time, and then
"erases" it the second time.
GDI+ doesn't have support for the pen modes anymore, but your task is
not too much more difficult.
There are a couple ways to do this:
1. you could keep a bitmap of what the clear, or erased state looks
like, and whenever you want to erase the line, you would do something like:
//...
private Image savedImage;
//...
// your standard paint method
private void My_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
if (something_has_changed_like_the_form_has_been_resized)
{
Rectangle rect = this.GetDrawingRectangle();
this.savedImage = new Bitmap(rect.Width, rect.Height);
Graphics gx = Graphics.FromImage(savedImage);
gx.Clear(this.BackColor);
// draw the normal, erased state
// ...
gx.Dispose();
}
Graphics g = e.Graphics;
g.DrawImageUnscaled(this.savedImage,0,0);
// now draw any of the lines, pictures, etc.
// that you want to be erased.
}
2. The previous method is good if you need to completely redraw every
element of your picture each time, but what if you have a bunch of lines
already drawn, and you only want to erase one of them? Here's where you
can use a TextureBrush as a sort of eraser.
//...
private Image lastImage;
private Brush eraserBrush;
//...
// your standard paint method
private void My_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
if (something_has_changed_like_the_form_has_been_resized)
{
// we may need to redraw everything...
Rectangle rect = this.GetDrawingRectangle();
this.lastImage = new Bitmap(rect.Width, rect.Height);
Graphics gx = Graphics.FromImage(this.lastImage);
gx.Clear(this.BackColor);
// draw the normal, erased state
// ...
// draw all of the elements that should be drawn...
gx.Dispose();
this.eraserBrush = new TextureBrush(this.lastImage);
}
// all of our lines, pictures, etc. are already stored
// inside lastImage, so we don't need to do anything here.
// let's say we kept track of some coordinates for a line,
// and also kept track of whether or not we need to do
// some erasing
if (bLineNeedsErasing)
{
// by drawing to this Graphics object, we're updating the
// bitmap image.
Graphics imageGraphics = Graphics.FromImage(this.lastImage);
// assuming the first line was drawn with a width of 1 (float)
Pen p = new Pen(this.eraserBrush, 1F);
// assuming we kept track of a couple System.Drawing.PointF
// points representing the ends of the line
imageGraphics.DrawLine(p, this.linePoint1, this.linePoint2);
imageGraphics.Dispose();
}
Graphics g = e.Graphics;
g.DrawImageUnscaled(this.lastImage,0,0);
}
This second way is almost always the better way to go.
One last note: you're going to notice the screen flickering if you're
doing any kind of drawing. To alleviate this, look up the SetStyle
method, and use something like:
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
in your own initialization code.