ListView Geschwindigkeit
-
Hallo...
ich möchte mit folgendem Code eine Dateiliste erstellen. Leider dauert das Einlesen ziehmlich lange. Hat jemand einige Tipps, wo die Geschwindigkeit verlohren geht, und wieso die Listview so oft neu gezeichnet wird ?
void __fastcall TForm1::OrdnerEinlesen() { TListItem *MeinLinkesItem; TStringList *TempList = new TStringList; SHFILEINFO FileInfo; BY_HANDLE_FILE_INFORMATION lpFileInfo; TIcon *MyIcon = new TIcon(); WORD wTemp; AnsiString MyAttribut = ""; int attrnr = 0; TSearchRec sr; int iAttributes = faAnyFile; SYSTEMTIME sysTime; FILETIME filetime; TDateTime dtFileCreated; // enthält Erstellungsdatum //TDateTime dtFileLastModified; // enthält Datum der letzten Änderung AnsiString DateiName; DWORD DWattrnr; AnsiString StringListString; if (FindFirst(VerzeichnisUndErweiterung, iAttributes, sr) == 0) { do { attrnr = sr.Attr; if (BOOL(attrnr & FILE_ATTRIBUTE_DIRECTORY)) { DateiName = ExtractFileName(sr.Name); StringListString = DateiName; TempList->Add(StringListString); } } while (FindNext(sr) == 0); FindClose(sr); } if(TempList->Count != 0) { //TempList->Sort(); int LoeschIndex = TempList->IndexOf("."); if(LoeschIndex != -1) { TempList->Delete(LoeschIndex); } LoeschIndex = TempList->IndexOf(".."); if(LoeschIndex != -1) { TempList->Delete(LoeschIndex); } VerzeichnisZaehler = TempList->Count; int DateiNameZaehler = 0; if(UnterVerzeichnis == true) { MeinLinkesItem = Form1->ListView1->Items->Add(); MeinLinkesItem->Caption = ".."; MeinLinkesItem->ImageIndex = 3; MeinLinkesItem->SubItems->Add(""); MeinLinkesItem->SubItems->Add("<DIR>"); MeinLinkesItem->SubItems->Add(UnterVerzeichnisDatum); MeinLinkesItem->SubItems->Add(UnterVerzeichnisAttribut); Form1->ListView1->Update(); } for(DateiNameZaehler; DateiNameZaehler< TempList->Count; DateiNameZaehler++) { //SendMessage(ListView1->Handle, WM_SETREDRAW, FALSE, 0); //Neuzeichnen //deaktivieren DateiPfad = VerzeichnisPfad; AppendStr(DateiPfad,TempList->Strings[DateiNameZaehler]); //--------------------------------------------------------------------------- /////////////////////// //Start Icon auslesen// /////////////////////// SHGetFileInfo(DateiPfad.c_str(),0,&FileInfo,sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_SMALLICON); MyIcon->Handle = FileInfo.hIcon; Form1->ImageList3->AddIcon(MyIcon); /* /////////////////////////// //Icon in Image1 anzeigen// ////////////////////////// Form1->Width+=8; TImage *NeuesImage = new TImage(this); NeuesImage->Parent = Form1; NeuesImage->Top = 256; NeuesImage->Left = 380; NeuesImage->Width = 20; NeuesImage->Height = 20; TIcon *Icon = new TIcon; Icon->Handle=CopyIcon(FileInfo.hIcon); NeuesImage->AutoSize=true; NeuesImage->Stretch=false; NeuesImage->Picture->Assign(Icon); delete Icon; //////////////////////////////// //Ende Icon in Image1 anzeigen// //////////////////////////////// */ ////////////////////// //Ende Icon auslesen// ////////////////////// //--------------------------------------------------------------------------- //DateiErweiterung = ExtractFileExt(DateiPfad); //--------------------------------------------------------------------------- DateiName = ExtractFileName(DateiPfad); //DateiName = StringReplace(DateiName,DateiErweiterung,"",TReplaceFlags() << rfIgnoreCase); ////////////////////////////////////////////////////////// //Ordner-Erweiterung in der Spalte Erweiterung anzeigen// //////////////////////////////////////////////////////// //--------------------------------------------------------------------------- FindFirst(DateiPfad, iAttributes, sr); FindClose(sr); //--------------------------------------------------------------------------- //AnsiString DateiGroesse2 = FormatFloat("#,###",lpFileInfo.nFileSizeLow); //--------------------------------------------------------------------------- /* SYSTEMTIME sysTime; FILETIME filetime; FileTimeToLocalFileTime(&lpFileInfo.ftLastAccessTime, &filetime); FileTimeToSystemTime(&filetime, &sysTime); SystemTimeToDateTime(sysTime); AnsiString DateiZeit = FormatFloat("00",sysTime.wDay); AppendStr(DateiZeit,"."); AppendStr(DateiZeit,FormatFloat("00",sysTime.wMonth)); AppendStr(DateiZeit,"."); AppendStr(DateiZeit,FormatFloat("####",sysTime.wYear)); AppendStr(DateiZeit," "); AppendStr(DateiZeit,FormatFloat("00",sysTime.wHour)); AppendStr(DateiZeit,":"); AppendStr(DateiZeit,FormatFloat("00",sysTime.wMinute)); AppendStr(DateiZeit,":"); AppendStr(DateiZeit,FormatFloat("00",sysTime.wSecond)); AppendStr(DateiZeit,":"); AppendStr(DateiZeit,FormatFloat("000",sysTime.wMilliseconds)); */ //--------------------------------------------------------------------------- //------------Beispiel CPP.DE------------------------------------------------ //--------------------------------------------------------------------------- FileTimeToSystemTime(&(sr.FindData.ftCreationTime), &sysTime); dtFileCreated = TDateTime(sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds) + TDateTime(sysTime.wYear, sysTime.wMonth, sysTime.wDay); //FileTimeToSystemTime(&(sr.FindData.ftLastWriteTime), &sysTime); //dtFileLastModified = TDateTime(sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds) //+ TDateTime(sysTime.wYear, sysTime.wMonth, sysTime.wDay); DateiZeit = dtFileCreated; //--------------------------------------------------------------------------- //------------Beispiel CPP.DE------------------------------------------------ //--------------------------------------------------------------------------- DWattrnr = sr.Attr; //DWORD DWattrnr = GetFileAttributes(DateiPfad.c_str()); //Gibt bei Dateien, die //in Verwendung sind //keine Attribute aus! MyAttribut = ""; if (BOOL(DWattrnr & FILE_ATTRIBUTE_DIRECTORY)) { if (BOOL(DWattrnr & FILE_ATTRIBUTE_READONLY)) { AppendStr(MyAttribut,"R"); } else { AppendStr(MyAttribut,"-"); } if (BOOL(DWattrnr & FILE_ATTRIBUTE_ARCHIVE)) { AppendStr(MyAttribut,"A"); } else { AppendStr(MyAttribut,"-"); } if (BOOL(DWattrnr & FILE_ATTRIBUTE_HIDDEN)) { AppendStr(MyAttribut,"H"); } else { AppendStr(MyAttribut,"-"); } if (BOOL(DWattrnr & FILE_ATTRIBUTE_SYSTEM)) { AppendStr(MyAttribut,"S"); } else { AppendStr(MyAttribut,"-"); } } //--------------------------------------------------------------------------- MeinLinkesItem = Form1->ListView1->Items->Add(); MeinLinkesItem->Caption = DateiName; MeinLinkesItem->SubItems->Add(""); //if(DateiName.LowerCase() == "$recycle.bin" && DateiErweiterung.LowerCase() == ".bin") if(DateiName.LowerCase() == "$recycle.bin") { MeinLinkesItem->ImageIndex = 0; } else { MeinLinkesItem->ImageIndex = Form1->ImageList3->Count-1; } //MeinLinkesItem->SubItems->Add(DateiErweiterung); //if (BOOL(attrnr & FILE_ATTRIBUTE_DIRECTORY)) if (!BOOL(DWattrnr & FILE_ATTRIBUTE_REPARSE_POINT)) { MeinLinkesItem->SubItems->Add("<DIR>"); } if (BOOL(DWattrnr & FILE_ATTRIBUTE_REPARSE_POINT)) { MeinLinkesItem->SubItems->Add("<LINK>"); } MeinLinkesItem->SubItems->Add(DateiZeit); MeinLinkesItem->SubItems->Add(MyAttribut); Form1->ListView1->Update(); //SendMessage(ListView1->Handle, WM_SETREDRAW, FALSE, 0); //Neuzeichnen //deaktivieren //Form1->Caption = DateiPfad; } //delete MeinLinkesItem; delete TempList; delete MyIcon; //SendMessage(ListView1->Handle, WM_SETREDRAW, TRUE, 0); //Neuzeichnen } //aktivieren } //---------------------------------------------------------------------------==>Eisbeer<==
-
- ListView->Items->BeginUpdate();
- ListView füllen
- ListView->Items->EndUpdate();
Damit setzt das ListView seine Aktualisierungen so lange aus, bis alle Elemente drin sind. Geht deutlich schneller

-
Bei wirklich vielen Einträgen hilft nur ein VirtualListView.
Im examples-Verzeichnis des BCB sollte sich dazu ein Beispiel finden.
-
Für ein ähnliches Problem mit vielen Daten (> 10.000) hatte ich die Einleseroutine in einen Thread ausgelagert und nur jede Sekunde aktualisiert.
Es lassen sich ca. 1000 Einträge pro Sekunde in die ListView eintragen...Aber sicherlich ist eine VritualListView am besten.
-
ListView1->Items->BeginUpdate();
ListView füllen
ListView1->Items->EndUpdate();Form1->ListView1->Items->Count = TempList->Count;
TempList->Sort(); deaktiviert
== Funktioniert leider alles nicht wie gewünscht.
was meint ihr mit VirtualListView das Beispiel hilft mir nicht wirklich weiter.
==>Eisbeer<==
-
Eine VirtualListView dient dazu, den Einlesevorgang zu beschleunigen und nur dir Daten zu holen, welche auch gerade angezeigt werden sollen.
Für dein Beispiel heißt das, daß du eigentlich nur erst die Dateinamen (+Pfad) ermitteln bräuchtest. Erst wenn die ListView gescrollt wird, würden dann die restlichen Daten nachgeladen (quasi eine Art Caching).
Mittels "TListView::OwnerDraw = true" würdest du eine VirtualListView erzeugen.
Dann dient das OnData-Ereignis dazu, die weiteren Daten des Eintrags (Datum, Attribute, Icon, ...) der ListView hinzuzufügen.Da man ja meist nur einen geringen Ausschnitt der gesamten Liste sieht, lohnt sich diese Vorgehensweise.
Du solltest deinen Source-Code am besten auch mal besser formatieren und strukturieren (viele Code-Zeilen könntest du in eigene Funktionen packen).
Am besten du fängst noch mal von vorne an und läßt dir ersteinmal nur die Dateinamen anzeigen (dies sollte eigentlich sehr schnell gehen) und dann fügst du nach und nach die weiteren Infos hinzu.
Und du darfst natürlich nicht mehr "ListView->Update()" nach jedem Hinzufügen eines Eintrags aufrufen.
-
Wenn ich das ubdaten deaktiviere, wird der Inhalt erst angezeigt, sobalt alle Einträge in der ListView sind.
Auch das Auslagern in einen eingenen Thread brachte keinen Erfolg.
Das mit der VirtualListView habe ich verstanden. Hapert nur noch an der Umsetzung. (Wie kriege ich die Daten aus der StringList dann in die ListView...)
Als Erstes wird ja nur eine StringListe generiert, die sämtliche Pfade enthält.
Nur wieso wird nicht ein Eintrag gelesen, hinzugefügt und dann der Nächste ?
Auf jeden Fall erstmal danke für die bisherigen Tipps.
==>Eisbeer<==
-
Selbst wenn die Daten direkt in die ListView geschrieben werden funktioniert es nicht ???
if (FindFirst(VerzeichnisUndErweiterung, iAttributes, sr) == 0) { do { attrnr = sr.Attr; if (BOOL(attrnr & FILE_ATTRIBUTE_DIRECTORY)) { DateiName = ExtractFileName(sr.Name); MeinLinkesItem = Form1->ListView1->Items->Add(); MeinLinkesItem->Caption = DateiName; } } while (FindNext(sr) == 0); FindClose(sr); }==>Eisbeer<==
-
Was genau funktioniert nicht?
Welche Inhalte haben denn VerzeichnisUndErweiterung und iAttributes?
-
int iAttributes = faAnyFile; AnsiString VerzeichnisUndErweiterung = "C:\Windows\System32\*.*";Es werden einfach nicht alle elemente nacheinander angezeigt, sondern die ganze Liste auf Einmal.
Ich versuche mich gerade an der VirtualListView-Methode. Diese ist schon deutlich schneller, zeigt aber die Liste auch erst an, wenn alle Elemente eingelesen wurden.
==>Eisbeer<==
-
Guten Abend...
Anbei meine Gehversuche mit der VirtualListView...
Ich verstehe nur nicht, wieso die ListView erst angezeigt wird, wenn alle Elemente durchgegangen wurden.
Gibt´s ne Möglichkeit, dies zu beschleunigen ?
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { //Hint-Anzeige der ListView deaktivieren SendMessage(ListView1->Handle, LVM_SETTOOLTIPS, 0, 0); //Button benennen und als aktiev markieren Form1->Button1->Caption = "Füllen"; ActiveControl = Button1; //Aktives Steuerelement Form1->Button2->Caption = "Clear"; //--------------------------------------------------------------------------- //Eigenschaften von ListView1 einstellen und Spaltebbezeichnungen hinzufügen Form1->ListView1->ViewStyle = vsReport; Form1->ListView1->RowSelect = true; Form1->ListView1->OwnerData = true; TListColumn *MeinLinkesColumn; MeinLinkesColumn = Form1->ListView1->Columns->Add(); MeinLinkesColumn->Width = 73; MeinLinkesColumn->Caption = "Name"; MeinLinkesColumn = Form1->ListView1->Columns->Add(); MeinLinkesColumn->Width = 50; MeinLinkesColumn->Caption = "Erw."; MeinLinkesColumn = Form1->ListView1->Columns->Add(); MeinLinkesColumn->Width = 60; MeinLinkesColumn->Caption = "Groesse"; MeinLinkesColumn = Form1->ListView1->Columns->Add(); MeinLinkesColumn->Width = 132; MeinLinkesColumn->Caption = "Datum"; MeinLinkesColumn = Form1->ListView1->Columns->Add(); MeinLinkesColumn->Width = 42; MeinLinkesColumn->Caption = "Attr."; //--------------------------------------------------------------------------- //Variablen festlegen VerzeichnisPfad = "C:\\windows\\system32\\"; DateiTyp = "*.*"; VerzeichnisUndErweiterung = ""; AppendStr(VerzeichnisUndErweiterung,VerzeichnisPfad); AppendStr(VerzeichnisUndErweiterung,DateiTyp); //--------------------------------------------------------------------------- FileList = new TList; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { //TStringList *TempList = new TStringList; int attrnr = 0; TSearchRec sr; int iAttributes = faAnyFile; AnsiString DateiName; DWORD DWattrnr; if (FindFirst(VerzeichnisUndErweiterung, iAttributes, sr) == 0) { do { attrnr = sr.Attr; if (BOOL(attrnr & FILE_ATTRIBUTE_DIRECTORY)) { //DateiName = ExtractFileName(sr.Name); //TempList->Add(DateiName); TFileItem* fi = new TFileItem; fi->DateiName = ExtractFileName(sr.Name); fi->DateiErweiterung = "...Erw..."; fi->DateiGroesse = "...Groesse..."; fi->DateiZeit = "...DateiZeit..."; fi->DateiAttribut = "...Attr..."; FileList->Add(fi); Form1->Caption = FileList->Count; ListView1->Items->Count = FileList->Count; } } while (FindNext(sr) == 0); FindClose(sr); //ListView1->Items->Count = FileList->Count; } //--------------------------------------------------------------------------- } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { Form1->ListView1->Clear(); Form1->Caption = "0"; Form1->FileList->Clear(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item) { TFileItem* fi = (TFileItem*)FileList->Items[Item->Index]; Item->Caption = fi->DateiName; Item->SubItems->Add(fi->DateiErweiterung); Item->SubItems->Add(fi->DateiGroesse); Item->SubItems->Add(fi->DateiZeit); Item->SubItems->Add(fi->DateiAttribut); } //---------------------------------------------------------------------------==>Eisbeer<==
-
Geschwindigkeits-Problem gelößt...
in der DoWhile-Schleife nach
ListView1->Items->Count = FileList->Count;Form1->ListView1->Update();einfügen und es funktioniert wie gewünscht...
Könnte mir jemand sagen, wie ich aus der TList eine TStringList machen kann ?????? (Müde) wenn nicht heute, dann bieg´ ich´s morgen zurecht...
==>Eisbeer<==
-
Hallo
Indem du dir Werte aus dem TListView über eine Schleife in eine TStringList kopierst.
bis bald
akari
-
Danke akari...
War gestern nicht mehr fit. Die TList kann so bleiben. Die Geschwindigkeit verliere ich beim Auslesen der Icons.
SHGetFileInfo(DateiPfad.c_str(),0,&FileInfo,sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_SMALLICON); MyIcon->Handle = FileInfo.hIcon; Form1->ImageList3->AddIcon(MyIcon);Kennt jemand ´ne schnellere Methode ?
==>Eisbeer<==