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

Затем нарисовать ~ до ~ круга также в событии рисования. – Ralf

+2

'pictureBox1.Paint + = новый PaintEventHandler (pic_Paint);' должен находиться в вашей форме load или constructor. –

+0

@ RezaAghaei, почему его следует использовать только в конструкторе? и объясните немного больше? –

ответ

4

Вы не используете переменную pt в цикле foreach.

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 вам не нужно прикреплять hanlder событий PaintEventHandler, вам просто нужно сделать это один раз.

+1

Вот и все +1. Также OP должен поставить 'pictureBox1.Paint + = новый PaintEventHandler (pic_Paint);' в загрузке или конструкторе формы. Также он должен сначала «Заполнить», а затем «Рисовать эллипс». Также ему нужно также «Утилизировать» кисть. Лучше использовать 'use' для пера и кисти. –

+2

Вы также можете попробовать только аннулировать область PictureBox, где произошел щелчок (и окружающий ящик 20x20px), чтобы повысить производительность и уменьшить мерцание. https://msdn.microsoft.com/en-us/library/wtzka3b5(v=vs.110).aspx –

+1

@RezaAghaei - Хорошие моменты, обновленный ответ для отражения. – keyboardP

0

Итак, я подумал, а затем Visual Studio-ing, что, возможно, нам даже не нужен цикл foreach. Я все еще поддерживаю список, чтобы мы знали, где пользователь щелкнул, но нет необходимости перебирать его и каждый раз перерисовывать.

Я понимаю, что это не обрабатывает случай, когда базовый список изменен, но и исходный образец. Вот весь мой 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); 
     } 
    } 
} 

Update 1: Я обновил код, чтобы использовать событие Paint, который имеет цикл по каждому элементу. Тем не менее, я не делаю Invalidate (и Paint) каждый раз, когда добавляется круг - в этом нет необходимости. Просто добавление круга путем рисования означает, что элемент управления только отменяет действие и повторно рисует область, в которую был добавлен новый круг.

Попробуйте установить точку останова по методу DrawAllPoints. Вы увидите, что это происходит только во время полных недействительных операций, таких как минимизация и восстановление.

Обновление 2: После дополнительного чата я согласен, что метод Invalidate является превосходным. Код обновлен, чтобы использовать Invalidate с прямоугольником, чтобы сделать недействительным.

И теперь он очень похож на OP :)

+0

Я закончил кодирование, но мне интересно, может ли это быть превращено в метод расширения класса Control, поэтому мы можем сделать это, скажем, в панели, а не в PictureBox. Пища для размышления :) –

+0

Попробуйте минимизировать окно и восстановить его снова и увидеть результат. Все картины исчезнут. –

+0

Очень хорошо :) Может быть, я не закончил кодирование! –

 Смежные вопросы

  • Нет связанных вопросов^_^