8

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.

Dylan
  • 1,183
  • 4
  • 13
  • 26

6 Answers6

11

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 2
    i was also going to suggest that he had to switch to virtual mode of the listview. Personally we use the Virtual TreeView that Golztrol mentioned. – Ian Boyd Nov 20 '10 at 12:32
  • 1
    Mike Lischke's virtual tree view is pretty awesome. There's a lot to be said though for using the list view component if you do have a list rather than a tree because it allows you to use the native component for the platform. Also, virtual tree view presents quite a learning curve. – David Heffernan Nov 20 '10 at 12:37
  • @Tupel The question makes no mention of grouping – David Heffernan Dec 03 '14 at 09:51
  • 1
    @David You are right, but I thought it might be usefull information for people searching for informatie about this subject (the reason I found this question). – Tupel Dec 03 '14 at 15:21
10

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.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
6

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

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
  • I looked quickly at the Virtual Tree View component. How "hard" is it to slot it into place in an application using several standard TListView and TTreeView controllers and accesses and works on the columns and tree nodes all over in the code? Are we talking complete rewrite of those parts? If so, how much difference in speed gain would it be to just stick with TTreeView and TListView bu change them to work as virtual ones? – inquam Jan 11 '13 at 12:32
  • I honestly don't know the speed difference. I think a virtual TListView could be pretty fast too, but I've not used it in that way, so I can't give you a proper comparison. – GolezTrol Jan 11 '13 at 14:28
5

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.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
3

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.

Bill99
  • 395
  • 2
  • 8
3

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.

Vivian Mills
  • 2,552
  • 14
  • 19
  • FindCaption IIRC leads to an API call, but I may be wrong about that. I don't have Delphi on this machine to be 100% certain. – Vivian Mills Nov 21 '10 at 03:11