如何有选择地使Owner Drawn TListBox的画布无效?

时间:2011-04-06 00:12:51

标签: delphi ownerdrawn

我有一个所有者绘制的TListBox(lbVirtualOwnerDraw),其内容动态更新(一秒钟内可以有多达10个更新)。一次最多可以在列表框中放置300个项目。每个项目可能有大约5行文本和与之关联的图像。每当刷新一个项目时,我都必须刷新(或使其无效)TListBox,以便VCL框架调用ListBoxDrawItem。但由于所有冗余重新涂漆,这会对整体性能产生不利影响。所以我的问题是:

  1. 有没有办法让画布的一小部分无效,其中包含一个项目或其中一个部分的图形? (例如,包含一行文本或位图的矩形)。

  2. 我们如何在Draw Item中处理这样一个选择性的无效矩形?如果可以将整数作为Refresh或invalidate的一部分传递,我可以在DrawItem中使用它来确定要刷新的内容。

  3. 有没有办法找到一个项目在TListBox上是否可见(按索引)?

  4. 提前致谢!

1 个答案:

答案 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。如果项目的高度是固定的,您已经知道最多可以看到多少项目。如果不是,你需要总结它们。