Performance Probleme mit TListview

Rund um die LCL und andere Komponenten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Performance Probleme mit TListview

Beitrag von corpsman »

Hallo zusammen, ich schon wieder,..

Ich habe ein neues Problem.

Auf einem 2. Formular habe ich eine TListview plaziert. Dort füge ich 600 Items ein. Dann Zeige ich das Formular an.
Mein Problem ist nun, dass das Anzeigen des 2. Formulars Ewig dauert und ich nicht verstehe wieso, bzw wie ich das wieder beschleunigen können soll.
Unten mal die relevanten Code Zeilen:

Code: Alles auswählen


Procedure TForm1.Button1Click(Sender: TObject);
Var
  ti: Array[0..10] Of QWord;
  t: QWord;
  i: Integer;
  li: Tlistitem;
  s: String;
Begin
  button1.enabled := false;
  t := GetTickCount64;
  form2.ListView1.BeginUpdate; // ich dachte immer das hilft beim einfügen, aber hier scheint es keinen Einfluss zu haben ...
  form2.ListView1.Clear;
  ti[0] := GetTickCount64 - t;
  t := GetTickCount64;
  For i := 0 To 600 Do Begin
    li := Form2.ListView1.items.add();
    li.Caption := 'Hallo ' + inttostr(i);
    li.SubItems.Add('x');
    li.SubItems.Add('y');
  End;
  ti[1] := GetTickCount64 - t;
  t := GetTickCount64;
  form2.ListView1.EndUpdate; // Auch das End update dauert 0ms
  ti[2] := GetTickCount64 - t;
  t := GetTickCount64;
  form2.Show; // Dieses Form Show dauert bei mir mindestens 9s
  ti[3] := GetTickCount64 - t;
  t := GetTickCount64;
  s := '';
  For i := 0 To 3 Do Begin
    s := s + inttostr(ti[i]) + LineEnding;
  End;
  label1.caption := s;
  button1.enabled := true;
End;
Auf meinem System sind die ersten 3 Zeitmessungen ~ 0ms, aber die Zeit für das form2.show dauert zwischen 9000ms und 12000ms.


Wie immer das gesammt Beispiel Projekt im Anhang
Dateianhänge
Test.zip
(2.85 KiB) 69-mal heruntergeladen
--
Just try it

Frank Ranis
Beiträge: 201
Registriert: Do 24. Jan 2013, 21:22

Re: Performance Probleme mit TListview

Beitrag von Frank Ranis »

Hallo Corpsmann,

ich habe mal nen zweiten Button draufgeschmissen und hier das Form2.show direkt hinter das Begin gepackt.
Dann geht das erheblich schneller .
Frag mich warum !!!!! , war so ne Eingebung.

Auch bei mir dauert deine Orginal-Routine beim ersten Klick ca. 9 Sekunden.
Beim zweiten mal draufklicken wird Form2 und der Inhalt fast augenblicklich angezeigt.
Sehr komisch !!!!

Code: Alles auswählen

procedure TForm1.Button2Click(Sender: TObject);
Var
  ti: Array[0..10] Of QWord;
  t: QWord;
  i: Integer;
  li: Tlistitem;
  s: String;
Begin
  form2.Show; //  <---- hier 
  button1.enabled := false;
  t := GetTickCount64;
  form2.ListView1.BeginUpdate;
  form2.ListView1.Clear;
  ti[0] := GetTickCount64 - t;
  t := GetTickCount64;
  For i := 0 To 600 Do Begin
    li := Form2.ListView1.items.add();
    li.Caption := 'Hallo ' + inttostr(i);
    li.SubItems.Add('x');
    li.SubItems.Add('y');
  End;
  ti[1] := GetTickCount64 - t;
  t := GetTickCount64;
  form2.ListView1.EndUpdate;
  ti[2] := GetTickCount64 - t;
  t := GetTickCount64;
  ti[3] := GetTickCount64 - t;
  t := GetTickCount64;
  s := '';
  For i := 0 To 3 Do Begin
    s := s + inttostr(ti[i]) + LineEnding;
  End;
  label1.caption := s;
  button1.enabled := true;
End;
Gruss

Frank
www.flz-vortex.de

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Performance Probleme mit TListview

Beitrag von corpsman »

*g*.
Was ich übersehen habe in meiner Finalen Anwendung ist Form2 ein Modales fenster.
-> Wenn ich dann den Aufruf .showmodal vor ziehe geht das bei mir nicht :(.
Aber es freut mich schon mal dass jemand anderes mein Problem nachstellen kann ;)
--
Just try it

Benutzeravatar
theo
Beiträge: 10498
Registriert: Mo 11. Sep 2006, 19:01

Re: Performance Probleme mit TListview

Beitrag von theo »

Kann ich auf Linux nicht nachvollziehen.
Ich komme auf einem alten, schwachen Laptop auf 430 ms. (Intel Celeron N2820)

Lazarus 2.3.0 (rev main-2_3-497-gf8bc3ff316) FPC 3.2.2 x86_64-linux-gtk2

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Performance Probleme mit TListview

Beitrag von Michl »

Das ListView ist bekannt für seine schlechte Geschwindigkeit. Es ist mMn nur geeignet für die Anzeige kleinerer Datenmengen. Sehr schön kann man bei dem Beispiel sehen, wenn man statt 600 z.b. 1200 oder 2400 Items nutzt, wie die Dauer exponentiell zunimmt (Windows).

Das Problem ist, daß wenn das Handle noch nicht erstellt wurde, alle Daten gecached werden. Sobald das Handle vom ListView da ist, werden die gecachten Items im Widgetset erstellt. Da scheint es hohes Potential unter Windows zu geben :wink:
Ist das Handle schon erstellt, dann werden direkt die OS Methoden entsprechend Widgetset genutzt, was dann unter Windows wieder schneller ist.

Wenn du eine funktionierende schnelle Lösung willst, verwende ein VirtualStringTree. https://wiki.freepascal.org/VirtualTreeview
Ansonsten kannst du versuchen der Ursache auf den Grund zu gehen. Als Einstieg wäre TListItems die procedure WSCreateItems, procedure WSCreateCacheItem, da speziell ACacheItem.WSUpdateText interessant. Mehr habe ich auf die schnelle jetzt nicht debuggt.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
theo
Beiträge: 10498
Registriert: Mo 11. Sep 2006, 19:01

Re: Performance Probleme mit TListview

Beitrag von theo »

Grundsätzlich kann man TListView vielleicht durch "AllocBy" und sicher durch "OwnerData" beschleunigen.
Zweiteres bedingt aber einen andere Logik (OnData, *virtual").

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Performance Probleme mit TListview

Beitrag von corpsman »

Danke Jungs für euren Input.
An der Einen Stelle habe ich das Listview auch schon durch TTreeView ersetzt, da ging das ganz Gut. Eure Aussagen bekräftigen mich nun darin es mal mit einem TStringgrid oder dem erwähnten https://wiki.freepascal.org/VirtualTreeview zu versuchen. Ich hatte nur gehofft mir den Aufwand sparen zu können, da meine Anwendung eigentlich schon so gut wie fertig ist :roll:
--
Just try it

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Performance Probleme mit TListview

Beitrag von Michl »

Achso, weil ich es eben noch in TWin32WSCustomListView.ItemSetText gelesen habe,
// autosize is an *extreme* performance bottleneck, even if WM_SETREDRAW
// was set to false it will ignore this and still redraw all columns.
// We will therefore postpone all autosizing until EndUpdate where we do
// it only once per column.
, erhöht es extrem die Geschwindigkeit, wenn AutoSize ausgestellt wird. Vielleicht hilfts ja als Anregung?

z.B.:

Code: Alles auswählen

procedure TForm2.FormCreate(Sender: TObject);
begin
  ListView1.Column[0].AutoSize := False;
  ListView1.Column[1].AutoSize := False;
  ListView1.Column[2].AutoSize := False;
end; 

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
theo
Beiträge: 10498
Registriert: Mo 11. Sep 2006, 19:01

Re: Performance Probleme mit TListview

Beitrag von theo »

@corpsman
Ich möchte aber doch noch gerne wissen, von welchem System du sprichst.
Hier auf OpenSUSE mit GTK2 komme ich auf dem lahmen Rechner auf 430ms und auf dem schnellen auf 130ms (beim 2.Mal auf 30ms).
Beides keine störenden Werte und meilenweit von deinen Messungen entfernt.
Also von welchem System sprichst du? Das scheint hier doch entscheidend.

wp_xyz
Beiträge: 4892
Registriert: Fr 8. Apr 2011, 09:01

Re: Performance Probleme mit TListview

Beitrag von wp_xyz »

Du kannst auch mit TListView im virtuellen Modus arbeiten, ähnlich wie TVirtualTreeView: OwnerData auf true setzen, die Anzahl der Items angeben und einen Handler für OnData schreiben - lädt 1.000.000 Items schneller als ich zwinkern kann. (Allerdings nur in diesem Beispiel, das "triviale" Daten on-the-fly erzeugt; wenn die Daten z.B. aus einer Datei kommen, muss man natürlich auch die Zeit für das Einlesen und Aufbereiten mit berücksichtigen).

Code: Alles auswählen

// in Form1
Procedure TForm1.Button1Click(Sender: TObject);
Begin
  Form2.ListView1.OwnerData := true;
  Form2.Listview1.Items.Count := 1000000;
  form2.Show;
End;

// in Form2
procedure TForm2.ListView1Data(Sender: TObject; Item: TListItem);
begin
  Item.Caption := 'Hallo ' + IntToStr(Item.Index);
  Item.SubItems.Add('x');
  Item.SubItems.Add('y');
end;

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Performance Probleme mit TListview

Beitrag von corpsman »

Also,
ich entwickle auf einer Linux Mint Mate Maschine, da kann ich die Performance Themen auch nicht feststellen, deswegen hatte ich es ja während des schreibens nicht gemerkt.
Nutzen tu ich das Programm auf meinem Windows Spiele Rechner, da läuft ein Windows 10.

Im Create das Autosize platt zu machen geht nicht, aber folgendes geht:

Code: Alles auswählen


Procedure TForm1.Button1Click(Sender: TObject);
Var
  ti: Array[0..10] Of QWord;
  t: QWord;
  i: Integer;
  li: Tlistitem;
  s: String;
Begin
  button1.enabled := false;
  t := GetTickCount64;
  form2.ListView1.Column[0].AutoSize := False;
  form2.ListView1.Column[1].AutoSize := False;
  form2.ListView1.Column[2].AutoSize := False;

  form2.ListView1.BeginUpdate;
  form2.ListView1.Clear;
  ti[0] := GetTickCount64 - t;
  t := GetTickCount64;
  For i := 0 To 600 Do Begin
    li := Form2.ListView1.items.add();
    li.Caption := 'Hallo ' + inttostr(i);
    li.SubItems.Add('x');
    li.SubItems.Add('y');
  End;
  ti[1] := GetTickCount64 - t;
  t := GetTickCount64;
  form2.ListView1.EndUpdate;
  ti[2] := GetTickCount64 - t;
  t := GetTickCount64;
  form2.Show;
  ti[3] := GetTickCount64 - t;
  t := GetTickCount64;
  s := '';
  For i := 0 To 3 Do Begin
    s := s + inttostr(ti[i]) + LineEnding;
  End;
  label1.caption := s;
  button1.enabled := true;
End;  
Damit geht die Ladezeit runter auf 300ms, und bei 6k Einträgen auf 2,6s, Die Richtung ist schon gut, aber bei weitem nicht akzeptabel. Ich werde mal diese Ownerdata geschichte die wp_xyz vorgeschlagen hat testen, dass macht mir einen guten Eindruck ..
--
Just try it

wp_xyz
Beiträge: 4892
Registriert: Fr 8. Apr 2011, 09:01

Re: Performance Probleme mit TListview

Beitrag von wp_xyz »

corpsman hat geschrieben:
Mo 14. Feb 2022, 11:08
Ich werde mal diese Ownerdata geschichte die wp_xyz vorgeschlagen hat testen, dass macht mir einen guten Eindruck ..
Der Vollständigkeit halber: Du musst die Daten außerhalb der ListView abspeichern, z.B. in einer TList, oder einem Array oder wie auch immer. Im OnData-Handler host du dir die Daten mit dem gewünschten Index (Item.Index) und füllst damit den TListItem.

Benutzeravatar
theo
Beiträge: 10498
Registriert: Mo 11. Sep 2006, 19:01

Re: Performance Probleme mit TListview

Beitrag von theo »

corpsman hat geschrieben:
Mo 14. Feb 2022, 11:08
Ich werde mal diese Ownerdata geschichte die wp_xyz vorgeschlagen hat testen
Das hatte ich weiter oben auch schon vorgeschlagen, hat aber - wie so oft - niemanden interessiert.
Muss ich "blumiger" schreiben, damit man meine Tipps zur Kenntnis nimmt? :lol:

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Performance Probleme mit TListview

Beitrag von corpsman »

Also das Ownerzeug ist eigentlich recht cool und scheint auch Zackig zu sein:

Code: Alles auswählen

Procedure TForm3.ListView1Data(Sender: TObject; Item: TListItem);
Begin
  item.Caption := fListViewData[item.Index].Left;
  If item.SubItems.Count < 2 Then Begin
    item.SubItems.Add('');
    item.SubItems.Add('');
  End;
  item.SubItemImages[0] := fListViewData[item.Index].Direction;
  item.SubItems[1] := fListViewData[item.Index].Right;
End;
Wenn man nicht mehr mit den Subitems arbeiten muss sieht das auch besser im Code aus.
Aber was noch echt störend ist, dass das jedes mal wenn ich meine Daten ändere der Cursor in der Listview wieder in die 1. Zeile Springt

Code: Alles auswählen

Procedure TForm3.ListView1KeyDown(Sender: TObject; Var Key: Word;
  Shift: TShiftState);
Var
  i: Integer;
Begin
  // STRG + A = Alles Markieren
  If (ssCtrl In shift) And (key = ord('A')) Then Begin // Hier Springt natürlich nichts
    For i := 0 To ListView1.Items.Count - 1 Do Begin
      ListView1.Items[i].Selected := true;
    End;
    exit;
  End;
  If key = ord('N') Then Begin // Hier der Sprung in Zeile 1 obwohl sich der Cursor nicht verschieben sollte
    For i := 0 To ListView1.Items.Count - 1 Do Begin
      If ListView1.Items[i].Selected Then Begin
        fListViewData[i].Direction := IndexDoNothing;
      End;
    End;
  End;
  If key = ord('R') Then Begin // Hier der Sprung in Zeile 1 obwohl sich der Cursor nicht verschieben sollte
    For i := 0 To ListView1.Items.Count - 1 Do Begin
      If ListView1.Items[i].Selected Then Begin
        fListViewData[i].Direction := IndexLeftToRight;
      End;
    End;
  End;
  If key = ord('L') Then Begin // Hier der Sprung in Zeile 1 obwohl sich der Cursor nicht verschieben sollte
    For i := 0 To ListView1.Items.Count - 1 Do Begin
      If ListView1.Items[i].Selected Then Begin
        fListViewData[i].Direction := IndexRightToLeft;
      End;
    End;
  End;
End;
--
Just try it

sstvmaster
Beiträge: 576
Registriert: Sa 22. Okt 2016, 23:12
OS, Lazarus, FPC: W10, L 2.2.6
CPU-Target: 32+64bit
Wohnort: Dresden

Re: Performance Probleme mit TListview

Beitrag von sstvmaster »

corpsman hat geschrieben:
Mo 14. Feb 2022, 11:35
...
Aber was noch echt störend ist, dass das jedes mal wenn ich meine Daten ändere der Cursor in der Listview wieder in die 1. Zeile Springt
...
Dann nimm doch wie hier: https://forum.lazarus.freepascal.org/in ... #msg375975 die CenterItem Procedure.

Hatte ich dir hier: viewtopic.php?p=126850#p126850 auch schon mal geschrieben.
LG Maik

Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)

Antworten