I have created a small application in C#, in which I draw a rectangle when the mouse is moved.
However, when the form is minimized or maximized, the drawing is erased. Also, when I draw a second time, the drawing of the first rectangle is erased.
How can I solve this problem? Here is the code that I currently have:
int X, Y;
Graphics G;
Rectangle Rec;
int UpX, UpY, DwX, DwY;
public Form1()
{
InitializeComponent();
//G = panel1.CreateGraphics();
//Rec = new Rectangle(X, Y, panel1.Width, panel1.Height);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
UpX = e.X;
UpY = e.Y;
//Rec = new Rectangle(e.X, e.Y, 0, 0);
//this.Invalidate();
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
DwX = e.X;
DwY = e.Y;
Rec = new Rectangle(UpX, UpY, DwX - UpX, DwY - UpY);
Graphics G = pictureBox1.CreateGraphics();
using (Pen pen = new Pen(Color.Red, 2))
{
G.DrawRectangle(pen, Rec);
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// Draws the rectangle as the mouse moves
Rec = new Rectangle(UpX, UpY, e.X - UpX, e.Y - UpY);
Graphics G = pictureBox1.CreateGraphics();
using (Pen pen = new Pen(Color.Red, 2))
{
G.DrawRectangle(pen, Rec);
}
G.Save();
pictureBox1.SuspendLayout();
pictureBox1.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
pictureBox1.Update();
}
The reason why your drawings are getting erased is because you're drawing into a Graphics object you obtained by calling the CreateGraphics method. In particular, this line of your code is incorrect:
Graphics G = pictureBox1.CreateGraphics();
As you've discovered, whenever the form is repainted (which happens when it is maximized, minimized, covered by another object on the screen, or in a number of other possible situations), everything that you've drawn into that temporary Graphics object is lost. The form completely repaints itself with its internal painting logic; it's completely forgotten about what you temporarily drew on top of it.
The correct way to draw persistent images in WinForms is to override the OnPaint method of the control that you want to draw onto (or, you could also handle the Paint event). So, if you wanted to paint onto your form, you would place your drawing code into the following method:
protected override void OnPaint(PaintEventArgs e)
{
// Call the base class first
base.OnPaint(e);
// Then insert your custom drawing code
Rec = new Rectangle(UpX, UpY, DwX - UpX, DwY - UpY);
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, Rec);
}
}
And to trigger a re-paint, you just call the Invalidate method in any of the mouse events (MouseDown, MouseMove, and MouseUp):
this.Invalidate();
Note, however, that there's absolutely no reason to call the Update method in the Paint event handler. All that calling the Update method does is force the control to repaint itself. But that is already happening when the Paint event gets raised!
Related
I am creating a Graphics Form where objects with coordinates x,y are being drawn into the Graphics. It works properly for small x and y, but when I want to draw them in different place (f.e. x = 500, y = 300) they disappear.
public WindowHandler()
{
dc = this.CreateGraphics();
this.Size = new Size(sizeX, sizeY); // 800x600
startSimulation = new Button
{
// button properties
};
this.Controls.Add(startSimulation);
startSimulation.Click += new EventHandler(StartSimulationClick);
}
private void CreationsMethods()
{
creations.PaintAllAnimals(dc);
}
public void PaintAllAnimals(Graphics g)
{
foreach (var animal in ecoStructure.world.animals)
{
animal.PaintAnimal(g);
}
}
public void PaintAnimal(Graphics graphics)
{
Rectangle rectangle = new Rectangle(x, y, 3, 3);
Pen pen = new Pen(colour);
graphics.DrawRectangle(pen, rectangle);
graphics.FillRectangle(colour, rectangle);
}
I want to put all the objects onto the window. Is there any way to make the Graphics "bigger"? Do I need to make another one? Or should I use different tool to draw rectangles?
Thanks to #Chris Dunaway for posting an answer in comment.
So I deleted the CreateCraphics, and instead of that i am now using an OnPaint method. It works slowly, but works. So I will try to make it as fast as i can. For now, I just created this. NextStepClick is how I use the OnPaint to paint the rectangles.
private void CreationsMethods(object sender, PaintEventArgs e)
{
dc = e.Graphics;
base.OnPaint(e);
creations.PaintAllAnimals(dc);
}
private void NextStepClick(object sender, EventArgs e)
{
this.Refresh();
picBox.Paint += new System.Windows.Forms.PaintEventHandler(CreationsMethods);
}
Trying to draw a shape over existing panels for a good while, but by now out of ideas. Could somebody help me out, please? It ends up always behind the panels (and pictureBox /the grey one/). I tried 3 different ways, whithout success. this is my code:
namespace DrawingOnFront
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel11_MouseClick(object sender, MouseEventArgs e)
{
DrawIt(90, 70);
}
private void DrawIt(int x, int y)
{
Rectangle Circle = new Rectangle(x,y,40,40);
SolidBrush Red = new SolidBrush(Color.Red);
Graphics g = this.CreateGraphics();
g.FillEllipse(Red, Circle);
/*
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(bmp);
int width = pictureBox1.Width /4;
int height = pictureBox1.Height /2;
int diameter = Math.Min(width, height);
g.FillEllipse(Red, x, y, width, height);
pictureBox1.Image = bmp;
*/
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Graphics g = e.Graphics)
{
Rectangle Circle = ClientRectangle;
Circle.Location = new Point(100, 60);
Circle.Size = new Size(40, 40);
using (SolidBrush Green = new SolidBrush(Color.Green))
{
g.FillEllipse(Green, Circle);
}
}
}
}
}
Sorry for this basic lama question, probably for most of you it is very easy, I am still learning it. Thanks a lot in advance.
My comments above apply. Here is an example of how to draw onto each control and the form separately:
We best have a common drawing routine that we can call from the Paint event of each participating element, in our case a Panel, a PictureBox and the Form.
The trick is for all nested elements to draw the circle shifted by their own location. To do so we pass these things into the drawing routine:
a valid Graphics object. We get it from the Paint events.
and a reference to the control; we use it to offset the drawing on each control (except the form) with Graphics.TranslateTransform..:
Result:
As you can see it looks as if we painted one circle over all elements but actually we drew three circles, each onto one element..:
private void canvasForm_Paint(object sender, PaintEventArgs e)
{
draw(sender as Control, e.Graphics);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
draw(sender as Control, e.Graphics);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
draw(sender as Control, e.Graphics);
}
private void draw(Control ctl, Graphics g)
{
Rectangle r = new Rectangle(200, 100, 75, 75);
if (ctl != canvasForm) g.TranslateTransform(-ctl.Left, -ctl.Top);
g.FillEllipse(Brushes.Green, r);
g.ResetTransform();
}
Note that the same result could be created with three calls, one FillRectangle, one DrawImage and one FillEllipse :-)
This question already has answers here:
Draw a rectangle on mouse click
(4 answers)
Closed 7 years ago.
So I've been trying lately to make a paint application to practice C#.
My problem for the past 2 days is in the creation of rectangles.
I made a panel so all the drawing are going there. The user selects the shape he wants to draw using a menu and he can start drawing with the mouse.
I encounter 2 problems which are the following:
1) Even though my starting point was inside the panel, I moved the mouse and went outside the panel and the rectangle was drawn outside the panel as shown in the picture below.
2) After I create this rectangle and I try to draw another, the previous one is deleted. So in a way I can't draw 2 rectangles at once.
Here's a part of my source code.
Graphics mygraphics;
Pen lPen = new Pen(Color.Black); //Left Pen
Pen rPen = new Pen(Color.White); //Right pen
Point sp = new Point(0, 0);
private bool isRectangle;
private bool isLeft, isRight; //isLeft -- Left Click, isRight -- Right Click
private void drawPanel_MouseMove(object sender, MouseEventArgs e)
{
if (isRectangle == true)
{
if (e.Button == MouseButtons.Left)
{
isLeft = true;
Point p = e.Location;
int x = Math.Min(sp.X, p.X);
int y = Math.Min(sp.Y, p.Y);
int w = Math.Abs(p.X - sp.X);
int h = Math.Abs(p.Y - sp.Y);
mRect = new Rectangle(x, y, w, h);
this.Invalidate();
}
}
}
private void drawPanel_MouseDown(object sender, MouseEventArgs e)
{
sp = e.Location;
}
private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
isLeft = false;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawRectangle(lPen, mRect);
}
What I want to accomplish is my rectangles not getting deleted after I try to draw another one and to draw them inside the panel.
What do you guys suggest?
Here are the minimal changes I suggest:
List<Rectangle> rectangles = new List<Rectangle>();
Rectangle mRect = Rectangle.Empty;
private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
isLeft = false;
rectangles.Add(mRect);
mRect = Rectangle.Empty;
drawPanel.Invalidate();
}
private void drawPanel_Paint(object sender, PaintEventArgs e)
{
foreach (Rectangle rect in rectangles) e.Graphics.DrawRectangle(lPen, rect );
e.Graphics.DrawRectangle(Pens.Orange, mRect); // or whatever..
}
Note that the Paint event now is the one of the Panel. Do make sure you hook it up with the Panel!!
Also note how I draw the current rectangle mRect in a different color than the list of the other rectangles; this is of course optional..
I have an application which uses the mouse to free-draw a rectangle on a picbox image. However the rectangle only shows up behind the picbox, rather than on top of it. Is there a property i can set which can fix this? (show rect on top of picbox image rather than behind it). Here is the code:
System.Drawing.Graphics picboxGraphics;
bool mDown = false;
int mouseX;
int mouseY;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
mDown = true;
mouseX = e.X;
mouseY = e.Y;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (mDown == true)
{
this.Refresh();
Pen drawPen = new Pen(Color.Red, 5);
int width = e.X - mouseX, height = e.Y - mouseY;
Rectangle rect = new Rectangle(mouseX, mouseY, width * Math.Sign(width), height * Math.Sign(height));
picboxGraphics = this.CreateGraphics();
picboxGraphics.DrawRectangle(drawPen, rect);
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
mDown = false;
}
You creating graphics from form which is behind the picbox
you can create graphics from picbox's image and draw someting. But if you want layer system you can draw your thins on an transparent image and combine them. with this vay you can make an undo or delete layer system.
There are several problems in your code: dispose, global variable and wrong control to create graphics from. Make it this way:
using(var graphics = (sender as Control).CreateGraphics())
graphics.DrawRectangle(drawPen, rect);
But honestly, you have to organize it differently (assuming you are going to mimik Paint):
create new object (when mouse is down)
in Paint event draw object (if any)
during mouse move event, update edited object properties and call Invalidate
when you minimize/restore your form, the object will be still there (while in your example, it will get lost).
You can support List of objects to have storage for many rectangles and add history support (as TC Alper Tokcan answer suggesting) to at least Undo last object.
I'm very new in C#
I want a rectangle to appear wherever there's a mouseclick on a panel
Here's my code:
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
int x = e.Location.X;
int y = e.Location.Y;
if (radioButton1.Checked == false)
{
((Panel)sender).Invalidate(new Rectangle(x * 40, y * 40, 40, 40));
}
else if (radioButton2.Checked == true)
{
return;
}
}
I wonder how to change the color of the rectangle?
Please advise me if my code is wrong.
Thanks.
Your drawing should be performed in the panel's Paint event handler. When you click the panel, create the rectangle (in the MouseUp event of the panel) and store it in a collection of rectangles (such as a dictionary). Then refresh the panel. In the panel's Paint event, draw all the rectangles. Here is a simple example:
Dictionary<Color, List<Rectangle>> rectangles = new Dictionary<Color, List<Rectangle>>();
private void panel1_Paint(object sender, PaintEventArgs e)
{
//The key value for the dictionary is the color to use to paint with, so loop through all the keys (colors)
foreach (var rectKey in rectangles.Keys)
{
using (var pen = new Pen(rectKey)) //Create the pen used to draw the rectangle (using statement makes sure the pen is disposed)
{
//Draws all rectangles for the current color
//Note that we're using the Graphics object that is passed into the event handler.
e.Graphics.DrawRectangles(pen, rectangles[rectKey].ToArray());
}
}
}
//This method just adds the rectangle to the collection.
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Color c = getSelectedColor(); //Gets a color for which to draw the rectangle
//Adds the rectangle using the color as the key for the dictionary
if (!rectangles.ContainsKey(c))
{
rectangles.Add(c, new List<Rectangle>());
}
rectangles[c].Add(new Rectangle(e.Location.X - 12, e.Location.Y - 12, 25, 25)); //Adds the rectangle to the collection
}
//Make the panel repaint itself.
panel1.Refresh();
}
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
Graphics g = panel1.CreateGraphics();
g.DrawRectangle(new Pen(Brushes.Black),
new Rectangle(new Point(e.X, e.Y), new
Size(100, 100)));
}
you can change the color in Brushes.Black part of code, change it as you desire