Reply to Morten Wennevik: Drawing problem

J

James Dean

I know what you mean about using invalidate and i have already just
cleared the graphics object and set it to the back Color. The problem is
that i want to keep these lines, ellipses or rectangles i have drawn on
the screen so i just draw the image to an offscreen bitmpa but the next
time i want to draw another image on top of this the backcolor clears
and i lose the shape i had drawn to the bitmap previously......i know i
can just use the mouseup......but i want to see the image as being
drawn......here is the code

public Main_Form()
{
raphicsObject = this.CreateGraphics();
graphicsObject.PageUnit = GraphicsUnit.Pixel;
offScreenBmp = new Bitmap(this.Width, this.Height);
Graphics OffScreenGraphics = Graphics.FromImage(offScreenBmp);
OffScreenGraphics.DrawImage(offScreenBmp,0,0);
}

private void Main_Form_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{

startatX = e.X;
startatY = e.Y;
shouldPaint = true;
}

private void Main_Form_MouseMove(object sender,
System.Windows.Forms.MouseEventArgs e)
{
if(shouldPaint)
{
PaintToScreen1(e.X, e.Y);
}
}

private void PaintToScreen1(int x, int y)
{
Pen pen = new Pen(Color.DarkBlue);
int MouseX = x;
int MouseY = y;
int width = MouseX - startatX;
int height = MouseY - startatY;
if(LineMenuItem.Checked == true)
{
graphicsObject.DrawLine(pen,startatX,startatY,x,y);
}
else if(EllipseMenuItem.Checked == true)
{
graphicsObject.DrawEllipse(pen,startatX,startatY,width,height);
}
else if(RectMenuItem.Checked == true)
{
graphicsObject.DrawRectangle(pen,startatX,startatY,width,height);
}

}

private void Main_Form_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
shouldPaint = false;
Pen newpen = new Pen(Color.Gray,0);
graphicsObject = temporaryGraphicsObject;
graphicsObject.DrawImage(offScreenBmp,0,0);
}

In the PaintScreen method if i put
graphicsObject.Clear(this.BackColor)......then it will erase the
previous shape i have drawn on the screen......hope u can help
 
M

Morten Wennevik

James, you need to handle the drawing procedure for what should be drawn
on the screen in case of Invalidation() and store previously drawn
shapes. I have taken the liberty to make a few code suggestions (none are
tested) but you might want to use the offscreen bitmap when drawing
previous shapes instead of drawing each shape on every Invalidate, which
might get slow with many shapes.


// a collection of shapes
public enum Shapes
{
Line,
Rectangle,
Ellipse
}

// a shape structure
public struct Shape
{
public Shapes type;
public int startX;
public int startY;
public int endX;
public int endY;
}

ArrayList drawnShapes; // initialize in constructor = new ArrayList();

//I suggest you change the MouseMove code
private void Main_Form_MouseMove(object sender, MouseEventArgs e)
{
if(shouldPaint)
{
endatX = e.X;
endatY = e.Y;
Invalidate();
}
}

private void Main_Form_MouseUp(object sender, MouseEventArgs e)
{
shouldPaint = false;
Pen newpen = new Pen(Color.Gray,0);

Shape s = new Shape();
if(LineMenuItem.Checked == true)
{
s.type = Shapes.Line;
}
else if(EllipseMenuItem.Checked == true)
{
s.type = Shapes.Ellipse;
}
else if(RectMenuItem.Checked == true)
{
s.type = Shapes.Rectangle;
}
s.startX = startAtX;
s.startY = startAtY;
s.endX = endatX;
s.endY = endatY;
drawnShapes.Add(s);

shouldPaint = false;
Invalidate();
}

//add

protected void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen pen = new Pen(Color.DarkBlue);
int width = endatX - startatX;
int height = endatY - startatY;

DrawPreviousShapes(ref g, ref pen); // or draw from offscreenbitmap

if(LineMenuItem.Checked == true)
{
g.DrawLine(pen, startatX, startatY, endatX, endatY);
}
else if(EllipseMenuItem.Checked == true)
{
g.DrawEllipse(pen, startatX, startatY, width, height);
}
else if(RectMenuItem.Checked == true)
{
g.DrawRectangle(pen, startatX, startatY, width, height);
}
pen.Dispose();
}

private void DrawPreviousShapes(ref Graphics g, ref Pen pen)
{
foreach(Shape s in drawnShapes)
{
if(s.type == Shapes.Line)
{
g.DrawLine(pen, s.startX, s.startY, s.endX, s.endY);
}
else if(s.type == Shapes.Ellipse)
{
g.DrawEllipse(pen, s.startX, s.startY, s.endX - s.startX, s.endY
- s.startY);
}
else if(s.type == Shapes.Rectangle)
{
g.DrawRectangle(pen, s.startX, s.startY, s.endX - s.startX,
s.endY - s.startY);
}
}
}

OnPaint will be called by windows whenever it needs to refresh (like
hiding the window and bringing it back to front) or you Invalidate() it.

If it isn't the main form you can create a new drawing method like this:

Panel p = new Panel();
p.Paint += new PaintEventHandler(p_Paint);

private void p_Paint(object sender, PaintEventArgs e)
{
}

For the targeting of shapes you can do this to get the first available
shape
private Shape GetShape(int x, int y)
{
foreach(Shape s in drawnShapes)
{
if(x >= s.startX && y >= s.startY)
{
if(x <= s.endX && y <= s.endY)
return s;
}
}
}

Happy coding!
Morten
 
J

James Dean

Thanks alot sorry for bothering you.......that helps me so much......as
well in understanding how it works also. Thank you for your help
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top