我正在用GDI+开发一个保留模式的绘图应用程序。该应用程序可以将简单的形状绘制到画布上,并执行基本编辑。这样做的数学运算被优化到最后一个字节,这不是问题。我正在使用内置Controlstyles.DoubleBuffer的面板上绘图。
现在,如果我在大显示器上最大化运行我的应用程序(在我的情况下是高清),我的问题就出现了。如果我试图从(大的)画布的一角到另一角的对角画一条线,它将开始滞后,CPU会上升。
我的应用程序中的每个图形对象都有一个边界框。因此,当我使从最大化应用程序的一角到相反的对角的线的边界框无效时,该边界框实际上与画布一样大。当用户绘制一条线时,边界框的这种失效会在mousemove事件上发生,并且有一个明显的滞后可见。如果线条是画布上的唯一对象,则也存在此延迟。
我尝试过用很多方法来优化这一点。如果我画一条较短的线,CPU和lag就会停机。如果我删除无效()并保留所有其他代码,应用程序就会很快。如果我使用一个区域(仅跨越图形)来使无效,而不是使用边界框,它同样很慢。如果我将边界框拆分为背靠背的一系列较小的框,从而减少了无效区域,则看不到明显的性能提升。
因此,我在这里不知所措。如何加速失效?
顺便说一句,Paint.Net和Mspaint都有同样的缺点。然而,Word和PowerPoint似乎能够像上面描述的那样画一条线,没有延迟,也没有CPU负载。因此,实现预期的结果是可能的,问题是如何实现?
发布于 2009-06-07 21:29:41
对于像线条这样的基本显示项目,如果每个绘制周期绝对必须使它们的整个边界无效,则应考虑将它们拆分为几个部分。
这样做的原因是GDI+ (以及GDI本身)使矩形形状的区域无效,就像您在边界框中指定的那样。您可以通过测试一些水平线和垂直线与斜率与显示区域的坡度相似的线来验证这一点。
因此,假设您的画布是640x480。如果您绘制了一条从0,0到639,479的直线;Invalidate()将使从顶部的0,0到639,0到底部的0,479到639,479的整个区域无效。比方说,从0,100到639,100的水平线产生的矩形只有1个像素高。
区域将具有非常相同的问题,因为区域被视为一组组合在一起的水平范围集。因此,对于从一个角落到另一个角落的大对角线,为了与您设置的边界框匹配-区域必须指定每条垂直线上的每组像素或整个边界框。
因此,作为一种解决方案,如果您有一条非常长的行,将其划分为四分之一或八分之一,性能应该会有相当大的提高。回顾上面的例子,如果你只是将两部分一分为二-你将把无效的总面积减少到0,0x319,239加上320,240x639,479。
这是一个四分之一分割的可视示例。粉红色区域是无效的区域。不幸的是,所以不会让我张贴图片或超过1个链接,但这应该足以解释一切。
(线以季度分割,无效总面积为表面的1/4 )
a 640x480 extent with 4 equal sized boxes carved behind a line drawn across the diagonal
或者,您可以考虑重写更新,以便只绘制与必须更新的区域匹配的项目部分,而不是指定边界框。这实际上取决于有多少对象需要参与绘制的更新。如果在给定的帧中有数千个对象,则可以考虑忽略所有无效区域并重新绘制整个场景。
发布于 2009-06-11 04:56:46
你不能真的加快无效的速度。它之所以慢是因为它在消息队列上发布了一个WM_PAINT事件。然后过滤掉,最终你的OnPaint甚至会被调用。您需要做的是在MouseMove事件期间直接在控件中绘制。
在我所做的任何需要一些流畅动画的控件中,我的OnPaint事件通常只调用PaintMe函数。这样,我就可以随时使用该函数来重新绘制控件。
发布于 2009-06-05 19:15:21
要澄清的是:用户是在画一条直线,还是你的线实际上是一堆连接鼠标点的线段?如果这条线是一条从原点到当前鼠标点的直线,不要使()无效,而是使用XOR笔刷绘制一条可撤消的线,然后撤消前一条线,只有在用户完成绘制后才会失效。
如果您正在绘制一堆小线段,只需使最近线段的边界框无效即可。
https://stackoverflow.com/questions/957573
复制相似问题