Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对于我们想要做的事情,系统绘图是否太慢?_C#_Gdi+_System.drawing - Fatal编程技术网

C# 对于我们想要做的事情,系统绘图是否太慢?

C# 对于我们想要做的事情,系统绘图是否太慢?,c#,gdi+,system.drawing,C#,Gdi+,System.drawing,我目前正在开发WinForms应用程序的用户界面。主窗口是一个无边界窗体,其表面积几乎全部在form.Paint事件中渲染。创建了一个后缓冲区,并按照相当常规的方式绘制: private void form_Paint(object sender, PaintEventArgs e) { e.Graphics.DrawImage(BackBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel); } 后缓冲区的某些区域在各种

我目前正在开发WinForms应用程序的用户界面。主窗口是一个无边界窗体,其表面积几乎全部在form.Paint事件中渲染。创建了一个后缓冲区,并按照相当常规的方式绘制:

private void form_Paint(object sender, PaintEventArgs e) {
  e.Graphics.DrawImage(BackBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
}
后缓冲区的某些区域在各种条件下被重绘;鼠标悬停的效果很常见。仔细重画的类仅使适用区域无效。尽管如此,只需在窗体上滑动鼠标,就足以使高端CPU的使用率在几秒钟内达到50%以上

我已经分析了应用程序,调用上面的DrawImage消耗了超过80%的CPU时间。我知道GDI+速度很慢,没有(很少?)使用GPU。。。而应用程序的目标平台也不能保证GPU不会首先被集成。但我不知道情况会这么糟

我是否应该面对这样一个事实:GDI+对于我们想要做的事情来说还不够快,或者代码中还有改进的机会

-编辑-

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

this.BufferBmp = new Bitmap(screenWidth, screenHeight);
this.Gfx = Graphics.FromImage(BufferBmp);

Gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;

如果处理得当,GDI+的性能会非常好。我建议您使用类似的方法分析图形代码,但您可以参考其他一些经验法则来提高性能:

  • 使用OnDraw事件中传递的图形对象,不要创建自己的图形对象
  • 使用剪裁区域最小化需要重绘的区域
  • 在类范围内创建画笔、字体和笔等图形对象(不要每次都重新创建)
  • 避免有太多来自OnDraw方法的方法调用
  • 避免在绘图阶段创建过多对象
  • Try/catch块将影响性能
  • 可以使用GDI而不是GDI+(参见下面的链接)

此外,还有一个选项可以改为执行BitBlt。请参见此处获取一个。

我认为您希望创建一个新类,该类继承自
表单
,然后使用
OnPaint
方法进行绘图,不要监听表单中的
Paint
事件。

创建自己的“后台缓冲区”而不是使用内置的双缓冲支持是很难实现的。重要的是缓冲区的像素格式。在大多数现代机器上,不管我怎么做,32bppPArgb格式的速度都是其他格式的十倍。支持内置的双缓冲,以获得更高的性能


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

你好,保罗。我确实用过蚂蚁。它确定了代码中e.Graphics.DrawImage位置出现的瓶颈。让我大吃一惊的是,没有一个命中测试(用Rectangle.Intersect不雅观地完成)或后缓冲区绘图造成任何显著的负载。@Kivin:有趣。什么是DrawImage绘图?它是缓存还是动态创建的?BackBuffer是一个类,它包含一个位图(在启动时创建),该位图与屏幕分辨率匹配。它负责在各种事件(如鼠标悬停和单击)期间绘制适当的曲面。它隐式地转换为它所包含的位图,以便绘制图像。我将编辑我的OP以构建位图及其图形。Paul,为了解决您的问题:如OP中所示,我使用提供的图形。我正在剪。我只是在使尽可能小的区域无效。GDI对象是静态的,在prog启动时创建。绘画事件实际上只是一行。Try/Catch块几乎不存在。了解。。。我想你可能在简化函数。看看这个:(链接也包括在我的答案中)你多久调用一次这个方法,剪辑矩形有多大?我怀疑你从后台缓冲区到屏幕的次数比你必须的要多。难以置信。将像素格式更改为32bppPArgb可将CPU消耗减少十倍以上。