4

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

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

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

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

提前致谢!

4

1 回答 1

12

您可以使用InvalidateRectapi 使窗口的一部分无效。要查找项目占用的区域,您可以使用ItemRectListBox 的方法。例如使第 4 项无效:

var
  R: TRect;
begin
  R := ListBox1.ItemRect(3);
  InvalidateRect(ListBox1.Handle, @R, True);
end;

(或 'False' 作为 'InvalidateRect' 的 'bErase',请参阅其文档)。要仅使位图或文本无效,请在传递给 InvalidateRect 之前相应地修改矩形。


您不能传递索引或任何类型的用户数据来刷新或失效。在绘画例程中,您必须根据位置确定要绘制的项目,或者在绝对必要时使用全局变量。但是你不需要那个,如果你只使一个项目的一部分无效,OnDrawItem将只为那个项目调用。无论如何,不​​要太担心绘制非无效项目,因为在更新区域之外不会有任何实际的绘制,你不会有任何显着的性能影响(请参阅此处的第 3 段)。


要确定一个项目是否可见,您将从顶部的第一个可见项目开始,并将连续项目的高度添加到控件的 ClientHeight。顶部项目位于TopIndex。如果项目的高度是固定的,您已经知道最多有多少项目是可见的。如果没有,你需要总结它们。

于 2011-04-06T02:00:35.000 回答