C# 如何在windows窗体上更快地绘制圆?
我需要在给定的X,Y坐标下画小圆圈,但在窗口的面板上可以高达6000个圆圈。速度非常慢,5000圈大约需要2到3秒。 我怎么能画得更快C# 如何在windows窗体上更快地绘制圆?,c#,canvas,drawellipse,C#,Canvas,Drawellipse,我需要在给定的X,Y坐标下画小圆圈,但在窗口的面板上可以高达6000个圆圈。速度非常慢,5000圈大约需要2到3秒。 我怎么能画得更快 private void drawBGA_Pins(BGAmap PinCordinates, double ExternalZoomFactor, double ExternalOffset_X, double ExternalOffset_Y) { Graphics g = this.imgBox.CreateGra
private void drawBGA_Pins(BGAmap PinCordinates, double ExternalZoomFactor, double ExternalOffset_X, double ExternalOffset_Y)
{
Graphics g = this.imgBox.CreateGraphics();
double zoomFactor = (Math.Min(Math.Abs((imgBox.Width) / PinCordinates.width), Math.Abs((imgBox.Height) / PinCordinates.height)))*92/100 * ExternalZoomFactor;
//g.Clear(Color.Transparent); //you can choose another color for your background here.
Pen pen = new Pen(Color.Yellow);
foreach (var p in PinCordinates.pkgCordinates)
{
try
{
g.DrawEllipse(pen, (float)(ExternalOffset_X + (p.X* zoomFactor)), (float)(ExternalOffset_Y + (p.Y* zoomFactor)), 10, 10);
}
catch
{
}
}
}
按照下面的优化顺序进行操作,直到您对性能感到满意为止
正如我在评论中所指出的:您发布的代码有很多问题,其中之一也是速度不足的原因 Winforms图形规则#1:切勿使用
控件。CreateGraphics
强>
也不要试图缓存图形
对象!使用Graphics g=Graphics.FromImage(bmp)
或在控件的Paint
事件中,使用e.Graphics
参数将bmp绘制到位图中
(唯一的例外是您实际上不想保存的图形,例如绘制橡胶和矩形。)。。
您可以通过执行最小化/最大化顺序来测试图形的持久性…)
正确的方法是保留要绘制的内容列表,并且每当该列表发生更改时,使所绘制的控件无效。所有的绘图都应该在Paint
事件中,使用e.Graphics
在那里
这里经常讨论这个问题;但这里更有趣的是,与错误的、不持久的方法相比,正确的方法将非常快
让我们看看:
创建图形对象的50k和100k圆缺少的计时为5.4s(vs 0.18s)和10.9s(vs 0.41s)。(动画文件对它们来说太长了..)
因此e.Graphics
可以更快地“绘制”圆圈~30-100倍
怎么会这样实际上,“正确”的方法只会在内部准备双缓冲控件的表面,但在完成并且有时间时,只将其推到显示屏上一次,而错误的方式将直接传递每个圈。该优化由系统完成,同时限制输出区域
(PictureBox
默认为双缓冲;其他控件也可以设置为双缓冲,请参阅)
这是试验台:
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");
}
int计数=5000;
List pinCoordinates=新列表();
随机rnd=新随机(9);
浮动缩放因子=1.5f;
私有无效按钮1\u单击(对象发送者,事件参数e)
{
//初始化一个点列表
pinCoordinates.Clear();
大小sz=pictureBox1.ClientSize;
Cursor=Cursors.WaitCursor;
for(int i=0;i
最后一点注意:如果使用Graphics g=Graphics.FromImage(bmp)
绘制位图,则可以获得相同的速度。这应该不会超过几分之一秒。一定要在catch
中放入一些内容,以确保没有调用is。例外很慢!不要在常规情况下抓住他们。(而是测试以避免!!)-另外:您不应该使用control.CreateGraphics
,正如这里解释的那样>10k次!!-此外,您正在泄漏GDI资源,如画笔和图形对象(您不应该首先创建它们)-仅在Paint
事件中绘制或传递其e.Graphics
对象!!-对于无闪烁的绘图,标签必须是双缓冲的。默认情况下只有PictureBox
。不使用control.CreateGraphics的一个原因是持久性,但另一个原因是速度。正确操作会将输出速度提高约100倍,这是我测试的结果!除了@Taw的注释外,您还应该扩展imgbox类,覆盖OnPaint方法并从OnPaint参数获取Graphics obejct,请参见MSDN:太好了,我可以使用以前的建议将时间缩短一半,但这会吹走所有记录。非常感谢你