Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Listview: select all too slow

83 views
Skip to first unread message

Werner Lehmann

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Hi,

I am using a listview in virtual (ownerdata) mode with approx. 4500
items in it. All items must be selected if the user selected the menuitem
'Select All'. I am doing it like this:

procedure TDM.miSelectAllClick(Sender: TObject);
var i: integer;
begin
with Listview1 do try
Items.BeginUpdate;
i:=0;
while i<Items.Count do begin
Items[i].Selected:=true;
inc(i);
end;
finally
Items.EndUpdate;
end;
end;

This takes 8 seconds for all the 4500 items. 8 seconds can be a long time
if the user must wait for it and is expecting an instanteous action. I could
show a hourglass cursor or a progress dialog box. But hopefully there is a
faster way?

The ownerdata property does not help much here since apparently the selected
state is still handled by the common control itself. Which is not too fast at
it.

NB: The usual answer here is to say 'use Listview1.GetNextItem instead of
index based access of Listview1.Items'. I was about to use that approach but
when I checked the VCL source for GetNextItem I saw that it eventually does
the same index based access additional to some other processing so it should
be really slower even.

Regards,
WL


Jim Kueneman

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Werner,
I have battled this for some time. I think it is the overhead of the VCL. I
wrote a listview similar to Explorer's right pane and experienced the same. Even
selecting a screen of small icons with the mouse is noticeably slower than
Explorer. I finally gave up and decided that I would have to write a new
Listview component from scratch to get the speed I wanted. Someday.

Jim

Werner Lehmann

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Jim,


Jim Kueneman wrote:
>
> I have battled this for some time. I think it is the overhead of the VCL. I
> wrote a listview similar to Explorer's right pane and experienced the same. Even
> selecting a screen of small icons with the mouse is noticeably slower than

hm. When I saw that the GXExplorer listview component is slower than the explorer
listview I blamed it on the intensive PIDL handling. Which I am not doing. The same
might be true for just selecting the icons.

> Explorer. I finally gave up and decided that I would have to write a new
> Listview component from scratch to get the speed I wanted. Someday.

Tell me when you've done that :)

Although I don't know what you could do different than this:

var i: integer;
Item: TLVItem;
begin
Listview1.Items.BeginUpdate;
try
Item.stateMask:=LVIS_SELECTED;
Item.state:=LVIS_SELECTED;
for i:=0 to Items.Count-1 do
SendMessage(Listview1.Handle, LVM_SETITEMSTATE, i, Longint(@Item));
finally
Listview1.Items.EndUpdate;
end;
end;

(Note: in this form only valid if you really want to select all items or the
listview is in virtual mode.)

The above code takes more or less the same time and I don't see how can you
speed it up.

Regards,
WL


PS: I have been told (on IRC :) that MS-VC++ handles listview operations much
faster. The test problem was like this: add 100.000 items to a non virtual
listview (nonsense in the first place but it is a test). The speed of this is
more or less acceptable if you do it like this:

for i:=0 to 99999 do
Listview.Items.Add;

It slows to a crawl if you want to set a caption:

for i:=0 to 99999 do
with Listview.Items.Add do
Caption:='foobar';

You may not even want to wait for that. And if the app is shut down it takes
still much time to free the allocated memory. The person on IRC stated that
MS-VC++ would do that much faster. Personally I suspect that the delphi string
handling gets in the way here but this is just a guess.


Peter Below (TeamB)

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
In article <3A17F89F...@bwl.uni-kiel.de>, Werner Lehmann wrote:
> I am using a listview in virtual (ownerdata) mode with approx. 4500
> items in it. All items must be selected if the user selected the menuitem
> 'Select All'. I am doing it like this:
>
> procedure TDM.miSelectAllClick(Sender: TObject);
> var i: integer;
> begin
> with Listview1 do try
> Items.BeginUpdate;
> i:=0;
> while i<Items.Count do begin
> Items[i].Selected:=true;

Ignore the TListitems and implement a selected flag in your own data structure,
paint the items according to the value of the flag, not the Tlistitem state.
This way you can run over your memory structure at full speed and then just
Invalidate the listview to repaint the items in the selected state. Of course
you need to take over mouse click processing for selection now.

Peter Below (TeamB) 10011...@compuserve.com)
No e-mail responses, please, unless explicitly requested!


Jim Kueneman

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to

Werner Lehmann wrote:

> hm. When I saw that the GXExplorer listview component is slower than the explorer
> listview I blamed it on the intensive PIDL handling. Which I am not doing. The same
> might be true for just selecting the icons.

Nope, I wrote my own classes to mimic what GXExplorer does (thanks Gerald for
teaching me a lot about shell programming). I tried caching all the shell info so
everything was ready to load into the listview, with little speed difference. Also
notice the difference in dragging the column width around. Explorer is almost
instaneous, TListview lags on its updates.

Jim


Jim Kueneman

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to

Werner,

I uploaded a few MS documents to the borland.public.attachments that go over the
Custom Draw paint cycles, work areas, and virtual listview.

Jim

Werner Lehmann wrote:

Werner Lehmann

unread,
Nov 19, 2000, 7:58:09 PM11/19/00
to
"Peter Below (TeamB)" wrote:
>
> Ignore the TListitems and implement a selected flag in your own data structure,
> paint the items according to the value of the flag, not the Tlistitem state.

Ok. This would mean ownerdraw. I am unsure about how to do that. So that it just
looks like windows paints it by default. There are 7 Ownerdraw events in TListview
and 5 might be relevant. Any sample code? Anything simpler than that, I mean can I
utilize a 'default drawing'?

> This way you can run over your memory structure at full speed and then just
> Invalidate the listview to repaint the items in the selected state. Of course
> you need to take over mouse click processing for selection now.

Yes, that should not be a problem. What is still odd: clicking on a selected item
fires OnChange and OnSelectItem twice (deselect, select again). Thus dependent
visual controls are refreshed when its not necessary. Resulting in visible and un-
expected flickering. But that is another story which apparently noone could figure
out when I posted it before.

Regards,
WL


Mike Orriss (TeamB)

unread,
Nov 20, 2000, 1:28:13 AM11/20/00
to
In article <3A17F89F...@bwl.uni-kiel.de>, Werner Lehmann wrote:
> I am using a listview in virtual (ownerdata) mode with approx. 4500
> items in it. All items must be selected if the user selected the menuitem
> 'Select All'.
>

Why are you offering SelectAll in the first place?

In this scenario, I usually offer two buttons: Process and ProcessAll. The
first operates on selected items and the latter does what it says.


Mike Orriss (TeamB & Developer Express)
(Unless stated otherwise, my replies relate to Delphi 5)
(No unsolicited e-mail replies please)

Werner Lehmann

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
"Mike Orriss (TeamB)" wrote:
>
> Why are you offering SelectAll in the first place?
>
> In this scenario, I usually offer two buttons: Process and ProcessAll. The
> first operates on selected items and the latter does what it says.

Mike,

you are absolutely right. That idea did not even strike me. I think it's
just the usual procedure me (and users!) got used to: select one, process
one -- select all, process all.

I think a dedicated process all menuitem is very acceptable :)

Regards,
WL

Werner Lehmann

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
Jim Kueneman wrote:
>
> I uploaded a few MS documents to the borland.public.attachments that go over the
> Custom Draw paint cycles, work areas, and virtual listview.

I just read them, thanks a lot. I understand better now what this is all about. It
might even answer my previous question to Peter Below about 'utilizing the default
listitem drawing'. Fortunately I can skip that now since Mike Orriss's suggestion is
acceptable.

As a sidenote: printing webpages to PDF in order to build a private web library is
a very good idea. I used to save the pages in HTML format including all embedded images.
But I like the PDF way better. Probably smaller and only one file instead of many. And
easier to create... if you have a PDF printer driver.

Every now and then I read one of the articles in these delphi webzines and find it useful
but cannot be bothered to start Netscape Composer to get it all properly saved to my HDD.
Printing to PDF is the way out here :)

Which driver are you using: Adobe Distiller or Aladdin Ghostscript's pdfwrite? Or is
there a third option?

Regards,
WL


Jim Kueneman

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to

Werner Lehmann wrote:

> Every now and then I read one of the articles in these delphi webzines and find it useful
> but cannot be bothered to start Netscape Composer to get it all properly saved to my HDD.
> Printing to PDF is the way out here :)
>
> Which driver are you using: Adobe Distiller or Aladdin Ghostscript's pdfwrite? Or is
> there a third option?

I like the PDF way of doing it since it takes nothing more than "Print..." and answering a
few questions about where you want the file! I use Adobe Acrobat which comes with a print
driver so it looks like an installed printer. Distiller takes a PS file and converts it to a
PDF, an extra step that is a pain since I have 3.0 and the newer PS files have some extra
baggage in the first line that I have to manually strip out before it will run.

Jim


Markus Klingseisen

unread,
Dec 13, 2000, 1:44:51 AM12/13/00
to
> Item.stateMask:=LVIS_SELECTED;
> Item.state:=LVIS_SELECTED;
> for i:=0 to Items.Count-1 do
> SendMessage(Listview1.Handle, LVM_SETITEMSTATE, i, Longint(@Item));

Using the macro ListView_SetItemState(ListView1.Handle, -1, LVIS_SELECTED,
LVIS_SELECTED) might be even faster.


0 new messages