我有一个所有者绘制的TListBox(lbVirtualOwnerDraw),其内容动态更新(一秒钟内可以有多达10个更新)。一次最多可以在列表框中放置300个项目。每个项目可能有大约5行文本和与之关联的图像。每当刷新一个项目时,我都必须刷新(或使其无效)TListBox,以便VCL框架调用ListBoxDrawItem。但由于所有冗余重新涂漆,这会对整体性能产生不利影响。所以我的问题是:
有没有办法让画布的一小部分无效,其中包含一个项目或其中一个部分的图形? (例如,包含一行文本或位图的矩形)。
我们如何在Draw Item中处理这样一个选择性的无效矩形?如果可以将整数作为Refresh或invalidate的一部分传递,我可以在DrawItem中使用它来确定要刷新的内容。
有没有办法找到一个项目在TListBox上是否可见(按索引)?
提前致谢!
答案 0 :(得分:10)
您可以使用InvalidateRect
api使窗口的一部分无效。要查找项占用的区域,可以使用ListBox的ItemRect
方法。例如,使第4项无效:
var
R: TRect;
begin
R := ListBox1.ItemRect(3);
InvalidateRect(ListBox1.Handle, @R, True);
end;
(或'False'为'InvalidateRect'的'bErase',请参阅其文档)。要使位图或文本无效,请在传递给InvalidateRect之前相应地修改矩形。
您无法传递索引或任何类型的用户数据来刷新或无效。在绘画例程中,您必须根据位置确定要绘制的项目,或者如果绝对必要则使用全局变量。但是您不需要这样做,如果您只使一个项目的一部分无效,则仅会为该项目调用OnDrawItem
。在任何情况下,不要过于担心绘制未经过无效的项目,因为在更新区域之外不会有任何实际绘图,您将不会有任何显着的性能损失(参见第3段{{3 }})。
要确定项目是否可见,您将从顶部的第一个可见项目开始,并将连续项目的高度添加到控件的ClientHeight。顶部项目位于here。如果项目的高度是固定的,您已经知道最多可以看到多少项目。如果不是,你需要总结它们。