代码之家  ›  专栏  ›  技术社区  ›  Jesse Hallam

是系统。绘图太慢,我们想做什么?

  •  3
  • Jesse Hallam  · 技术社区  · 15 年前

    我目前正在开发win表单应用程序的用户界面。主窗口是一个无边界窗体,其表面积几乎完全在form.Paint事件中呈现。创建了一个后缓冲区,并按惯例绘制:

    private void form_Paint(object sender, PaintEventArgs e) {
      e.Graphics.DrawImage(BackBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
    }
    

    在各种情况下,后缓冲区的某些区域会被重绘;鼠标悬停效果非常常见。重新仔细绘制的类只会使适用区域无效。尽管如此,只要在窗体上滑动鼠标就足以使高端CPU在几秒钟内使用率达到50%。

    我已经分析了这个应用程序,在调用上面的DrawImage80%以上的CPU时间都被消耗掉了。我知道GDI+的速度很慢,没有(很少?)使用GPU。。。而应用程序的目标平台并不能保证GPU一开始就不会被集成。但我不知道有这么糟。

    -编辑-

    BackBuffer表示在系统启动期间创建的位图。它的大小与屏幕分辨率相匹配。在各种事件(如鼠标悬停和单击)期间,会在其上绘制各种区域。它的创建相当简单:

    this.BufferBmp = new Bitmap(screenWidth, screenHeight);
    this.Gfx = Graphics.FromImage(BufferBmp);
    
    Gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
    
    3 回复  |  直到 15 年前
        1
  •  3
  •   Hans Passant    15 年前

    创建自己的“后缓冲区”而不是使用内置的双缓冲支持是很难获得性能的。重要的是 伟大的

    另一个可能的损失是您试图保持剪辑区域尽可能小。当区域变得复杂时,它可以字节。如果让快速鼠标移动生成小的矩形更新区域,听起来就接近了。当画作落后时,它几乎总是会落后,因为鼠标的优先级更高,你可以建立一个相当复杂的小矩形链。首先通过使整个区域无效来测试这个问题。下一个方法是自己扩展这个区域,始终保持它是一个矩形。当OnPaint运行时重置它。

        2
  •  3
  •   Community Mohan Dere    9 年前

    如果处理得当,GDI+的性能会非常好。我建议用类似于 RedGate's Ants 但还有其他一些经验法则可以用来提高性能:

    • 使用OnDraw事件中传递的图形对象,不要创建自己的
    • 在类范围内创建画笔、字体和笔等绘图对象(不要每次都重新创建)
    • 避免有太多来自OnDraw方法的方法调用
    • 避免在绘图阶段创建过多对象
    • 可以使用GDI而不是GDI+(请参见下面的链接)

    此外,还有一个替代BitBlt的选项。看这里 similar question and solution

        3
  •  1
  •   lincolnk    15 年前

    我想您想创建一个新的类,它继承自 Form 然后在 OnPaint Paint 表单中的事件。