如何有选择地使所有者绘制的 TListBox 的画布无效?

发布于 2024-10-30 22:37:05 字数 466 浏览 5 评论 0原文

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

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

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

  3. 是否有一种方法可以查找某个项目在 TListBox 上是否完全可见(通过索引)?

提前致谢!

I have an owner drawn TListBox (lbVirtualOwnerDraw), whose content gets updated dynamically (there can be as high as 10 updates in a second). There can be up to 300 items in the list box at a time. Each item may have about 5 lines of text and an image associated with it. Whenever an item is refreshed, I have to refresh (or invalidate) the TListBox so that the ListBoxDrawItem will be invoked by the VCL framework. But this adversely affects overall performance because of all the redundant repainting. So my question is:

  1. Is there a way to invalidate only a small portion of the canvas which contains the drawing of one item or one of its parts? (e.g., rectangle containing one line of text or the bitmap).

  2. How can we handle such a selective invalidate rectangle in Draw Item? If it were possible to pass an integer as part of the Refresh or invalidate I could use that in DrawItem to determine what to refresh.

  3. Is there a way to find if an item is visible at all on a TListBox (by index)?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

白云悠悠 2024-11-06 22:37:05

您可以使用 InvalidateRect使窗口的一部分无效的 api。要查找项目占用的区域,您可以使用 ItemRect< ListBox 的 /code>方法。例如,使第四项无效:(

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

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

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

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

You can use the InvalidateRect api to invalidate a part of a window. To find the area an item occupies you can use the ItemRect method of the ListBox. For instance to invalidate the 4th item:

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

(or 'False' as 'bErase' of 'InvalidateRect', see its documentation). To invalidate only the bitmap or text, modify the rectangle accordingly before passing to InvalidateRect.

You cannot pass an index or any kind of user data to refresh or invalidate. In the painting routine you have to determine the item you're drawing depending on the location, or use global variables if it's absolutely necessary. But you won't need that, if you invalidate part of only one item, OnDrawItem will be called for only that item. And in any case, don't worry too much about drawing non-invalidated items, since there won't be any actual drawing outside of the update region, you won't have any significant performance hit (see the 3rd paragraph here).

To determine if an item is visible you would be starting from the first visible item at the top and adding the heights of the consecutive items as far as the ClientHeight of the control. The top item is at TopIndex. If the height of the items are fixed you already know how many items are visible at most. If not you'll need to sum them up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文