0

我有一个WinForm应用程序'Bouncing Balls',我需要在 a 上绘制球bitmap并在此表单上显示位图。

我有一个plusButton添加新球的,我将每个新球保存在一个列表中。

现在,该Form_Paint方法告诉每个球自己画,它工作正常,直到有很多球并且所有应用程序变得非常慢..

这是我的代码:

表单代码的paint方法:

 private void Form1_Paint(object sender, PaintEventArgs e)
 {
     ballsArray.drawImage(bmp,e, ClientRectangle);
 }

注意: ballsArray来自 type AllBalls,这是一个包装球方法的类,在他的 c'tor 中,我正在创建一个保存每个球的列表。,bmp是在表单加载时创建的 - onForm_Load()方法。

代码的drawImage ballsArray

 public void drawImage(Bitmap bmp,PaintEventArgs e, Rectangle r)
 {
     foreach (Ball b in allBalls)
     {
         b.drawImage(bmp,e, r);
     }
 }

drawImage球码:

  public void drawImage(Bitmap bmp, PaintEventArgs e, Rectangle r)
  {
      using (Graphics g = Graphics.FromImage(bmp))
      {
          e.Graphics.FillEllipse(brush, ballLocation);
          g.DrawImage(bmp, 0, 0);
      }
  }

注意: ballLocation是一个矩形,表示每一步运动中球的位置。

那么我做错了什么?是什么导致应用程序缓慢?

我有一个约束要在位图上绘制所有内容并将其呈现在表单上。我还传递了加载表单时创建的位图,因为我需要在其上绘制每个位图。

4

3 回答 3

3

一些使这个速度更快的基本技术:

  • 不要对自己进行双重缓冲,尤其是不要双重缓冲两次。通过将表单的 DoubleBuffer 属性设置为 true 获得的双缓冲优于您自己进行的大多数双缓冲。缓冲区经过高度优化,可以有效地与您的视频适配器设置配合使用。因此,完全删除您的bmp变量并绘制到您从 Paint 事件处理程序参数中获得的 e.Graphics。

  • 您没有使用传递的r参数。可能旨在支持剪切隐形球。您要传递的是 e.ClipRectangle,您可以跳过完全超出此矩形的画球。虽然这是一种优化,但当您使用 Aero 主题时它并不是通常有用的,而且您确实会得到不一致的重绘率,因此您可能想跳过那个。

  • 目前还不清楚为什么在绘制球时同时使用 Graphics.FillEllipse 和 Graphics.DrawImage。图像应该与圆圈重叠,因此只需删除 FillEllipse。

  • 非常注意存储球图形的 Bitmap 对象。您要确保的第一件事是它是按照图像的确切大小绘制的,因此不必重新缩放。重新缩放非常昂贵。虽然您在 DrawImage() 调用中没有任何重新缩放,但如果位图的分辨率与视频适配器的分辨率不同,您仍然会得到它。下一步将解决

  • 球位图的像素格式非常重要。您需要一个允许将位图直接复制到视频内存而无需任何格式转换的设备。在任何现代机器上,该格式都是 PixelFormat.Format32bppPArgb。差异是巨大的,它的绘制速度比其他任何一个都快十倍。您不会从您添加的图像资源中获得这种格式,您必须在程序启动时创建该位图。检查此答案以获取所需的代码。

当您遵循这些准则时,您应该能够将渲染速度至少提高 15 倍。如果这仍然足够,那么您确实需要转向 DirectX,它具有无与伦比的优势,能够将球图形存储在视频内存中,因此您不会将昂贵的 blt 从主内存转移到视频内存。

于 2013-01-13T13:22:20.160 回答
0

DrawImageon Paint(或就此而言 on MouseMove)是非常糟糕的设计。

Graphics.DrawImage是昂贵的操作,而且对屏幕来说是额外的昂贵。为了改善您的用户体验(缓慢),您应该在 MouseDown/MouseUp 事件上进行绘制。

此外,首先在您的drawImage方法中绘制到 MemoryBuffer 并在准备好最终图像后,在 UI 上绘制一次。这种技术称为双缓冲

不要闪烁!双缓冲!- 代码项目

此外,您还可以查看BitBlit Native API 以快速将颜色/图像传输到屏幕。

一个简约的 c# 示例在这里

于 2013-01-13T12:25:43.970 回答
0

在表单上启用双缓冲 ( DoubleBuffered = true)。

于 2013-01-13T12:32:16.833 回答