0

I am browsing and listing content of a small FTP folder using IdFTP.

I would like that with a double click the user could be able to start the download of the file.

I noticed that FTP.Get is working well but is UI-blocking.

Could you point me to a possibile workaround?

mjn
  • 36,362
  • 28
  • 176
  • 378
realtebo
  • 23,922
  • 37
  • 112
  • 189
  • 3
    Do the FTP stuff in a thread. That is how any UI-blocking stuff must be done. – Sherlock70 Jun 06 '23 at 14:44
  • Could you point me to a tutorial of multithreading wit Delphi or a basic example of how to create, execute and terminate a thread? Inside I'll do the download job – realtebo Jun 06 '23 at 14:47
  • It seems this older question should get you going in the right direction: https://stackoverflow.com/questions/13661713/multithreaded-file-upload-synchronization – Sherlock70 Jun 06 '23 at 14:58
  • 10 years ago? I never read posts and answers older than 2-3 years. but I'll give it a try, thanks – realtebo Jun 06 '23 at 15:01
  • 1
    Well this Youtube Video from Coderage X is only 7 years old: https://www.youtube.com/watch?v=F9D9dQz2RPE&list=PLwUPJvR9mZHgOEzhKYeLF_UzPu2W3cFdI – Sherlock70 Jun 06 '23 at 15:05
  • @realtebo The age of an answer doesn't detract from it's quality. SO users tend not to answer questions that already have answers, no matter what age those answers are! – Freddie Bell Jun 14 '23 at 06:29

2 Answers2

3

Doing any UI-blocking operations in the main UI thread is never a good idea, always perform them in a worker thread instead, and have it synchronize with the UI thread as needed. Delphi has a TThread class for this purpose, which you can derive from and override its virtual Execute() method as needed. Or, use its CreateAnonymousThread() method.

Indy also has its own TIdThread extension to TThread, as well as a TIdThreadComponent component wrapper, too.

But, if you must use the main UI thread, then Indy does have a TIdAntiFreeze component that allows the main UI thread to continue processing messages while a UI-blocking Indy operation is in progress. Simply place a TIdAntiFreeze onto your MainForm (or instantiate it in code as needed) and Indy will handle the rest.

Note that TIdAntiFreeze is basically just a wrapper for Application.ProcessMessages(), allowing Indy operations to pump the message queue periodically, so this comes with all the same re-entrance risks that are common with ProcessMessages(), so use this with care.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

I don't know if this will also work with IdFtp, but in general the easiest way to do it is like this:

uses Threading;

procedure TForm2.Button1Click(Sender: TObject);
begin
  DownloadWithoutBlockingUI;
end;

procedure TForm2.Download;
begin
  //something long-lasting
  for var i:=0 to 500 do begin
    Sleep(1);
    //don't change anything in the UI here!
  end;
end;

procedure TForm2.DownloadWithoutBlockingUI;
var
  aTask: ITask;

begin
  Label1.Caption:='Start...';
  //preparation of the parallel task
  aTask:=TTask.Create(procedure ()
    begin
      //what will be executed
      Download;

      //after completion I will arrange UI modification
      TThread.Queue(nil,
        procedure
        begin
          Label1.Caption:='Finished';
        end
      );
    end);
  //start of a parallel task
  aTask.Start;
end;
Vladimír Klaus
  • 157
  • 1
  • 8