2016-07-12 129 views
2

事实上,我想每次双击并且不需要删除前的圆圈,就可以在新的位置绘制圆圈。需要注意的是,我使用了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(); 
    } 

} 

enter image description here

+0

然后在paint事件中绘制〜before〜circle。 – Ralf

+2

'pictureBox1.Paint + = new PaintEventHandler(pic_Paint);'应该在你的表单加载或构造函数中。 –

+0

@ RezaAghaei,为什么只能在构造函数中使用?多解释一下? –

回答

4

您没有使用在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); 
    } 
} 

在代码中,你只是在重写每Point在同一位置的圆圈中points列表。

此外,正如Reza在评论中提到的,每次单击PictureBox时都不需要附加PaintEventHandler事件hanlder,只需要一次。

+1

就是这样+1。另外,OP应该在表单加载或构造函数中放置'pictureBox1.Paint + = new PaintEventHandler(pic_Paint);'。他还应该先填充,然后绘制椭圆。另外他还需要'处置'刷子。对笔和笔使用“使用”更好。 –

+2

您也可以尝试仅使发生点击的PictureBox区域(以及周围的框20x20px)无效以提高性能并减少闪烁。 https://msdn.microsoft.com/en-us/library/wtzka3b5(v=vs.110).aspx –

+1

@RezaAghaei - 好点,更新的答案反映。 – keyboardP

0

所以我开始思考,然后Visual Studio的,也许我们甚至不需要foreach循环。我仍然维护一个List,以便我们知道用户点击的位置,但不需要遍历它并每次重绘所有内容。

我意识到这并不处理底层列表被修改的情况,但原始示例也不处理。这里是我的整个Form1类:

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方法上设置断点。你会发现它只发生在完全失效操作期间,例如最小化和恢复。

更新2: 进一步的聊天后,我同意Invalidate方法是优越的。代码更新为使用无效与矩形无效。

现在它看起来非常像OP :)

+0

我完成了编码,但是我不知道这是否可以转化为Control类的扩展方法,因此我们可以将它应用于Panel而不是PictureBox。食物的思考:) –

+0

尽量减少窗口,并再次恢复,看看结果。所有的画作将会消失。 –

+0

非常好:)也许我没有完成编码! –