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. :(
Related
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 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;
I want to draw a line on a panel and then move it as the mouse moves. To do so, I draw the line and when the mouse moves I redraw the line to the new location and remove the previous line by drawing a line with the background color on it. It works fine if I do not use the high quality smoothing mode. But if use high quality smoothing mode, it leave traces on the panel. Does anybody know how to fix this? Thank you.
Here is the code
int x_previous = 0;
int y_previous = 0;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
Pen pen1 = new System.Drawing.Pen(Color.Black, 3);
Pen pen2 = new System.Drawing.Pen(panel1.BackColor, 3);
Graphics g = panel1.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.DrawLine(pen2, new Point(0, 0), new Point(x_previous, y_previous));
g.DrawLine(pen1, new Point(0, 0), new Point(e.Location.X, e.Location.Y));
x_previous = e.Location.X;
y_previous = e.Location.Y;
}
Here is the snapshot with SmoothingMode
Here is the snapshot without SmoothingMode
Instead of drawing a line over a line, the safest option would be to clear the graphics using g.Clear(panel1.BackColor). This will wipe everything off that has been drawn, so that you can safely draw a new line:
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
Pen pen1 = new System.Drawing.Pen(Color.Black, 3);
Pen pen2 = new System.Drawing.Pen(panel1.BackColor, 3);
Graphics g = panel1.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
// Clear the graphics, creating a blank area to draw on
g.Clear(panel1.BackColor);
g.DrawLine(pen1, new Point(0, 0), new Point(e.Location.X, e.Location.Y));
x_previous = e.Location.X;
y_previous = e.Location.Y;
}
Hope this helps!
Instead of drawing the line in the event handler for the mouse movement you should use it to Invalidate the panel and perform the line drawing in a handler for its Paint event. There will be no need to erase the old line.
I haven't used WinForms in a while, so you'll have to forgive me if this doesn't work.
I assume that anti-aliasing has slightly blurred the edges of the line so that the initial line extends slightly further out than the width of the pen. That also means that the edges of the white pen won't be completely opaque when drawing over the black line.
Try increasing the width of the white pen until it completely covers the black, and maybe see if you can leave the Graphics object with lower quality rendering for the white pen, and use the smoothing only for the black pen.
I have a paint program made in C#/GDI+ in which I draw different shapes with interchangeable colors and pen sizes on a panel. I have got the shape-drawing methods working OK, but when it comes to using a free pen (as you would in MS Paint) I have made a method that does the job, just quite ugly (see pic in link).
if (crtanje)
{
debljina = float.Parse(debljina_box.Text);
Graphics gr = Graphics.FromImage(bit);
gr.SmoothingMode = SmoothingMode.HighQuality;
olovka = new Pen(boja, debljina);
gr.DrawLine(olovka, new Point(prethodnoX ?? e.X, prethodnoY ?? e.Y), new Point(e.X, e.Y));
panel1.CreateGraphics().DrawImageUnscaled(bit, new Point(0, 0));
prethodnoX = e.X;
prethodnoY = e.Y;
}
Can this code be fixed to make drawing smoother or should I take some other approach?
the pic
I suppose you could iterate through a for loop and increase it by a very small amount so that it draws points more frequently and makes the line smoother. You could save the current point and calculate the next one, then draw a line between them. That's how you could make it smoother!
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