views:

51

answers:

4

In c# I am using a PictureBox on a win form.

I am trying to recreate MSPaint to learn about the Graphics Object. It all works fine and dandy except that when another window is on on top of the PictureBox, or the entire form is resized, what is drawn under the other window in there is removed.

Here is a scaled down version of the code I am working with.

private Graphics _g;
private bool _bIsMouseDown = false;

private void picCanvas_MouseDown(object sender, MouseEventArgs e)
{
  if (!_bIsGraphicsSet) _g = picCanvas.CreateGraphics();
  _bIsMouseDown = true;
  DrawRectangle(e);
}

private void picCanvas_MouseMove(object sender, MouseEventArgs e)
{
  if (_bIsMouseDown) DrawRectangle(e);
}

private void picCanvas_MouseUp(object sender, MouseEventArgs e)
{
  _bIsMouseDown = false;
}

private void DrawRectangle(MouseEventArgs e)
{
    System.Drawing.Rectangle r = CreateRectangle(e);
    Pen pen = ChooseDrawColor();
    _g.DrawRectangle(pen, r);
}

private Rectangle CreateRectangle(MouseEventArgs e)
{
  int h = 10; 
  int w = 10; 
// there is code in here for multiple sized rectangles, 
//I know the math can be simplified for this example. 
          return new Rectangle(e.X - (w / 2), e.Y - (h / 2), w, h);
        }

Any thoughts would be much appreciated.

+1  A: 

You need to move all drawing code to the Paint event handler. In mouse event handlers, just set some variables reflecting new image state, and invalidate the window. Take a look at this sample: http://www.codeproject.com/KB/graphics/drawtools.aspx

Alex Farber
+1  A: 

I think what you are facing is that your picture pox gets repainted on its paint event.

The approach I usually take to managing custom paint jobs is this:

  • Store some abstract representation of your picture as a class member. I your case, it may be a collection of shapes, a bitmap, or so on.
  • Override the OnPaint method (if extending a control) or the Paint event handler, and repeat your drawing steps using the data you've stored above.
  • In events that should cause an update, such as picCanvas_MouseDown, call Invalidate() on the control to force it to repaint.

Because resize events cause invalidation, your paint routine will get called, and the picture will appear to remain unchanged.

kbrimington
+3  A: 

That is because you are not drawing on the window, you are just drawing on the screen where the window happens to be.

You need to use the Paint event to do the drawing. You need to store what you draw in some way, either as a list of commands so that you can repeat them, or as a bitmap image.

So, when you want to draw something, you add it to your list of commands or draw it on the bitmap, then you invalidate the control so that the Paint event is invoked. In the Paint even you add the code to do the actual drawing, i.e. repeat the commands in your list, or draw the bitmap onto the control.

Guffa
A: 

You could create an image to store the drawing.

private Bitmap _drawBuffer;

...

_drawBuffer = new Bitmap(pictureBox.Image);
_g = Graphics.FromImage(_drawBuffer));

...

private void DrawRectangle(MouseEventArgs e)
{
    System.Drawing.Rectangle r = CreateRectangle(e);
    Pen pen = ChooseDrawColor();
    _g.DrawRectangle(pen, r);
    pictureBox.Image = _drawBuffer;
}

This comes with the plus side of being able to save the image using the Image.Save function. You'll need to resize the bitmap on resize.

Blam