在不删除以前的圆的情况下在新位置绘制圆?
Draw circle in new position without removing previous circle?
其实我是想在每次双击的时候在新的位置画一个圆圈,而不是在圆圈之前去掉,需要注意的是,我用的是PictureBox
.
public Point postionCursor { get; set; }
List<Point> points = new List<Point>();
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
postionCursor = this.PointToClient(new Point(Cursor.Position.X - 25, Cursor.Position.Y - 25));
points.Add(postionCursor);
pictureBox1.Invalidate();
pictureBox1.Paint += new PaintEventHandler(pic_Paint);
}
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);
SolidBrush myb = new SolidBrush(Color.White);
g.DrawEllipse(p, postionCursor.X, postionCursor.Y, 20, 20);
g.FillEllipse(myb, postionCursor.X, postionCursor.Y, 20, 20);
p.Dispose();
}
}
您没有在 foreach
循环中使用 pt
变量。
foreach (Point pt in points)
{
using(Pen p = new Pen(Color.Tomato, 2))
using(SolidBrush myb = new SolidBrush(Color.White))
{
g.FillEllipse(myb, pt.X, pt.Y, 20, 20);
g.DrawEllipse(p, pt.X, pt.Y, 20, 20);
}
}
在您的代码中,您只是为 points
列表中的每个 Point
覆盖相同位置的圆圈。
此外,正如 Reza 在评论中提到的,您无需在每次单击 PictureBox 时都附加 PaintEventHandler
事件处理程序,只需执行一次即可。
所以我开始思考,然后 Visual Studio-ing,也许我们甚至不需要 foreach 循环。我仍然维护一个列表,这样我们就知道用户点击了哪里,但是不需要循环遍历它并每次都重绘所有内容。
我意识到这不处理基础列表被修改的情况,原始样本也不处理。这是我的整个 Form1 class:
public partial class Form1 : Form
{
private const int CircleDiameter = 20;
private const int PenWidth = 2;
private readonly List<Point> _points = new List<Point>();
public Form1()
{
InitializeComponent();
pictureBox1.Paint += (sender, args) =>
{
_points.ForEach(p => DrawPoint(p, args.Graphics));
};
}
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
var cursorLocation = pictureBox1.PointToClient(Cursor.Position);
_points.Add(cursorLocation);
var circleArea = new Rectangle(
cursorLocation.X - CircleDiameter/2 - PenWidth,
cursorLocation.Y - CircleDiameter/2 - PenWidth,
CircleDiameter + PenWidth*2,
CircleDiameter + PenWidth*2);
pictureBox1.Invalidate(circleArea);
}
private static void DrawPoint(Point point, Graphics graphics)
{
point.X -= CircleDiameter / 2;
point.Y -= CircleDiameter / 2;
using (var pen = new Pen(Color.Tomato, PenWidth))
using (var brush = new SolidBrush(Color.White))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.DrawEllipse(pen, point.X, point.Y, CircleDiameter, CircleDiameter);
graphics.FillEllipse(brush, point.X, point.Y, CircleDiameter, CircleDiameter);
}
}
}
更新 1:
所以我更新了代码以使用具有 foreach 循环的 Paint 事件。但是,我不会在每次添加圆圈时都使(和绘制)无效 - 没有必要这样做。仅通过绘制添加圆意味着控件仅使添加新圆的区域无效并重新绘制。
尝试在 DrawAllPoints 方法上设置断点。您会看到它仅在完全失效操作期间发生,例如最小化和恢复。
更新二:
经过进一步交谈,我同意 Invalidate 方法更优越。代码更新为使用 Invalidate 和一个矩形来使无效。
现在看起来非常像 OP :)
其实我是想在每次双击的时候在新的位置画一个圆圈,而不是在圆圈之前去掉,需要注意的是,我用的是PictureBox
.
public Point postionCursor { get; set; }
List<Point> points = new List<Point>();
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
postionCursor = this.PointToClient(new Point(Cursor.Position.X - 25, Cursor.Position.Y - 25));
points.Add(postionCursor);
pictureBox1.Invalidate();
pictureBox1.Paint += new PaintEventHandler(pic_Paint);
}
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);
SolidBrush myb = new SolidBrush(Color.White);
g.DrawEllipse(p, postionCursor.X, postionCursor.Y, 20, 20);
g.FillEllipse(myb, postionCursor.X, postionCursor.Y, 20, 20);
p.Dispose();
}
}
您没有在 foreach
循环中使用 pt
变量。
foreach (Point pt in points)
{
using(Pen p = new Pen(Color.Tomato, 2))
using(SolidBrush myb = new SolidBrush(Color.White))
{
g.FillEllipse(myb, pt.X, pt.Y, 20, 20);
g.DrawEllipse(p, pt.X, pt.Y, 20, 20);
}
}
在您的代码中,您只是为 points
列表中的每个 Point
覆盖相同位置的圆圈。
此外,正如 Reza 在评论中提到的,您无需在每次单击 PictureBox 时都附加 PaintEventHandler
事件处理程序,只需执行一次即可。
所以我开始思考,然后 Visual Studio-ing,也许我们甚至不需要 foreach 循环。我仍然维护一个列表,这样我们就知道用户点击了哪里,但是不需要循环遍历它并每次都重绘所有内容。
我意识到这不处理基础列表被修改的情况,原始样本也不处理。这是我的整个 Form1 class:
public partial class Form1 : Form
{
private const int CircleDiameter = 20;
private const int PenWidth = 2;
private readonly List<Point> _points = new List<Point>();
public Form1()
{
InitializeComponent();
pictureBox1.Paint += (sender, args) =>
{
_points.ForEach(p => DrawPoint(p, args.Graphics));
};
}
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
var cursorLocation = pictureBox1.PointToClient(Cursor.Position);
_points.Add(cursorLocation);
var circleArea = new Rectangle(
cursorLocation.X - CircleDiameter/2 - PenWidth,
cursorLocation.Y - CircleDiameter/2 - PenWidth,
CircleDiameter + PenWidth*2,
CircleDiameter + PenWidth*2);
pictureBox1.Invalidate(circleArea);
}
private static void DrawPoint(Point point, Graphics graphics)
{
point.X -= CircleDiameter / 2;
point.Y -= CircleDiameter / 2;
using (var pen = new Pen(Color.Tomato, PenWidth))
using (var brush = new SolidBrush(Color.White))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.DrawEllipse(pen, point.X, point.Y, CircleDiameter, CircleDiameter);
graphics.FillEllipse(brush, point.X, point.Y, CircleDiameter, CircleDiameter);
}
}
}
更新 1: 所以我更新了代码以使用具有 foreach 循环的 Paint 事件。但是,我不会在每次添加圆圈时都使(和绘制)无效 - 没有必要这样做。仅通过绘制添加圆意味着控件仅使添加新圆的区域无效并重新绘制。
尝试在 DrawAllPoints 方法上设置断点。您会看到它仅在完全失效操作期间发生,例如最小化和恢复。
更新二: 经过进一步交谈,我同意 Invalidate 方法更优越。代码更新为使用 Invalidate 和一个矩形来使无效。
现在看起来非常像 OP :)