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!
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With