![]() |
Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
So sieht meine füll routine aus:
Delphi-Quellcode:
Lasse ich das Icon laden weg = hab ich fast sofort die Ergebnisse dargestellt
in .dfm
object FileIcons: TImageList BlendColor = clGradientInactiveCaption BkColor = 15918295 Masked = False Left = 632 Top = 32 end ... FileIcons: TImageList; ... procedure DoIt(); var i: Integer; SL2: TStringDynArray; SL2idx: Integer; Icon: TIcon; dummy: Word; begin dummy := 0; SL2idx := 0; SetLength( SL2, 1 ); ...code um SL zu füllen... if SL2idx > 0 then Dec( SL2idx ); SetLength( SL2, SL2idx ); Icon := TIcon.Create; Icon.Transparent := True; lvFiles.Items.BeginUpdate; for i := 0 to Length( SL2 ) -1 do with lvFiles.Items.Add() do begin if cbUseIcons.Checked then Icon.Handle := ExtractAssociatedIcon( hInstance, PWideChar( SL2[ i ] ), dummy ); Icon.Transparent := True; ImageIndex := FileIcons.AddIcon( Icon ); DestroyIcon( Icon.Handle ); Caption := SL2[ i ]; end; lvFiles.Items.EndUpdate; Icon.Free; end; Nehm ich Icon mit rein dauert es teilweise ewig. Mach ich da was falsch? |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Lädst du mit ExtractAssociatedIcon ein Icon einer Datei? Wenn ja liegt es an diesen IO-Zugriffen. SHGetFileInfo ist eventuell schneller.
Besser ist es aber die Icons schon vorher in eine ImageList zu laden und dann direkt von der ImageList ins ListView zu transportieren. |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Daten- / Iconmenge?
Programm beim Laden der Icons minimieren, damit nicht dauernd "neu gemalt" wird. irgendwie sowas:
Delphi-Quellcode:
Die Bildschirmausgabe ist nachwievor das Langsamste bei Programmen ;-)
Application.Minimize;
lvFiles.Items.BeginUpdate; ... lvFiles.Items.EndUpdate; Application.Restore; |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
SHGetFileInfo hatte ich vorher, liefert aber nicht immer das zurück was ich möchte. Zwischen den beiden ist kein Nennenswerter Geschwindigkeits-Unterschied.
Ja die IO Zugriffe sind da enorm beansprucht, da falls kein Icon in Datei sein sollte sucht Windows nach dem nächst besten (also mit ExtractAssociatedIcon, die SH-Variante gibt da zu schnell auf und liefert blanko-Template wieder, was nicht unbedingt ein schnelleres Ergebnis bedeutet) Was ich allerdings im Hinterkopf habe, wenn ich ListView mit ShellListView-Demo vergleiche, bei der Shell-Variante ist ein kompletter Dateipfad schwupps die wupps geladen, sogut wie Verzögerungsfrei. Selbst bei Ordnern mit mehreren Tausend Dateien. Vielleicht kann ich das ja irgendwie für mich Nutzbar machen, am Ende bleibt es ja eine ListView. Danke für die Idee es vorher in die ImageList zu laden und beim ListView.Add() nurnoch index dahin setzen, werde ich auf jeden Fall mal ausprobieren, ob es schneller geht, wer weiß :) |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Probier mal ein
Delphi-Quellcode:
um den Ladevorgang zu legen.
FileIcons.BeginUpdate/EndUpdate
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Zitat:
Ich melde mich nach Tests wieder. Dateimenge sind mal 50 mal 500, selten mehr. Aber selbst bei 20-30 Dateien dauert es manchmal 20-30 sekunden. Trotz SSD. |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Bin mit guten Nachrichten zurück, also das FileIcons.Begin/EndUpdate brachte schonmal etwas boost, rein objektiv Betrachtet.
Delphi-Quellcode:
aber das wirkt tatsächlich Wunder, kann ich nur Weiterempfehlen! Besten Dank für Tipps, hab ich aufgesaugt und werde es mir merken!
Application.Minimize;
lvFiles.Items.EndUpdate; FileIcons.EndUpdate; Application.Restore; Application.BringToFront; Ich teste jetzt noch ob das füllen der Icons seperat vom ListView.Add() was bringt. Beste Grüße! |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Spontan und komplex:
Ob ein Thread hier hilft, bin ich mir nicht sicher, da es ja um Icon-Handles geht, die im Haupthread stehen müssen. Aber mindestens die Liste laden und erst danach im OnIdle die Icons stückweise nachladen könnte eine Option sein? Oder nur die Icons der in der Liste aktuell sichtbaren Einträge laden und die anderen beim Scrollen nachladen? Ggfls auch Icons cachen, macht die Shell ja auch. |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
@CCRDude, die Idee gefällt mir, sehr sogar!
Also Icon routine komplett aus meiner Füll methode raus, wenn die fertig ist einen Thread starten der dann poe á poe Icons cached und in ListView das Index dafür setzt. Hab ich ehrlich gesagt noch nie probiert, cooler Gedanke, das werde ich mal separat testen. Ob mein MainThread momentan hängt kann mir ziemlich egal sein denn ohne ListView kann das Teil nichts :-] |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Hm...würde mir einer mal erklären, warum BeginUpdate und EndUpdate einer ListView nicht ausreichen, und zusätzlich noch das Minimize btw. Restore mehr Geschwindigkeit bringen soll?
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Zitat:
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Ist 'ne langjährige praktische Erfahrung / Beobachtung, die man halt ausnützen kann, wenn was schneller gehen soll. Und ja @DieDolly, anwenderfreundlich ist was anderes ;-) |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Delphi-Quellcode:
Ich habe die Idee mit Thread mal auf diese Weise ausprobiert, also Geschwindigkeit boost ohne ende, aber irgendwas mach ich da noch falsch, jetzt werden viele Icons nicht korrekt geladen.
procedure TfrmMain.StartIcons();
begin TThread.CreateAnonymousThread(procedure () var LIcon: TIcon; I: Integer; dummy: Word; begin dummy := 0; LIcon := TIcon.Create; LIcon.Transparent := True; try lvFiles.Update; FileIcons.BeginUpdate; for i := 0 to lvFiles.Items.Count -1 do begin LIcon.Handle := ExtractAssociatedIcon( hInstance, PWideChar( lvFiles.Items.Item[ i ].Caption ), dummy ); LIcon.Transparent := True; lvFiles.Items.Item[ i ].ImageIndex := FileIcons.AddIcon( LIcon ); DestroyIcon( LIcon.Handle ); end; TThread.Synchronize (TThread.CurrentThread, procedure () begin end); finally FileIcons.EndUpdate; LIcon.Free; end; end).Start; end; |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Niemals unsynchronisiert aus einem Thread heraus auf VCL-Controls zugreifen, das ist eine uralte Weisheit.
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Im Moment macht Synchronize gar nichts. Und dann kannst du auch nicht sicher sein ob Synchronize das richtige ist denke mal nicht denn du möchtest ja nicht warten oder? Denn dann dauert es wieder genauso lang. Spiele mal mit Queue und Synchronize rum dann nimm das was am besten für dich ist. gruss |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Wo kommt denn der Geschwindigkeitsvorteil her?
Vorher wurde alles im Mainthread gemacht, jetzt alles in einem einzigen Thread. Die Arbeit wurde 1:1 verlagert. Einen Vorteil hast Du doch erst, wenn Du mehrere Threads auf das Problem loslässt und somit mehrere Kerne nutzt. :gruebel: |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Delphi-Quellcode:
Danke, ich habe es auf diese Weise korrigiert aber das Problem besteht immer noch, ich finde meinen Fehler nicht.
procedure TfrmMain.StartIcons();
begin TThread.CreateAnonymousThread(procedure () var LIcon: TIcon; I: Integer; dummy: Word; begin dummy := 0; LIcon := TIcon.Create; LIcon.Transparent := True; try lvFiles.Update; FileIcons.BeginUpdate; for i := 0 to lvFiles.Items.Count -1 do begin begin LIcon.Handle := ExtractAssociatedIcon( hInstance, PWideChar( lvFiles.Items.Item[ i ].Caption ), dummy ); LIcon.Transparent := True; end; TThread.Synchronize (TThread.CurrentThread, procedure () begin lvFiles.Items.Item[ i ].ImageIndex := FileIcons.AddIcon( LIcon ); end); DestroyIcon( LIcon.Handle ); end; finally FileIcons.EndUpdate; LIcon.Free; end; end).Start; end; |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
DeddyHs Hinweis auf alle VCL-Controls anwenden und nicht nur auf eine Zeile? ;-)
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Du verwendest SendMessage besser wäre PostMessage wenn du nicht warten willst. Zitat:
Du kannst TThread wie eine normale procedure behandeln falls du das nicht weist.
Delphi-Quellcode:
gruss
TThread.Synchronize (TThread.CurrentThread,
procedure () var // Meine Variablen begin // Meine Funktion end); |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Ich hoffe *bet* das ichs jetzt gerafft habe:
Delphi-Quellcode:
procedure TfrmMain.StartIcons();
begin TThread.CreateAnonymousThread(procedure () var LIcon: TIcon; dummy: Word; begin dummy := 0; LIcon := TIcon.Create; LIcon.Transparent := True; try TThread.Synchronize (TThread.CurrentThread, procedure () var I: Integer; begin lvFiles.Update; FileIcons.BeginUpdate; for i := 0 to lvFiles.Items.Count -1 do begin LIcon.Handle := ExtractAssociatedIcon( hInstance, PWideChar( lvFiles.Items.Item[ i ].Caption ), dummy ); LIcon.Transparent := True; lvFiles.Items.Item[ i ].ImageIndex := FileIcons.AddIcon( LIcon ); DestroyIcon( LIcon.Handle ); end; end); finally FileIcons.EndUpdate; LIcon.Free; end; end).Start; end; |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Delphi-Quellcode:
TThread.Synchronize (TThread.CurrentThread,
Bist sicher? Nicht Nil! Nur mal als sample
Delphi-Quellcode:
function TSessionThread.OnSessionCreated(NewSession: IAudioSessionControl): HResult;
begin Result := S_FALSE; if (MainThreadID <> GetCurrentThreadId) then begin TThread.Queue(nil, procedure var bDuplicate: BOOL; i: Integer; begin if Assigned(FOnAudioSessionCreate) then begin ASessionInfo := GetSessionInfo(NewSession); if ASessionInfo.FileName <> '' then begin // Check to prevent duplicate registeration of audio session bDuplicate := false; for i := 0 to (FSessionCount - 1) do if SessionInfo[i].PID = ASessionInfo.PID then begin // for the case of reuse of same PID (but different programs) if SessionInfo[i].State <> AudioSessionStateExpired then begin bDuplicate := true; Break; end; end; if not bDuplicate then begin inc(FSessionCount); SetLength(SessionInfo, FSessionCount); SessionInfo[FSessionCount - 1] := ASessionInfo; FOnAudioSessionCreate(NewSession, ASessionInfo, FSessionCount); end; end; end; end); Result := S_OK; end; end; Zitat:
Super na ja dann addiere die unbekannten mal zur Imagelist. ;) Ist doch einfach oder? :) gruss |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Mein nächster Versuch, bis jetzt mehr als gescheitert, bin noch auf Fehlersuche.
Hab mal im Soure kommentiert so wie ich es dachte das es funktioniert:
Delphi-Quellcode:
das ist momentan die schnellste variante, da sie nicht funktioniert :-]
//dieses mal mit eingabe
procedure TfrmMain.StartIcons( ListView: TListView; ImageList: TImageList ); begin // hier soll ein Thread abseits des Mainthreads starten um diesen zu entlasten TThread.CreateAnonymousThread(procedure () var // <- locale variablen für den Thread LIcon: TIcon; dummy: Word; I: Integer; LImageList: TImageList; LListView: TListView; begin dummy := 0; LListView := TListView.Create( nil ); LImageList := TImageList.Create( nil ); LIcon := TIcon.Create(); LIcon.Transparent := True; LImageList.BeginUpdate; LImageList.Assign( ImageList ); // <-- lokale kopie der aktuellen liste LListView.Items.BeginUpdate; LListView.Assign( ListView ); // <-- lokale kopie der aktuellen liste try // <-- beginne mit der arbeit an den lokalen kopien for i := 0 to LListView.Items.Count -1 do begin LIcon.Handle := ExtractAssociatedIcon( hInstance, PWideChar( LListView.Items.Item[ i ].Caption ), dummy ); LIcon.Transparent := True; LListView.Items.Item[ i ].ImageIndex := LImageList.AddIcon( LIcon ); DestroyIcon( LIcon.Handle ); end; LImageList.EndUpdate; LListView.Items.EndUpdate; TThread.Synchronize (nil, procedure () // übergebe lokale kopien zurück an vcl begin FileIcons.BeginUpdate; FileIcons.Assign( LImageList ); FileIcons.EndUpdate; lvFiles.Items.BeginUpdate; lvFiles.Assign( LListView ); lvFiles.Items.EndUpdate; end); finally LIcon.Free; LImageList.Free; LListView.Free; end; end).Start; end; |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
![]() |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
OK letzter Tip.. Doublebuffer true?
gruss |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Eigentlich bietet sich TParallel.For hierfür an.
Sherlock |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Zitat:
Zitat:
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Delphi-Quellcode:
geht. Das Code-Beispiel, auf das ich mich bezog, enthält das jedoch genau nicht - wurde aber mit "Geschwindigkeit boost ohne ende" klassifiziert.
TParallel.For
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Wenn man im TParallel.For noch auf die Festplatte zugreifen muss, dann braucht man auch keine TParallel mehr nutzen denn dann schadet das eher. |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Die Thread-Instanz wird in einen Record geschrieben:
Delphi-Quellcode:
und dann wird ein
class procedure TThread.Synchronize(const AThread: TThread; AMethod: TThreadMethod);
var FSynchronize: TSynchronizeRecord; begin FSynchronize.FThread := AThread; // da FSynchronize.FSynchronizeException := nil; FSynchronize.FMethod := AMethod; FSynchronize.FProcedure := nil; Synchronize(@FSynchronize); end; class procedure TThread.Synchronize(const AThread: TThread; AThreadProc: TThreadProcedure); var FSynchronize: TSynchronizeRecord; begin FSynchronize.FThread := AThread; // oder da FSynchronize.FSynchronizeException := nil; FSynchronize.FMethod := nil; FSynchronize.FProcedure := AThreadProc; TThread.Synchronize(@FSynchronize); end;
Delphi-Quellcode:
damit aufgerufen:
TNotifyEvent
Delphi-Quellcode:
der bei einer VCL-Anwendung mit dieser Methode verbunden ist:
class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean = False; ForceQueue: Boolean = False);
var SyncProc: TSyncProc; SyncProcPtr: PSyncProc; begin [...] if Assigned(WakeMainThread) then WakeMainThread(SyncProcPtr.SyncRec.FThread); [...] end;
Delphi-Quellcode:
Wie man sieht, mit der schönen Instanz die mit Sender übergeben wird, wird schon mal gar nichts gemacht.
procedure TApplication.WakeMainThread(Sender: TObject);
begin PostMessage(Handle, WM_NULL, 0, 0); end; (BTW: Bei FMX sieht es auch nicht besser aus) Fazit Es ist völlig egal ob man dort eine Instanz des aktuellen Threads, oder irgendeine Instanz oder eine ungültige oder eben einfach gar keine mit
Delphi-Quellcode:
übergibt. Somit besteht kein Grund zur Sorge, wenn jemand dort eine Instanz übergibt.
nil
Darum sollte man hier auch ganz beherzt ein
Delphi-Quellcode:
übergeben, denn das ist kürzer und gaukelt auch keine sonstige Funktionalität vor.
nil
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
(Mal davon ausgehend, dass durch die Sammelroutine nicht noch andere Controls verändert werden). |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Hab' letzlich ein Programm geschrieben, dass Textdateien einliest, daraus eine Wortliste erstellt, um diesen dann als 1:n-Beziehung in 'ne Datenbank zu schreiben (dient der schnellen Suche nach Inhalten, quasi sowas wie Google light für lokale Dateien). Die Datenbankinteraktion erfolgt ausschließlich über Select- und Insert-Statements per ExecSQL, also keine datensensitiven Controls. Damit man was sieht, gibt es 'ne Progressbar, die halt alle 100 oder so ähnlich Statements eine Position weitergeht. Sonst wird nix an der Oberfläche geändert. Das Programm wird minimiert mindestens um den Faktor 10 schneller, auch dann, wenn ich auf die Progressbar verzichte. Statusänderungen, Fortschrittsanzeige mache ich nun, in dem ich alle 100 Sätze den Application.Title, bei minimiertem Programm, ändere. Dann sieht man immernoch den Fortschritt, aber die Oberfläche bleibt unsichtbar. Damit ist es (warum auch immer) deutlich schneller. Bei der großen Datenmenge, die zu verarbeiten ist, summiert sich das auf Laufzeitverkürzungen von vielen Stunden bis zu mehreren Tagen. Vermutlich sollte man sowas dann direkt als Konsolenprogramm schreiben. |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Zitat:
|
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
gruss |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Delphi-Quellcode:
) auch beim
TThread
Delphi-Quellcode:
sinnvoll verwendet wird.
TThread.Queue
Auch
Delphi-Quellcode:
ruft intern
TThread.Queue
Delphi-Quellcode:
auf und das habe ich oben erläutert.
class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean = False; ForceQueue: Boolean = False)
Aber bestimmt übersehe ich da etwas ... |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Ich bin jetzt auf Hide und Show umgestiegen, das erspart dem Rechner eine Animation abzuspielen :-) |
AW: Kann ich meine ListView beschleunigen (Icon laden dauert ewig)
Zitat:
Delphi-Quellcode:
ruft
TThread.Destroy
Delphi-Quellcode:
auf und dort werden alle noch nicht erledigten Queue-Events für diesen Thread gelöscht und somit nicht mehr ausgeführt. Übergibt man beim Queue ein nil, kommen die Events auch noch an wenn der auslösende Thread schon weg ist.
TThread.RemoveQueuedEvents
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz