How to keep graphics when resizing C# form - c#

I am working on a program where I need to draw rectangle graphics onto the form itself, when I click the form. I created code to do this (below), but when I resize the form the rectangles are deleted.
How do I retain the drawn rectangles when the form is resized?
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
Graphics g = this.CreateGraphics();
Pen Haitham = new Pen(Color.Silver, 2);
g.FillRectangle(Haitham.Brush, new Rectangle(e.X, e.Y, 50, 50));
}

You could do this instead:
private List<Point> _points = new List<Point>();
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
foreach(Point point in _points)
{
using (Pen Haitham = new Pen(Color.Silver, 2))
{
e.Graphics.FillRectangle(Haitham.Brush, new Rectangle(point.X, point.Y, 50, 50));
}
}
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
_points.Add(new Point(e.X, e.Y));
Invalidate(); // could be optimized to invalidate only the future rectangle draw
}
In Windows with Winforms (or native Windows), you supposed to override OnPaint and do almost all your paint logic there.
Note with WPF, it would be different, you would compose a scene adding elements to it (here you would add a Rectangle shape to a Canvas for example).

You must do the "Graphics" things in the "Paint" event. Then you can see your rectangle always, because the event fires whenever windows needed to invalidate the paintings.
Cheers

I'm not too terribly familiar with graphics, but I am assuming that you would need to put all of your drawing objects into a container and have them redrawn when the form is sized. You might need to recall all of your paining objects in the sizeChanged event.

Related

Visual Studio C# pictureBox - drawing in From constructor doesn't show up

I have the problem that I want to draw on a pictureBox with an image loaded before the user gets to see it. The drawing in principle works, but if I do it in the constructor it doesn't show up. It does work if I call the same function with a button.
public Form1()
{
InitializeComponent();
draw();
}
public void draw()
{
pictureBox1.Refresh();
Graphics g = pictureBox1.CreateGraphics();
Rectangle rect = new Rectangle(new Point(20, 20), new Size(40, 40));
rect.Offset(8, 8);
g.DrawEllipse(new Pen(Brushes.Black, 2), rect);
g.Dispose();
}
private void button1_Click(object sender, EventArgs e)
{
draw();
}
I would have assumed that the circle would show up when the Form loads but it only does when I press the button. The code itself gets executed, as tested with a Message box.
The control paints itself in its Paint event, so as soon as it's shown on screen (ie, after your code), it will paint itself in dull gray as normal.
If you want to custom paint a control, any control, you either override its OnPaint function or subscribe to its exposed Paint event.
A hint should be the fact that you had to create your own Graphics object, as opposed to using the object constructed during normal painting operations, that also includes proper clipping handling.

WinForms - How do I run a function with PaintEventArgs when the form is loaded?

I'm trying to understand the graphics, and in the Graphics.FromImage documentation, it has this as an example:
private void FromImageImage(PaintEventArgs e)
{
// Create image.
Image imageFile = Image.FromFile("SampImag.jpg");
// Create graphics object for alteration.
Graphics newGraphics = Graphics.FromImage(imageFile);
// Alter image.
newGraphics.FillRectangle(new SolidBrush(Color.Black), 100, 50, 100, 100);
// Draw image to screen.
e.Graphics.DrawImage(imageFile, new PointF(0.0F, 0.0F));
// Dispose of graphics object.
newGraphics.Dispose();
}
I'm new to C# and Windows Forms and am struggling to understand how this all fits together. How is this code run, say when the form first loads or when a button is pressed?
Maybe this will help. I have an example of both drawing on Paint events but also drawing on top of an existing Image. I created a form with two picture boxes. One for each case. pictureBox1 has an event handler for the .Paint event, while pictureBox2 is only drawn when a button is pressed.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
pictureBox1.BackColor=Color.Black;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
// The code below will draw on the surface of pictureBox1
// It gets triggered automatically by Windows, or by
// calling .Invalidate() or .Refresh() on the picture box.
DrawGraphics(e.Graphics, pictureBox1.ClientRectangle);
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
// The code below will draw on an existing image shown in pictureBox2
var img = new Bitmap(pictureBox2.Image);
var g = Graphics.FromImage(img);
DrawGraphics(g, pictureBox2.ClientRectangle);
pictureBox2.Image=img;
}
void DrawGraphics(Graphics g, Rectangle target)
{
// draw a red rectangle around the moon
g.DrawRectangle(Pens.Red, 130, 69, 8, 8);
}
}
So when you launch the application a red rectangle appears on the left only, because the button hasn't been pressed yet.
and when the button is pressed, the red rectangle appears on top of the image displayed in pictureBox2.
Nothing dramatic, but it does the job. So depending on the mode of operation you need (user graphics, or image annotations) use the example code to understand how to do it.

How to draw multiple ellipse in the same panel

I am trying to draw some ellipse in the same panel, and the coordinators are determined by mouse click. Here is my code, this code can only draw one circle. The newer circle is always updating the older circle on the panel. So there is always only one circle.
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
x = e.X;
y = e.Y;
panel1.Invalidate();
}
Graphics g;
private void panel1_Paint(object sender, PaintEventArgs e)
{
g = panel1.CreateGraphics();
g.FillEllipse(Brushes.Red, x,y, 10, 10);
}
Winforms graphics basic rule #1 : Never use control.CreateGraphics! Never try to cache a Graphics object! Either draw into a Bitmap bmp using a Graphics g = Graphics.FromImage(bmp) or in the Paint event of a control, using the e.Graphics parameter..
You can test the persistance of your graphics by doing a Minimize/Maximize sequence..
The correct way is to keep a list of things to draw and whenever that list changes Invalidate the control you draw on. All drawing should be in the Paint event, using e.Graphics there!
This will let you draw many circles:
List<Point> points = new List<Point>(); // List<T> is wonderful !
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
points.Add(e.Location);
panel1.Invalidate();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics; // only ever use this one for persistent graphics!!
foreach( Point pt in points)
g.FillEllipse(Brushes.Red, pt.X, pt.Y, 10, 10);
}
delete them all by
points.Clear();
Delete the last one by
points.Remove(points.Last());
For other sizes store List<Rectangle> instead. For more complex drawing create a DrawAction class of your own to hold pens, colors or even rotations and other shapes etc..

DIfference between PaintEventArgs.Graphics and Graphics.FromHwnd in Drawing

Latest
//combination of pictureBox1.Invalidate(); and pictureBox1.Update();
pictureBox1.Refresh();
After pictureBox1.Refresh(); , it will trigger pictureBox1_Paint
Following code will have the icon remain on the picture box.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (checkBox1.Checked)
{
e.Graphics.DrawIcon(IconCamera, rect);
}
}
Following code NOT! it will draw the icon and clear it soon after it was drawn in Paint (that why have my old question)
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics graphic = Graphics.FromHwnd(pictureBox1.Handle);
if (checkBox1.Checked)
{
graphic.DrawIcon(IconCamera, rect);
}
}
I thought these two graphics are same but it seem like they are not same.
May I know what is the difference of Graphics of PaintEventArgs of
pictureBox1 and Graphics from handle of pictureBox1?
Why DrawIcon on pictureBox1 Paint event with Graphics from handle of
pictureBox1 will disappear in Paint event but not in the function I
declared? thanks
Old Question
When I checked the checkbox then I will draw icon on the picture box,
Graphics graphic = Graphics.FromHwnd(pictureBox1.Handle);
if (checkBox1.CheckState.ToString() == "Checked")
{
Icon IconCamera = new Icon("cam.ico");
Rectangle rect = new Rectangle(100, 100, 32, 32);
graphic.DrawIcon(IconCamera, rect);
}
BUT After the picture box refresh,
pictureBox1.Refresh();
the drawn icon will disappear.
May I know what picturebox event OR else can I make use to put in the drawing icon code to maintain or always auto redraw the icon even after the picture box refresh()? thanks. I tried Paint and Validating of picturebox1 cannot work.
The best is to use two calls one after each other:
pictureBox1.Invalidate();
pictureBox1.Update();
This will force the picturebox to be redrawn.
Then I subscribe for Paint event, which is signalled when previous two lines of code are called (in case of redrawing the picturebox). Here I do the all the drawings.
In your case it would be something like this:
public void Paint(PaintEventArgs e)
{
if (checkBox1.Checked)
{
Rectangle rect = new Rectangle(100, 100, 32, 32);
Icon IconCamera = new Icon("cam.ico");
e.Graphics.DrawIcon(IconCamera, rect);
}
}
Then, subscribe for event CheckedChanged of checkBox1, and call there that two redrawing commands from the begin of this post.
It causes, that when user change the checked state of checkBox1, pictureBox1 will be forced to be redrawn and the icon will be drawn according to checkBox1 state.
You can avoid using a Graphics object and find another way. I don't know if you are forced in using an icon, but you can try to use a Label this way.
label1.Image = "yourImage.bmp" // you can use a bitmap
There here come your statement.
if(checkBox1.Checked) {
label1.Visible = true;
label1.Location = new Point(x, y); // your coordinate
}
Then you can handle checkBox1_CheckedChanged and code:
Void checkBox1_CheckedChanged(object sender, EventArgs e) {
if(!checkBox1.Checked) {
label1.Visible = false;
}
}
Hope this could help.

How to assign a click event handler to part of a drawn rectangle?

Imagine I use the .NET graphic classes to draw a rectangle.
How could I then assign an event so that if the user clicks a certain point, or a certain point range, something happens (a click event handler)?
I was reading CLR via C# and the event section, and I thought of this scenario from what I had read.
A code example of this would really improve my understanding of events in C#/.NET.
Thanks
You can assign Click event handler to control whose surface will be used to draw rectangle.
Here is a small example:
When you click on form inside of rectangle it will be drawn with red border when you click outside it will be drawn with black border.
public partial class Form1 : Form
{
private Rectangle rect;
private Pen pen = Pens.Black;
public Form1()
{
InitializeComponent();
rect = new Rectangle(10, 10, Width - 30, Height - 60);
Click += Form1_Click;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawRectangle(pen, rect);
}
void Form1_Click(object sender, EventArgs e)
{
Point cursorPos = this.PointToClient(Cursor.Position);
if (rect.Contains(cursorPos))
{
pen = Pens.Red;
}
else
{
pen = Pens.Black;
}
Invalidate();
}
}
PointToClient method translates cursor coordinates to control-relative coordinates. I.e. if you cursor is at (screenX, screenY) position on the screen it can be at (formX, formY) position relatively to form's top-left corner. We need to call it to bring cursor position into coordinate system used by our rectangle.
Invalidate method makes control to redraw itself. In our case it triggers OnPaint event handler to redraw rectangle with a new border color.

Categories