Lazarus Pascal heeft een handige functie, "FindAllFiles", welke alle files en directories can vinden binnen een gegeven pad, met gegeven criteria, en geeft het antwoord terug als een nette TStringList.
Dit werkt erg goed, en snel, maar heeft een nadeel: het vreet resources op dusdanige manier dat jouw programma stil lijkt te zijn staan of lijkt te zijn vastgeslagen. Erg lastig voor de gebruikerservaring want de gebruiker weet niet of het nu nog bezig is, of dat het foute boel is, dus willen we graag een indicatie dat het e.e.a. nog draait.
Het liefste zouden we tussendoor een Application.ProcessMessages willen doen, maar dat gaat niet,... tenzij we een truc gebruiken die ik in het Lazarus Forum vond, van een gebruiker met de naam Molly.
Het eerste wat ik me moest realiseren is dat FindAllFiles op 2 manieren gebruikt kan worden: of je krijgt een TStringList als antwoord terug, of je geeft een bestaande TSTringList aan de functie door die dan de inhoud daarvan veranderd - en dat laatste biedt de oplossing.
Als voorbeeld heb ik op mijn Form een TLabel gebruikt die aangeeft hoeveel files er gelezen zijn, en een TButton om het zoeken te starten.
Dus we hebben een TLabel met de naam Label1, en een TButton met de naam Button1.
Vervolgens moeten we in onze code een TStringList, waaraan we een "OnChange" kunnen hangen welke dan weer Application.ProcessMessages kan aanroepen.
In code:
De handler voor het OnChange event:
procedure TForm1.FindAllFilesInterrupt(Sender: TObject);
Const UpdateFrequency = 10;
begin
if (TStringList(Sender).Count mod UpdateFrequency = 0) then // for every 10th file
begin
Label1.Caption:='File count: ('+IntTostr(TStringList(Sender).Count)+')';
application.ProcessMessages;
end;
end;
Dit zal Label1 steeds per 10 gevonden files updaten. Je kunt voor UpdateFrequency een lagere waarde gebruiken, maar hoe lager deze waarde, hoe meer refreshes en dus hoe langzamer het geheel loopt (afhankelijk van jouw computer natuurlijk).
Vervolgens moeten we de dus een TStringList maken, de handler er aan hangen en FindAllFiles op de juiste manier aanroepen:
procedure TForm1.Button1Click(Sender: TObject);
var AllFiles : TStringList;
...
begin
...
AllFiles := TStringList.Create;
AllFiles.OnChange:=@FindAllFilesInterrupt;
FileUtil.FindAllFiles(AllFiles,'/Path/we/want/to/scan','*.*',true);
AllFiles.OnChange:=nil;
...
end;
Als FindAllFiles klaar is, verwijder ik de handler weer - voor het geval we later met de TStringList dingen gaan uithalen.