TListView schnell laden
-
Hi,
hier mal der Code:
//ListView füllen for(int i = 0; i < iAnzahl-1; ++i) { if(strcmp(logEntries[i].Date.c_str(), "\0") == 0) { if(i != 0 && ListView->Items->Count != 0) { AnsiString sTemp = ListView->Items->Item[ListView->Items->Count-1]->SubItems->Strings[6]; sTemp += logEntries[i].Message.c_str(); sTemp += ";"; ListView->Items->Item[ListView->Items->Count-1]->SubItems->Strings[6] = sTemp; } } else { TListItem *item = ListView->Items->Add(); item->Caption = logEntries[i].Date.c_str(); item->SubItems->Add(logEntries[i].Time.c_str()); item->SubItems->Add(logEntries[i].Modul.c_str()); item->SubItems->Add(logEntries[i].Line.c_str()); item->SubItems->Add(logEntries[i].Thread.c_str()); item->SubItems->Add(logEntries[i].Process.c_str()); item->SubItems->Add(logEntries[i].Severity.c_str()); item->SubItems->Add(logEntries[i].Message.c_str()); } LoadForm->stepProgressBar(); LogEntry listEntry; listEntry.Date = logEntries[i].Date; listEntry.Time = logEntries[i].Time; listEntry.Modul = logEntries[i].Modul; listEntry.Line = logEntries[i].Line; listEntry.Thread = logEntries[i].Thread; listEntry.Process = logEntries[i].Process; listEntry.Severity = logEntries[i].Severity; listEntry.Message = logEntries[i].Message; this->m_lLogEntry.push_back(listEntry); if(i%100 == 0) ListView->Repaint(); }
-
Sorry, bin irgendwie auf ne Taste gekommen, dass der den Beitrag schon postet.
Das logentries[] ist ne Liste in die ich das File schon eingelsen hab. Das mach ich mit der Boost Library. Aber das dauert nicht lang. Die meiste Zeit nimmt der gepostete Code in Anspruch. Hab das schon gemessen.
Werd mir das Beispiel mal anschauen!!!
Gruß
-
Du solltest vor dem Bearbeiten des ListViews
ListView->Items->BeginUpdate()
schreiben, und am Ende
ListView->Items->EndUpdate()
dadurch wird der Listview nicht bei jeder Änderung neu gezeichnet, sondern erst, wenn du fertig bist mit Ändern.
mfg
xXx
-
Das hat er ja schon gemacht.
@_gast_
Verwende bitte die Code-Tags. So ist das etwas schlecht zu lesen.
Ich nehmen mal an, du verwendest std::string. Hiermit willst du wohl testen ob der String leer istif(strcmp(logEntries[i].Date.c_str(), "\0") == 0)
einfacher so
if(logEntries[i].Date.empty())
-
Hi,
danke für die Hinweise, aber das mit dem BeginUpdate() und EndUpdate() hab ich schon drin. Und das mit der empty-Abfrage hab ich eingebaut und es bringt nicht viel zwei, drei Sekündchen.
Hat vielleicht jmd von euch noch noch Beispiel für einen virtual ListView, ausser dem das bei C++ Builder in den Examples steht?
Gruß
-
Wofür ist denn das Repaint am Ende der Schleife (bei 30000 Einträgen werden dann ja 300 Repaint-Aufrufe gemacht)?
P.S. Wie zeitraubend ist denn die Methode "LoadForm->stepProgressBar()", da die jedesmal aufgerufen wird?
Ich selber hatte auch schon das Problem mit ListView und großen Daten.
Ich habe dann das Hinzufügen der Daten in einen eigenen Thread ausgelagert, so daß der Anwender in der Zwischenzeit schon mal weiterarbeiten kann, während die ListView gefüllt wird.
-
Ich habe in solchen Fällen einfach LockWindowUpdate() verwendet. Kann natürlich
sein, dass BeginUpdate()/EndUpdate() was ähnliches bewirkt.Gruß
Alexander
-
Will man viele Daten in einer ListView anzeigen, kann man die mit dem Ereignis "OnData" machen (Wie im Borland-Beispiel VirtualListView).
Hier ein kleines Beispiel:
#include <vcl.h> #pragma hdrstop #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" #define ANZAHLDATEN 30000 TForm1 *Form1; TList *MeineDaten; struct Daten { String vorname; String nachname; Daten(String Vorname, String Nachname) { vorname = Vorname; nachname = Nachname; } }; //--------------------------------------------------------------------------- String ZufallsString() { int length = random(10) + 3; String zstring = ""; char chars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (int i=0;i<length;i++) { zstring += chars[ random( strlen(chars) ) ]; } return zstring; } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner){} //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { randomize(); //Hier sammeln wir unsere Daten drin MeineDaten = new TList(); //OwnerData auf true setzen, sonst geht das Beispiel nicht ListView1->OwnerData = true; ListView1->RowSelect = true; ListView1->ViewStyle = vsReport; //Zwei Spalten einfügen TListColumn *column = ListView1->Columns->Add(); column->Caption = "Index"; column = ListView1->Columns->Add(); column->Caption = "Spalte1"; column = ListView1->Columns->Add(); column->Caption = "Spalte2"; //Dummydaten erzeugen for(int i=0;i<ANZAHLDATEN;i++) { MeineDaten->Add( new Daten( ZufallsString() , ZufallsString() ) ); } //ListView-Inhalt anzeigen FuelleView(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item) { if ((Item->Index < MeineDaten->Count)) { Daten *d =(Daten*)MeineDaten->Items[Item->Index]; Item->Caption = IntToStr(Item->Index); Item->SubItems->Add(d->vorname); Item->SubItems->Add(d->nachname); } } //--------------------------------------------------------------------------- void TForm1::FuelleView(void) { ListView1->Items->Count = MeineDaten->Count; ListView1->Items->BeginUpdate(); try { if (ListView1->Items->Count > 0) { //Erste Element markieren ListView1->Selected = ListView1->Items->Item[0]; ListView1->Selected->Focused = true; ListView1->Selected->MakeVisible(false); } } __finally { ListView1->Items->EndUpdate(); } }
MfG Barracuda
-
@Barracuda: coole Sache funktioniert echt flott
Danke dir!
Habe meine code gleich mal darauf abgestimmt und siehe da 10.000 entries 2 Sek.
Hänge hier jedoch noch an funktionen die direkt auf ein Item eines TListView zugreifen und z.B. den ImageIndex des Items ändern wollen ?? Könnte jemand dem obigen Beispiel noch ein OnButtonClick hinzufügen was "direkt" ein Item verändert.
Danke, und frohe feier tage (ferien) ... :xmas1:
-
Ich grabe den Thread nochmal aus...
Habe das jetzt so implementiert, aber irgendwie klappts bei mir noch nicht. Ich habe mit dem Debugger mal in das "OnData"-Event reingeschaut und festgestellt, dass sich Item->Index nie ändert und immer auf 0 bleibt.
Hier ist mal mein Code:
void TMainWindow::showSelectedModule() { string module = lv_moduleList->Selected->Caption.c_str();//lv_moduleList enthält eine Liste mit Dateipfaden functionList.initModulefuncList(module); //Liste wird nach Modulnamen sortiert; modulfuncVector wird erstellt //Ab hier wird wichtig ;-) m_MeineDaten = new TList(); for(int n = 0; n < functionList.getModulefunclistSize(); n++) //functionList enthält einen Vektor der Objekte vom Typ TModuleFunction enthält { m_MeineDaten->Add(&functionList.getModulefunctionAt(n)); } lv_moduleView->Items->Count = m_MeineDaten->Count; lv_moduleView->Items->BeginUpdate(); try { if (lv_moduleView->Items->Count > 0) { lv_moduleView->Selected = lv_moduleView->Items->Item[0]; lv_moduleView->Selected->Focused = true; lv_moduleView->Selected->MakeVisible(false); } } __finally { lv_moduleView->Items->EndUpdate(); } } void __fastcall TMainWindow::lv_moduleViewData(TObject *Sender, TListItem *Item) { if ((Item->Index < m_MeineDaten->Count)) { TModuleFunction *tempfunc =(TModuleFunction*)m_MeineDaten->Items[Item->Index]; Item->Caption = tempfunc->getTimestamp().c_str(); Item->SubItems->Add(tempfunc->getState().c_str()); Item->SubItems->Add(tempfunc->getFuncname().c_str()); Item->SubItems->Add(tempfunc->getDuration().c_str()); } }
An sich haargenau das gleiche wie Barracuda gepostet hat, bloß an mein Programm angepasst oder?
Also die Werte die in "tempfunc" stehen sind immer die gleichen.
Oder liegt das daran dass man bei solchen Events schwer mit Debugger arbeiten kann und er mir deshalb immer die gleichen Werte anzeigt?
edit: Habs gelöst. Da ich ja schon einen Vektor mit Daten habe brauchste ioch die TList ja gar nicht
Also alles was mit T-List zu tun hatte rausgeschmissen und durch ven Vektor ersetzt und siehe da...läuft ^^