Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



Share:
Notifications
Clear all

[Solved] Lazarus - Interrupting FindAllFiles for progress indication

1 Posts
1 Users
0 Reactions
2,259 Views
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2859
Topic starter  

Lazarus Pascal comes with a neat little function "FindAllFiles" which retrieves all files in a given path, matching a given Mask and returns it as a TStringList.

This works fast but has one little issue: it's resource intens and you Lazarus application freeze while it's being executed. The downside being: there is no way to do any kind of progress indication and the user might think the application hangs when retrieving a very large amount of files.

Simply adding Application.ProcessMessages would be the solution, but you can't unless we use a trick that I found in the Lazarus Forum by a user called Molly.

First thing I had to realize is that FindAllFiles can be used in two way; either it returns a TStringList or you pass it a TStringList to work with. The latter offers a fix.

As an example, I'll update a TLabel which indicates the number of files found, and a TButton to start the scan.
So on my form I have a TLabel called Label1, and a TButton called Button1.

Next we need to create a TStringList, so we can attach an "OnChange" event to it, which could call Application.ProcessMessages.

In code:

The handler for the 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;

This will update the label, each time we have found 10 files again. You can play with this value, lower value means more refreshes = slower execution of the whole thing (depending on your computer etc).

Next we need to attach this to our TStringList and call FindAllFiles the proper way:

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;

When FindAllFiles is done, I remove the handler again, since we probably will be using the TStringList later on and do not want to fire the event handler by accident.

That's all there is to it. Nice and clean solution!


   
ReplyQuote
Share: