如何有选择地使所有者绘制的 TListBox 的画布无效?
我有一个所有者绘制的 TListBox (lbVirtualOwnerDraw),其内容会动态更新(每秒可能有多达 10 次更新)。列表框中一次最多可以包含 300 个项目。每个项目可能有大约 5 行文本和与其关联的图像。每当刷新某个项目时,我都必须刷新(或无效)TListBox,以便 VCL 框架调用 ListBoxDrawItem。但由于所有多余的重新绘制,这会对整体性能产生不利影响。所以我的问题是:
有没有办法仅使包含一个项目或其一个部分的绘图的画布的一小部分无效? (例如,包含一行文本或位图的矩形)。
我们如何在 Draw Item 中处理这样一个选择性无效的矩形?如果可以传递一个整数作为刷新或无效的一部分,我可以在 DrawItem 中使用它来确定要刷新的内容。
是否有一种方法可以查找某个项目在 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:
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).
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.
Is there a way to find if an item is visible at all on a TListBox (by index)?
Thanks in advance!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以使用
InvalidateRect
使窗口的一部分无效的 api。要查找项目占用的区域,您可以使用ItemRect< ListBox 的 /code>
方法。例如,使第四项无效:(
或“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 theItemRect
method of the ListBox. For instance to invalidate the 4th item:(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.