Как отмечено в моем комментарии: код, который вы публикуете, имеет много проблем, и одна из них также является причиной отсутствия скорости ..
Графика Winforms правило № 1: Никогда не используйте control.CreateGraphics
!
Также никогда не пытайтесь кэшировать объект Graphics
! Либо рисуйте в Bitmap bmp
, используя Graphics g = Graphics.FromImage(bmp)
, либо в Paint
событии элемента управления, используя параметр e.Graphics
..
(Единственное исключение - графика, которую вы на самом деле не хотите сохранять , например, рисование прямоугольников с резинкой ..
Вы можете проверить устойчивость вашей графики, выполнив последовательность минимизации / максимизации ..)
Правильный способ состоит в том, чтобы сохранить список вещей для рисования и всякий раз, когда этот список изменяется Invalidate
элемент управления, на котором вы рисуете. Весь рисунок должен быть в событии Paint
, используя e.Graphics
там!
Это обсуждалось довольно часто здесь; но что еще интереснее, так это то, что правильный путь будет действительно быстрым по сравнению с неправильным, непостоянным.
Посмотрим:
Пропущенные моменты времени для кругов 50k и 100k с созданным графическим объектом составляют 5,4 с (против 0,18 с) и 10,9 с (против 0,41 с). (Файл анимации будет слишком длинным для них ..)
Так что e.Graphics
может «нарисовать» круги ~ в 30-100 раз быстрее.
Как получилось? - На самом деле «правильный» путь будет только подготовить поверхность с двойной буферизацией управления внутри , но только толкнет его на дисплей один раз когда он закончится и успеет это сделать, тогда как неправильный способ доставит каждый круг напрямую . Эта оптимизация выполняется системой, а также ограничивает область вывода.
(PicturBox
по умолчанию имеет двойную буферизацию; другие элементы управления также могут быть выполнены, см. здесь )
Вот испытательный стенд:
int count = 5000;
List<PointF> pinCoordinates = new List<PointF>();
Random rnd = new Random(9);
float zoomFactor = 1.5f;
private void Button1_Click(object sender, EventArgs e)
{
// init a list of points
pinCoordinates.Clear();
Size sz = pictureBox1.ClientSize;
Cursor = Cursors.WaitCursor;
for (int i = 0; i < count; i++)
{
pinCoordinates.Add(new PointF(rnd.Next(sz.Width), rnd.Next(sz.Height)));
}
// now draw in one way or the other:
if (radioButton1.Checked)
{
Graphics g = pictureBox1.CreateGraphics();
DateTime dt0 = DateTime.Now;
foreach (var p in pinCordinates) DoDraw(g, p);
sayTime(dt0);
}
else
{
pictureBox1.Invalidate();
}
Cursor = Cursors.Default;
}
private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
DateTime dt0 = DateTime.Now;
foreach (var p in pinCoordinates) DoDraw(e.Graphics, p);
sayTime(dt0);
}
void DoDraw(Graphics g, PointF p)
{
using (Pen pen = new Pen(Color.FromArgb(rnd.Next(1234567890))))
g.DrawEllipse(pen, p.X * zoomFactor, p.Y * zoomFactor, 10, 10);
}
void sayTime(DateTime dt)
{
DateTime dt1 = DateTime.Now;
label1.Text = (dt1 - dt).ToString("s\\.ffff");
}
Последнее замечание: Вы можете ожидать одинаковую скорость, если вы рисуете в растровое изображение, используя Graphics g = Graphics.FromImage(bmp)
..