There is a listview with several fields in delphi. A thread checks and adds items to listview. If there is the same caption, an integer will be added in the subitem of this caption. When the item count is less than 2000, the performance is OK. When checking and adding items and items count are more than about 2000, the performance is poor. When items count is larger than 20,000, the performance can be described as extremely slow. Is there some way to fast read and write in listview when the items may reach 50,000 or 100,000 ?
Thank you very much in advance
Edit:
We have read all your answers and thank all for your help.
The Delphi TListView control is a wrapper around the Windows list view component. In its default mode of operation copies of the list data are transferred from your app to the Windows control and this is slow.
The alternative to this is known as a virtual list view in Windows terminology. Your app doesn't pass the data to the Windows control. Instead, when the control needs to display data it asks your app for just the data that is needed.
The Delphi TListView control exposes virtual list views by use of the OwnerData property. You'll have to re-write your list view code somewhat but it's really the only solution.
You just need to use your list in "virtual" mode.
As in this code (replace with some data from your database or a TStringList or such):
procedure TForm1.ListBox1Data(Control: TWinControl; Index: Integer;
var Data: String);
begin
Data := Format('Item %d',[Index+1]); // set the text to be displayed
end;
You can customize further the drawing by using lbVirtualOwnerDraw style, and you must draw items using an OnDrawItem event handler. There is some sample code in the Delphi documentation (at least under Delphi 7). ;)
In Virtual mode, you can display 50000 or 100000 items in an instantaneous way.
For storing the text, using a good old TStringList will be faster than the Items method of the TListBox, because this Items[] property will have to communicate with Windows with "slow" GDI messages for each item, whereas a TStringList will just store the text in the Delphi heap, which is usually much faster.
You can call BeginUpdate and EndUpdate on the listview to improve performance, by preventing the listview to redraw itself while updating. But this will probably not give you the boost you want. Besides, you need to know that accessing VCL controls directly from a thread is not safe unless synchronised.
I think it would be better to skip the listview and pick a 3rd party control like Virtual Tree View which is both great and free. :)
Several years ago we found that in addition to BeginUpdate / EndUpdate changing the ListView's ViewStyle to vsIcon prior to adding large amounts of data to it, and back to vsReport after we were done vastly improved performance. That was on Windows 98 and Windows 2000 if I remember correctly so I am not sure whether this is still the case.
Try a virtual Listview, using the OnData handler.
The data stays in your own data structure, the listview calls your OnData handler to get just the data items it needs whenever it needs them. i.e. You extract the particular data from your data structure when it asks.
Your other job is to keep the listview's ItemCount to the number of items in the list.
BeginUpdate and EndUpdate are an absolute must when updating the items. From your description it sounds like your looping through the items looking for a specific caption. This is slow and will get more noticeable with larger amounts of data, obviously.
Since your looking for a matching caption use the listviews FindCaption function.
This does a windows call to search the items and is fairly quick and simple. If it finds it it passes back the item and you can reference it to update the subitem. Otherwise create a new item and continue with your processing.
As long as your thread safe and you should be able to see decent performance.
HTH.
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