C# 如何在windows窗体上更快地绘制圆?

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

我需要在给定的X,Y坐标下画小圆圈,但在窗口的面板上可以高达6000个圆圈。速度非常慢,5000圈大约需要2到3秒。 我怎么能画得更快

 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
                {

                }
            }
        }

按照下面的优化顺序进行操作,直到您对性能感到满意为止

  • 频繁更新UI后调用并控制.ResumeLayout

  • 检查是否正在调用控件。经常刷新,使用控件。无效而不是控件。刷新

  • 只画可见区域(Graphics.Clip)内的圆,然后要画的圆会少得多

  • 在Windows API级别暂停绘制。见此帖:


  • 正如我在评论中所指出的:您发布的代码有很多问题,其中之一也是速度不足的原因

    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:太好了,我可以使用以前的建议将时间缩短一半,但这会吹走所有记录。非常感谢你