I am new to c#(using visual c# 2010), and was tying to make a simple game, it will have bouncing ball type thing,
I used graphics fillellipse to make a ball, now i have this code with me,
protected override void OnPaint( PaintEventArgs e)
{
//System.Drawing.Graphics gobj;
gobj = this.CreateGraphics();
Pen pen = new Pen(System.Drawing.Color.LightSkyBlue, 6);
SolidBrush brush = new SolidBrush(System.Drawing.Color.Magenta);
Rectangle myRectangle = new Rectangle((PointToClient(Cursor.Position).X), PointToClient(Cursor.Position).Y, 250, 200);
gobj.DrawRectangle(pen, myRectangle);
gobj.FillEllipse(brush, myRectangle);
}
when i run this code, i keep on getting many circles and rectangles, popping under a section of screen only, but shouldn't it draw just a single circle??
Please help me understand this??
You drawing rectangle with DrawRectangle method and then circle with FillEllipse, you need to use just FillEllipse. And like Mikant mentioned you don't need to create graphics - use e.Graphics. Here is code:
protected override void OnPaint(PaintEventArgs e)
{
SolidBrush brush = new SolidBrush(System.Drawing.Color.Magenta);
e.Graphics.FillEllipse(brush, (this.Height / 2) - 40, (this.Width / 2) - 40, 80, 80);
}
This draws circle in form centre.
Good luck in experimenting and learning!
This should really be a comment, but I don't have high enough privilege yet!
I would get into the good habit of using the using statement when dealing withtypes that use unmanaged resources such as Pen and Font. It will ensure the correct use of IDisposable objects.
just remember never to use CreateGraphics method (especially inside OnPaint). replace all of your gobj with e.Graphics and enjoy
Related
I'm New in c sharp, i'm trying to make a circular button. the code below is making a ellipse for me but it is not looking smooth, also it is having partially hidden lines at right and bottom as shown in image
class ButtonEllipse: Button
{
protected override void OnPaint(PaintEventArgs e)
{
GraphicsPath graphics = new GraphicsPath();
Rectangle myEllipse = new Rectangle(0, 0, this.ClientSize.Width,this.ClientSize.Height);
graphics.AddEllipse(myEllipse);
Pen myPen = new Pen(Color.Black, 2);
this.Region = new System.Drawing.Region(graphics);
base.OnPaint(e);
}
}
can you please guide me how to get a exact and smooth circular button.
Try setting graphics.SmoothingMode = SmoothingMode.AntiAlias; Read more about antialiazing.
You should perhaps also paint the button graphics directly rather than using the Region. See DrawEllipse and FillEllipse.
I am new to drawing and paints in c# & I am trying to make a simple program it has 3 intersecting circles (A,B,C). What i want to do is paint a certain (according to result I get).
For example: If I get 1 as a result I want to fill the yellow bordered region, if I get 4 I want to fill green bordered region and so on.
My Code to draw these circles:
private void button1_Click(object sender, EventArgs e)
{
Graphics A = this.CreateGraphics();
Graphics B = this.CreateGraphics();
Graphics C = this.CreateGraphics();
Pen Bluepen = new Pen(Color.Blue, 2);
Pen RedPen = new Pen(Color.Red, 2);
Pen BlackPen = new Pen(Color.Black, 2);
A.DrawEllipse(Bluepen,100, 100, 150, 150);
B.DrawEllipse(RedPen, 195, 100, 150, 150);
C.DrawEllipse(BlackPen, 145, 190, 150, 150);
}
Since you are new to this topic I have to tell you: This is a lot harder that one would hope for.
Three solutions come to mind:
Construct a GraphicsPath you could fill from three Arcs. To calculate the arcs you need the rectangles you have but also the sweeping angle and also the starting angle. This will take quite some math..
After having drawn into a Bitmap you could floodfill the area you want to color. This will only work for bitamps from which you can extract the current color of each pixel, not for drawing onto controls..
The simplest way it still a bit involved, but only mildly so
Solution 3 (Create a Region and fill it)
You can use all sorts of set operations to combine areas called Regions. And you can construct a Region from a GraphicsPath. And you can construct a GraphicsPath by adding an ellipse. And you can clip the drawing area of a Graphics object to a Region.
Let's try:
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle r1 = new Rectangle(100, 100, 150, 150);
Rectangle r2 = new Rectangle(195, 100, 150, 150);
Rectangle r3 = new Rectangle(145, 190, 150, 150);
GraphicsPath gp1 = new GraphicsPath();
GraphicsPath gp2 = new GraphicsPath();
GraphicsPath gp3 = new GraphicsPath();
gp1.AddEllipse(r1);
gp2.AddEllipse(r2);
gp3.AddEllipse(r3);
Region r_1 = new Region(gp1);
Region r_2 = new Region(gp2);
Region r_3 = new Region(gp3);
r_1.Intersect(r_2); // just two of five..
r_1.Exclude(r_3); // set operations supported!
g.SetClip(r_1, CombineMode.Replace);
g.Clear(Color.Magenta); // fill the remaining region
g.ResetClip();
g.DrawEllipse(Pens.Red, r1);
g.DrawEllipse(Pens.Blue, r2);
g.DrawEllipse(Pens.Green, r3);
// finally dispose of all Regions and GraphicsPaths!!
r_1.Dispose();
gp1.Dispose();
.....
}
Do note that the region operations change the current region; if you want to fill more areas you need to restore the changed region!
Also note that I draw where any persistent drawing belongs: In the Paint event and that I use its e.Graphics object..
GraphicsPaths as Regions are GDI objects and should be disposed off!
Notes on solution 1 (Create a GraphicsPath by Math)
The full math is rather involved. By making a few assumptions the task can be greatly simplified: Let's assume the circles have the same size. Also that we first look at two circles only, with the same y-position. Finally that the circles form a symmetrical figure. (Which btw they don't: the red circle should have x=190 and the green one y=186,45..)
Getting the two intersection points as well as the sweeping angle is not so hard.
Next one can rotate the two points twice around the center of the whole figure by 120° using a Matrix; see here for an example. Now we have six points; we still need the smaller sweeping angle, which is also found with simple math.
Finally we can construct all 12 (!) GraphicsPaths from the 12 arcs and combine them at will.
The good part is that we can both fill and draw those paths. But, the code is rather extensive..
Notes on solution 2 (floodfill)
While you can't floodfill directly on a control you can prepare the result in a bitmap and then display that image on the control with Graphics.DrawImage.
For an example of coding a floodfill see this post!
I am trying to draw the YinYang symbol on C# windows Form Application. So far, I drew the big outer circle and the two innner circles.
I need help on drawing the curve part that runs down the middle of the circle
Also, how would I fill in the small circle and the other half of the circle to be black.
Also, it is possible to draw this without having to have a button (see code).
Here is a snippet of my code:
private void button1_Click(object sender, EventArgs e)
{
Graphics myGraphics = base.CreateGraphics();
Pen myPen = new Pen(Color.Black);
SolidBrush mySolidBrush = new SolidBrush(Color.Black);
myGraphics.DrawEllipse(myPen, 50,50, 150, 150);
Graphics innerCircle = base.CreateGraphics();
Pen myPen2 = new Pen(Color.Black);
SolidBrush mySolidBrush2 = new SolidBrush(Color.Black);
myGraphics.DrawEllipse(myPen, 118, 75, 20, 20);
Graphics innerCircle2 = base.CreateGraphics();
Pen myPen3 = new Pen(Color.Black);
SolidBrush mySolidBrush3 = new SolidBrush(Color.Black);
myGraphics.DrawEllipse(myPen, 118, 150, 20, 20);
}
You do not have to draw a curve, geometry of ying and yang is so beautiful that it lets you draw it only using circles.
Sorry for my paint skills, but I think you know what I mean by this pic. You said
I drew the big outer circle and the two innner circles.
So use this knowledge again without thinking about curves
Is there a method to draw on the panel in c# which not redraw what i've drawn? E.g. when I use refresh() or Invalidate() alway redraw me it, but I need something what not. :(
I have a simple Photoshop-made grid and i would like to use it as progress bar, i need to draw round ellipses from 1 to 100 (then probably about 100 times in x time).
If I use System.Graphic I have not persistent result.
Then I found the code to use the PaintEventArgs method by inserting instructions in the Paint Event of the form.
Unfortunately in my mind this is not a solution because I need to draw only when I need and only where I want.... in other word I need a simple Function able to draw desired ellipses when I need...
I tried also to override the OnPaint-base but I really don't understand how to use it and if may help to reach my goal.
Here some code:
With the paint event:
private void Main_Paint(object sender, PaintEventArgs e)
{
// Create pen.
Pen blackPen = new Pen(Color.Yellow, 3);
// Create rectangle for ellipse.
Rectangle rect = new Rectangle(355, 282, 9, 9);
e.Graphics.DrawEllipse(blackPen, rect);
}
With the Graphic mode:
private void lbl_help_Click(object sender, EventArgs e)
{
//SetStatus("BURNING PROCESS COMPLETED SUCCESSFULLY");
Graphics g = this.CreateGraphics();
// Create pen.
Pen blackPen = new Pen(Color.Yellow, 3);
// Create rectangle for ellipse.
Rectangle rect = new Rectangle(355, 282, 9, 9);
// Draw ellipse to screen.
g.DrawEllipse(blackPen, rect);
System.Threading.Thread.Sleep(3000);
}
And this one I found to override OnPaint(), but I really don't know how to use it, how to override the form-paint event or how to call it only when needed and passing values:
private void lbl_help_Click(object sender, EventArgs e)
{
//SetStatus("BURNING PROCESS COMPLETED SUCCESSFULLY",);
Graphics g = this.CreateGraphics();
// Create pen.
Pen blackPen = new Pen(Color.Yellow, 3);
// Create rectangle for ellipse.
Rectangle rect = new Rectangle(355, 282, 9, 9);
// Draw ellipse to screen.
g.DrawEllipse(blackPen, rect);
System.Threading.Thread.Sleep(3000);
}
Something other other:
I imagine if I use variables to store the percentage and call a paint-refresh of the form (maybe invalidate?) to update the result should work but I will lose any sort of animation, elsewhere I come-back to a non persistent state again... I need to use the grid as a progress bar, adding circles only at desired time, without losing the back drawings...
The grid I need to fill is very simple, here a screenshot:
Sry I should not post image for the reputation (i'm a new user!), here the link
EDIT:
I solved the smoothing problem (at least with the Graphic Mode):
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
Can I delete the old rectangle which I have drawn and draw a new rectangle?
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
Graphics g = this.panel1.CreateGraphics();
Pen pen = new Pen(Color.Black, 2);
g.DrawRectangle(pen, 100,100, 100, 200);
g.dispose();
}
No, you cannot "delete" something that's already been drawn. You can overwrite it with something else, but drawing with Graphics objects is like painting in real-life: once the paint is dry, you can only paint over it with another colour, you can't "erase" it.
You probably shouldn't be drawing things in response to a MouseClick, either. It's best to only draw things in response to a Paint event. What I would do in this situation is add a Rectangle structure to a list on the MouseClick and then call panel1.Invalidate() to ask it to redraw itself. Then in the Paint event for the panel, do the drawing there.
This will kill two birds with one stone, because you will be able to "erase" thing by simply removing them from the list of stuff to draw.
This is usually done by maintaining a collection of objects you want drawn. The mouse click should update this collection and then tell the window (or the affect region) to refresh. This has the enormous advantage of preserving whatever you've drawn if the window is moved off-screen, hidden behind other windows, minimized, etc.
For a rudimentary solution, create a hierarchy of drawable shape types derived from a common abstract Shape class, and use, e.g., a List for the collection. The base Shape class will have an abstract Draw method that the derived classes override.
For a more industrial-strength solution, look around for 2-D scene graphs.
One can use Graphics.Save() and Graphics.Restore(state) methods for that. For example:
private void SaveRestore2(PaintEventArgs e)
{
// Translate transformation matrix.
e.Graphics.TranslateTransform(100, 0);
// Save translated graphics state.
GraphicsState transState = e.Graphics.Save();
// Reset transformation matrix to identity and fill rectangle.
e.Graphics.ResetTransform();
e.Graphics.FillRectangle(new SolidBrush(Color.Red), 0, 0, 100, 100);
// Restore graphics state to translated state and fill second
// rectangle.
e.Graphics.Restore(transState);
e.Graphics.FillRectangle(new SolidBrush(Color.Blue), 0, 0, 100, 100);
}
http://msdn.microsoft.com/en-us/library/system.drawing.graphics.restore.aspx
Also, depending on the application, you might look at using DrawReversibleFrame. You can change the rectangle location by calling the Offset method.
Instead of calling g.DrawRectangle(pen, 100,100, 100, 200); , maintain the rectangle as a object which will be drawn by the graphics object. Each time you will update this rectangle object with new one and graphics object will draw the new one.
The refresh should clear the old rectangle and graphics will draw the new one.
You can just use VisualBasic PowerPacks, it is included with my version of Visual Studio 2008
Here's a sample code that will draw a rectangle over a TextBox, i.e. I am giving it a custom border
Dim x = TextBox1.Location.X
Dim y = TextBox1.Location.Y
Dim width = TextBox1.Width
Dim height = TextBox1.Height
Dim ShapeContainer1 As New Microsoft.VisualBasic.PowerPacks.ShapeContainer
Me.Controls.Add(ShapeContainer1)
Dim RectangleShape1 As New Microsoft.VisualBasic.PowerPacks.RectangleShape
ShapeContainer1.Shapes.AddRange(New Microsoft.VisualBasic.PowerPacks.Shape() {RectangleShape1})
RectangleShape1.Location = New System.Drawing.Point(x - 1, y - 1)
RectangleShape1.Size = New System.Drawing.Size(width + 1, height + 1)
RectangleShape1.BorderColor = Color.MistyRose
ShapeContainer1.Refresh()
Code is self describing but if you'd have any problem, just leave a message...
I think using DrawReversibleFrame is the right solution.
The first call draw the rectangle, the second call undraw it and so on.
Here is a sample code, a clic on the button will make the rectangle appear/disapper.
Rectangle pRect = new Rectangle(10, 10, 20, 20);
private void rect_Click(object sender, EventArgs e)
{
ControlPaint.DrawReversibleFrame(pRect, this.BackColor, FrameStyle.Thick);
}