Why after drawing circles their colors change? - c#

Why after drawing circles their colors change? , in fact, I draw circles but my problem is that after every time double click, the color of next circles change from blue to the background color.
public Form1()
{
InitializeComponent();
pictureBox1.Paint += new PaintEventHandler(pic_Paint);
}
public Point positionCursor { get; set; }
private List<Point> points = new List<Point>();
public int circleNumber { get; set; }
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
positionCursor = this.PointToClient(new Point(Cursor.Position.X - 25, Cursor.Position.Y - 25));
points.Add(positionCursor);
pictureBox1.Invalidate();
}
private void pic_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
foreach (Point pt in points)
{
Pen p = new Pen(Color.Tomato, 2);
g.FillEllipse(Brushes.Blue, positionCursor.X, positionCursor.Y, 20, 20);
g.DrawEllipse(p, pt.X, pt.Y, 20, 20);
p.Dispose();
}
}

You're drawing the ellipses correctly, but you always fill only one of them (the last one added, at the cursor's position).
// This is ok
g.DrawEllipse(p, pt.X, pt.Y, 20, 20);
// You should use pt.X and pt.Y here
g.FillEllipse(Brushes.Blue, positionCursor.X, positionCursor.Y, 20, 20);

change pic_Paint as below
private void pic_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
foreach (Point pt in points)
{
Pen p = new Pen(Color.Tomato, 2);
g.DrawEllipse(p, pt.X, pt.Y, 20, 20);
g.FillEllipse(Brushes.Blue, pt.X, pt.Y, 20, 20);
p.Dispose();
}
}

Related

How to draw a new square every time "DrawObject()" is in the file

So I have made a file reader and it reads every line in the file, i have a few commands that it will read and it works but this one wont work
When the file says "DrawObject()"
it should do this:
if (line.Contains("DrawObject()"))
{
r = new Rectangle();
r.Width = 32;
r.Height = 32;
Invalidate();
}
And it does draw the rectangle because in the paint event I put:
private void TestScript_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
g.Clear(Color.White);
if (dp == true)
{
g.FillRectangle(Brushes.Blue, x, y, 32, 32);
}
g.FillRectangle(Brushes.Blue, r);
DoubleBuffered = true;
}
and it draws the square (g.FillRectangle(Brushes.Blue, r))
but i want to be able to draw multiple squares
and every time a square is drawn the player can change the squares X and Y values
These are the X and Y values the player can change in the file:
if (line.Contains("ObjectX>"))
{
r.X = Convert.ToInt32(line.Substring(9));
}
if (line.Contains("ObjectY>"))
{
r.Y = Convert.ToInt32(line.Substring(9));
}
EDIT OF CODE:
if (line.Contains("DrawObject()"))
{
rectangles.Add(new Rectangle() { Width = 32, Height = 32 } );
Invalidate();
}
if (line.Contains("ObjectX>"))
{
Rectangle r = rectangles.Last();
r.X = Convert.ToInt32(line.Substring(9));
Invalidate();
}
if (line.Contains("ObjectY>"))
{
Rectangle r = rectangles.Last();
r.Y = Convert.ToInt32(line.Substring(9));
Invalidate();
}
If you want to draw multiple rectangles you need to "store" them all and not only the last one - e.g. like this:
// instead of "private Rectangle r" I assume you have
private List<Rectangle> rectangles = new List<Rectangle>();
And then during parsing:
if (line.Contains("DrawObject()"))
{
rectangles.Add(new Rectangle() { Width = 32, Height = 32 });
Invalidate();
}
...and painting:
private void TestScript_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
g.Clear(Color.White);
if (dp == true)
{
g.FillRectangle(Brushes.Blue, x, y, 32, 32);
}
foreach (Rectangle r in rectangles)
g.FillRectangle(Brushes.Blue, r);
DoubleBuffered = true;
}
...and to move the last one:
if (line.Contains("ObjectX>"))
{
Rectangle r = rectangles.Last();
r.X = Convert.ToInt32(line.Substring(9));
}
if (line.Contains("ObjectY>"))
{
Rectangle r = rectangles.Last();
r.Y = Convert.ToInt32(line.Substring(9));
}
NOTE: You should check here if there is already a rectangle set to avoid an error.

Convert PictureBox Selection Rectangle according to SizeMode

I have two PictureBoxes pbOriginal and pbFace. After Selecting a "face" from an image in pbOriginal I clone the rectangle selection and place it into pbFace.
However, Because pbOriginal is using SelectionMode=Stretch the actual area being copied is not the same as the area being selected.
How do I convert the coordinates of the Rectangle so that they truly reflect the coordinates of the Stretched Image?
Here is an example that draws the second rectangle right along as you draw the first one..:
Point mDown = Point.Empty;
Point mCurr = Point.Empty;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{ mDown = e.Location; }
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{ mCurr = e.Location; pictureBox1.Invalidate(); }
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Rectangle r = new Rectangle(mDown.X, mDown.Y, mCurr.X - mDown.X, mCurr.Y - mDown.Y);
e.Graphics.DrawRectangle(Pens.Orange, r);
pictureBox2.Invalidate();
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
if (pictureBox2.Image == null) return;
float stretch1X = 1f * pictureBox1.Image.Width / pictureBox1.ClientSize.Width;
float stretch1Y = 1f * pictureBox1.Image.Height / pictureBox1.ClientSize.Height;
int x = (int)(mDown.X * stretch1X);
int y = (int)(mDown.Y * stretch1Y);
int x2 = (int)(mCurr.X * stretch1X);
int y2 = (int)(mCurr.Y * stretch1Y);
Rectangle r = new Rectangle(x, y, x2 - x, y2 - y);
e.Graphics.DrawRectangle(Pens.Orange, r);
}
Note that it assumes that you are drawing top-left to bottom-right..
If you want to copy the selection you can use the same factors and the same Rectangle as the source for a DrawImage call:
float stretch1X = 1f * pictureBox1.Image.Width / pictureBox1.ClientSize.Width;
float stretch1Y = 1f * pictureBox1.Image.Height / pictureBox1.ClientSize.Height;
Point pt = new Point((int)(mDown.X * stretch1X), (int)(mDown.Y * stretch1Y));
Size sz = new Size((int)((mCurr.X - mDown.X) * stretch1X),
(int)((mCurr.Y - mDown.Y) * stretch1Y));
Rectangle rSrc = new Rectangle(pt, sz);
Rectangle rDest= new Rectangle(Point.Empty, sz);
Bitmap bmp = new Bitmap(sz.Width, sz.Height);
using (Graphics G = Graphics.FromImage(bmp))
G.DrawImage(pictureBox1.Image, rDest, rSrc , GraphicsUnit.Pixel);
pictureBox2.Image = bmp;
You may want to code the MouseUp event to store the finla mCurr position and trgger the copying..

Converting C# Graph into a proper mathematical graph

Recently, I have been working on this graphing system in C#, and I am having problems with the coordinate system. As we all know, C# uses the top left corner as 0,0 coordinates. What I want to accomplish is to make 0 in the middle of the windows form.
Currently, this is what I have...
As you can see, 0,0 is on the top left, making the center of the graph 400. So is there a way to transform the coordinates into a proper mathematical graph coordinate?
I hope I was able to explain this situation well as my English is not very well.
public partial class Form1 : Form
{
public static int _wWidth;
public static int _wHeight;
int mouseX, mouseY;
Point _center = new Point(_wWidth / 2, _wHeight / 2);
public Form1()
{
InitializeComponent();
foreach (Control c in this.Controls)
{
c.MouseDown += ShowMouseDown;
}
this.MouseDown += (s, e) => { this.label3.Text = "{X: " + e.X + " Y:" + e.Y + "}"; mouseX = e.X; mouseY = e.Y; };
}
private void ShowMouseDown(object sender, MouseEventArgs e)
{
var x = e.X + ((Control)sender).Left;
var y = e.Y + ((Control)sender).Top;
this.label3.Text = x + " " + y;
}
public void Form1_Load(object sender, EventArgs e)
{
this.ClientSize = new Size(800, 800);
int windowWidth = this.ClientSize.Width;
int windowHeight = this.ClientSize.Height;
_wWidth = windowWidth;
_wHeight = windowHeight;
button1.Location = new Point(_wWidth - button1.Width,0);
//AllocConsole(); /***** Enable console for debugging *****/
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
public void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
_drawPlain(e);
}
public void _drawPlain(PaintEventArgs e){
Graphics formGraphics = this.CreateGraphics();
for(int x = 0; x < _wHeight; x+=50)
{
e.Graphics.DrawLine(new Pen(Color.FromArgb(80, 75, 75)), new Point(0, x), new Point(_wWidth, x));
Console.ForegroundColor = ConsoleColor.Green; if (x == 20) { Console.Write("X - "); } Console.WriteLine(x);
e.Graphics.DrawString(x.ToString(), new Font("Arial", 10), new SolidBrush(Color.White), new Point(_wWidth/2,x));
}
for (int y = 0; y < _wWidth; y += 50)
{
e.Graphics.DrawLine(new Pen(Color.FromArgb(80, 75, 75)), new Point(y, 0), new Point(y, _wHeight));
Console.ForegroundColor = ConsoleColor.Red; if (y == 20) { Console.Write("Y - "); } Console.WriteLine(y);
int num = y;
e.Graphics.DrawString(num.ToString(), new Font("Arial", 10), new SolidBrush(Color.White), new Point(y, _wHeight/2));
}
e.Graphics.DrawLine(Pens.Green, new Point(0, _wHeight/2), new Point(_wWidth, _wHeight/2));
e.Graphics.DrawLine(Pens.DarkRed, new Point(_wWidth/2, 0), new Point(_wWidth/2, _wHeight));
//e.Graphics.DrawString("0", new Font("Arial", 10), new SolidBrush(Color.White), new Point(_wWidth / 2, _wHeight / 2));
//// Create pen.
//Pen blackPen = new Pen(Color.Black, 3);
//// Create points that define polygon.
//Point point1 = new Point(100, 200);
//Point point2 = new Point(300, 200);
//Point point3 = new Point(200, 50);
//Point[] curvePoints =
// {
// point1,
// point2,
// point3
// };
//// Draw polygon to screen.
//e.Graphics.DrawPolygon(blackPen, curvePoints);
}
public static int _yCellCount()
{
int _cell = 0;
for (int i = 0; i < 20; i++)
{
_cell++;
}
return _cell;
}
private void button1_Click(object sender, EventArgs e)
{
this.Refresh();
}
private void Form1_Click(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawLine(Pens.Yellow,new Point(mouseX,mouseY),new Point(_wWidth/2,400));
}
}

GraphicsPath eliminate text border

I'm using the GraphicsPath object to draw text in a rectangle. The rectangle is larger than the text, and I want to draw the text in any of the rectangle's corners, and also at the center of its edges.
The problem I have is that when I draw the path, a border is being left around the source rectangle. I want to be able to eliminate that border and make the text touch its bounding rectangle.
Here is the code I have:
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
Rectangle textRect = new Rectangle(100, 100, 150, 150);
Font f = new Font("Arial", 16);
float emSize = f.Height * f.FontFamily.GetCellAscent(f.Style) /
f.FontFamily.GetEmHeight(f.Style);
foreach (StringAlignment lineAlignment in Enum.GetValues(typeof(StringAlignment)))
{
foreach (StringAlignment alignment in Enum.GetValues(typeof(StringAlignment)))
{
StringFormat sf = new StringFormat() { LineAlignment = lineAlignment, Alignment = alignment };
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddString("txt", f.FontFamily, (int)f.Style, emSize, textRect, sf);
RectangleF bounds = gp.GetBounds();
g.FillPath(Brushes.Black, gp);
g.DrawRectangle(Pens.Red, Rectangle.Round(bounds));
}
}
}
g.DrawRectangle(Pens.Blue, textRect);
}
And here is the result:
Basically, I want the red rectangles (and the text they contain) to touch the blue rectangle, and to eliminate the border between them. Also, I need to use the GraphicsPath and not DrawString.
I ended up writing a helper method to calculate the offset of the rectangles and translate the text before drawing it. Here is the method I wrote:
private PointF FixAlignment(RectangleF parentRect, RectangleF childRect,
StringAlignment lineAlignment, StringAlignment alignment)
{
float xOffset = 0;
float yOffset = 0;
switch (lineAlignment)
{
case StringAlignment.Near:
yOffset = parentRect.Top - childRect.Top;
break;
case StringAlignment.Far:
yOffset = parentRect.Bottom - childRect.Bottom;
break;
}
switch (alignment)
{
case StringAlignment.Near:
xOffset = parentRect.Left - childRect.Left;
break;
case StringAlignment.Far:
xOffset = parentRect.Right - childRect.Right;
break;
}
return new PointF(xOffset, yOffset);
}
I used it in the Form1_Paint method like this:
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
Rectangle textRect = new Rectangle(100, 100, 150, 150);
Font f = new Font("Arial", 16);
float emSize = f.Height * f.FontFamily.GetCellAscent(f.Style) /
f.FontFamily.GetEmHeight(f.Style);
foreach (StringAlignment lineAlignment in Enum.GetValues(typeof(StringAlignment)))
{
foreach (StringAlignment alignment in Enum.GetValues(typeof(StringAlignment)))
{
StringFormat sf = new StringFormat() { LineAlignment = lineAlignment, Alignment = alignment };
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddString("txt", f.FontFamily, (int)f.Style, emSize, textRect, sf);
RectangleF bounds = gp.GetBounds();
// Calculate the rectangle offset
PointF offset = FixAlignment(textRect, bounds, lineAlignment, alignment);
// Translate using the offset
g.TranslateTransform(offset.X, offset.Y);
g.FillPath(Brushes.Black, gp);
g.DrawRectangle(Pens.Red, Rectangle.Round(bounds));
// Translate back to the original location
g.TranslateTransform(-offset.X, -offset.Y);
}
}
}
g.DrawRectangle(Pens.Blue, textRect);
}
Here is the result:

Draw a polyline with a linear gradient along it's stroke width in GDI+

Is it possible to draw a polyline that has a linear gradient along it's stroke width? That is, if you have a gradient with black on 0 and 100% and white 50%, the black will always be on the edge of the line and the white in the middle, regardless of the angle. Think of it as some sort of 3D pipes. Of course, the line will have a stroke width of at least 10px. All the questions here ask how to fill a line between it's ends. I'm definitely not interested in that. I'm working in C# using GDI+, can be any .NET version.
I think this is what you want:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode=SmoothingMode.AntiAlias;
DrawPipe(e.Graphics, 10f, new PointF(10, 10), new PointF(250, 80), Color.White, Color.Black);
DrawPipe(e.Graphics, 10f, new PointF(15, 60), new PointF(280, 120), Color.BlueViolet, Color.Black);
}
private void DrawPipe(Graphics g, float width, PointF p1, PointF p2, Color mid_color, Color edge_color)
{
SizeF along=new SizeF(p2.X-p1.X, p2.Y-p1.Y);
float mag=(float)Math.Sqrt(along.Width*along.Width+along.Height*along.Height);
along=new SizeF(along.Width/mag, along.Height/mag);
SizeF perp=new SizeF(-along.Height, along.Width);
PointF p1L=new PointF(p1.X+width/2*perp.Width, p1.Y+width/2*perp.Height);
PointF p1R=new PointF(p1.X-width/2*perp.Width, p1.Y-width/2*perp.Height);
PointF p2L=new PointF(p2.X+width/2*perp.Width, p2.Y+width/2*perp.Height);
PointF p2R=new PointF(p2.X-width/2*perp.Width, p2.Y-width/2*perp.Height);
GraphicsPath gp=new GraphicsPath();
gp.AddLines(new PointF[] { p1L, p2L, p2R, p1R});
gp.CloseFigure();
Region region=new Region(gp);
using(LinearGradientBrush brush=new LinearGradientBrush(
p1L, p1R, Color.Black, Color.Black))
{
ColorBlend color_blend=new ColorBlend();
color_blend.Colors=new Color[] { edge_color, mid_color, edge_color };
color_blend.Positions=new float[] { 0f, 0.5f, 1f };
brush.InterpolationColors=color_blend;
g.FillRegion(brush, region);
}
}
}
Edit 1
An alternative is to use a PathGradientBrush
GraphicsPath gp = new GraphicsPath();
gp.AddLines(new PointF[] { p1, p1L, p2L, p2, p2R, p1R });
gp.CloseFigure();
Region region = new Region(gp);
using (PathGradientBrush brush = new PathGradientBrush(gp))
{
brush.CenterColor = mid_color;
brush.SurroundColors = new Color[]
{
mid_color, edge_color,edge_color,mid_color,edge_color,edge_color
};
g.FillRegion(brush, region);
}
Edit 2
To make the edges smoother use some alpha transparency:
using(LinearGradientBrush brush=new LinearGradientBrush(
p1L, p1R, Color.Black, Color.Black))
{
ColorBlend color_blend=new ColorBlend();
color_blend.Colors=new Color[] {
Color.FromArgb(0, edge_color), edge_color, mid_color,
edge_color, Color.FromArgb(0, edge_color) };
color_blend.Positions=new float[] { 0f, 0.1f, 0.5f, 0.9f, 1f };
brush.InterpolationColors=color_blend;
g.FillRegion(brush, region);
}
Edit 3
With some artifacts multiple lines are drawing, by rendering circles between then first and then the lines
private void DrawPipes(Graphics g, float width, PointF[] points, Color mid_color, Color edge_color)
{
for (int i = 0; i < points.Length; i++)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(points[i].X - width / 2, points[i].Y - width / 2, width, width);
using (PathGradientBrush brush = new PathGradientBrush(gp))
{
brush.CenterColor = mid_color;
brush.SurroundColors = new Color[] { edge_color };
brush.CenterPoint = points[i];
g.FillPath(brush, gp);
}
}
if (i > 0)
{
DrawPipe(g, width, points[i - 1], points[i], mid_color, edge_color);
}
}
}

Categories

Resources