【发布时间】:2016-05-22 20:34:43
【问题描述】:
概述
我需要在画布上绘制大量图形,在本例中是TPaintBox 画布。油漆盒是TScrollBox 的子级,油漆盒的高度和宽度可能非常大,例如 5000x5000。
我有一个TList,其中包含我自己的对象,每个对象都有自己的 X 和 Y 属性以及自己的图形。在paintbox 的OnPaint 方法中,我遍历列表中的每个对象,然后将每个对象图形绘制到paintbox 画布上存储在对象X 和Y 位置的坐标处。
显然,绘制所有这些会减慢应用程序的速度并且变得非常沉重,所以我需要一种方法来优化它。
显而易见的方法是以某种方式利用 GPU 而不是 CPU,但这可能要复杂得多,Firemonkey 可以帮助我,但我严格运行在 VCL 类型的项目中,而不是 FMX。
可能的解决方案?
我遇到了CreateRectRgn,如果我理解正确的话,我想如果我可以在带有自定义区域的画框上进行绘制,例如在滚动框的可见区域中,这应该会大大提高性能。因此,考虑到这一点,我尝试了以下方式:
procedure TForm1.PaintBox1Paint(Sender: TObject);
var
MyRgn: HRGN;
begin
// iterate and draw objects onto FBuffer (offscreen bitmap) first,
// note: FBuffer size is the same as the scrollboxes clientwidth
// and clientheight
//begin
// ...
//end;
// create and paint on a region (visible area of the scrollbox) on
// the paintbox rather than painting the whole paintbox.
MyRgn := CreateRectRgn(0, 0, ScrollBox1.ClientWidth, ScrollBox1.ClientHeight);
try
SelectClipRgn(PaintBox1.Canvas.Handle, MyRgn);
PaintBox1.Canvas.Draw(ScrollBox1.HorzScrollBar.Position,
ScrollBox1.VertScrollBar.Position, FBuffer);
SelectClipRgn(PaintBox1.Canvas.Handle, HRGN(nil));
finally
DeleteObject(MyRgn);
end;
问题
我想首先也是最重要的是,这是否是优化我在颜料盒画布上绘画方式的好方法,我还有哪些其他可能的选择?我唯一需要注意的另一件事是检查每个对象的 X 和 Y,如果它在滚动框的可见区域之外,我不绘制它。
我仍然对创建剪辑区域的想法很熟悉,但是上面的代码示例感觉不对。我不喜欢不断创建和删除区域的想法,尤其是在绘制方法中。
我的项目变得相当大,实际上我将其放入自定义控件中,但是当处理数百个对象并将它们绘制在画盒画布上时,我逐渐变慢了,我很确定这与要么是我没有正确实现剪辑区域,要么是我不断创建、绘制然后从 OnPaint 方法中删除区域的方式。
有没有更实用的方法来实现这一点?例如,也许可以在表单创建时创建区域并在表单销毁(或从自定义控件构造函数/析构函数)销毁它?但是,如果调整了表单/控件的大小,我将如何调整剪辑区域的大小?
我真的可以使用一些建议并弄清楚我面临的这个问题,以帮助我更好地了解我可以做得更好或不同的地方。
谢谢。
【问题讨论】:
-
GraphicControl (PaintBox) 在为其父级 (ScrollBox) 获得的 DC 上运行。我的意思是,绘画已经被剪辑到滚动框的客户区。更多详情,请参阅
TWinControl.PaintControls。 -
@SertacAkyuz 哇,我从来不知道。如果是这种情况,那么我需要找到另一种优化绘画的方法,因为我确信在我尝试添加自己的剪辑区域之前它会更慢。无论如何,我的问题和疑虑仍然存在,特别是关于我是否实际上正确设置了剪切区域,无论画盒的父级是否为我这样做。我确信我的任务可以以更好的方式完成,但在此过程中学习或纠正错误总是受欢迎的。
-
@SertacAkyuz 另外,假设很久以后当我真正将所有内容放入自定义控件时,我最好在滚动框上发布画布并直接在其上绘制而不是使用子画框,那么我肯定还需要滚动框画布的剪切区域?
-
另一个修改应该考虑到速度的增加。通常情况下,系统忽略的绘图不应占用大量时间,也许是为该绘图做准备 - 计算等......您应该分析并查看需要时间的内容。 ...我很难理解你的设计。你的离屏位图就是滚动框的大小,那么你在画框的不可见部分画的是什么呢?
-
一个自己的画布或一个油漆盒子组件 - 性能方面无关紧要,油漆盒是一个非常轻量级的组件。相信我,wincontrol 在让子控件绘制自己之前将其 DC 剪辑到其子控件的大小。
标签: delphi delphi-xe7