Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fast read and write in listview in delphi?

Tags:

delphi

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.

like image 716
Dylan Avatar asked Nov 20 '10 12:11

Dylan


6 Answers

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.

like image 125
David Heffernan Avatar answered Nov 20 '22 10:11

David Heffernan


You just need to use your list in "virtual" mode.

  1. Put a TListBox on your form;
  2. Set the Style property to lbVirtual.
  3. Set the Count property to the number of items of your list.
  4. Then use the OnData handler to provide the text to be displayed on request:

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.

like image 24
Arnaud Bouchez Avatar answered Nov 20 '22 09:11

Arnaud Bouchez


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. :)

like image 32
GolezTrol Avatar answered Nov 20 '22 09:11

GolezTrol


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.

like image 32
dummzeuch Avatar answered Nov 20 '22 11:11

dummzeuch


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.

like image 3
Bill99 Avatar answered Nov 20 '22 11:11

Bill99


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.

like image 3
Vivian Mills Avatar answered Nov 20 '22 11:11

Vivian Mills