2016-07-12 68 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

非常好:)也許我沒有完成編碼! –