In our previous example we have used Synapse ThttpSend to download files from the web using blocking mode.
Now we want to unfreeze this blocking of application while downloading large files. We have used threads in this example. Before using thread we need to enable it first if we are using Linux.
By default we will find this compiler directive in main project source code:
uses {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF}
Remove useCThreads part to be like this:
uses {$IFDEF UNIX} cthreads, {$ENDIF}
This is the form:
And this is the code of form unit:
unit main; {$mode objfpc}{$H+} interface uses Classes, SysUtils, process, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, httpSend; type { THTTPDownload } THTTPDownload = class(TThread) private fURL: string; fFileName: string; public constructor Create(URL, FileName: string); procedure Execute; override; end; { TfmMain } TfmMain = class(TForm) btDownload: TBitBtn; btGet: TButton; edURL: TEdit; Label1: TLabel; Memo1: TMemo; SaveDialog1: TSaveDialog; procedure btDownloadClick(Sender: TObject); procedure btGetClick(Sender: TObject); private procedure DownloadTerminiated(Sender: TObject); { private declarations } public { public declarations } end; var fmMain: TfmMain; implementation { THTTPDownload } constructor THTTPDownload.Create(URL, FileName: string); begin inherited Create(True); fURL:= URL; fFileName:= FileName; end; procedure THTTPDownload.Execute; var httpClient: THTTPSend; begin httpClient:= THTTPSend.Create; if httpClient.HTTPMethod('GET', fURL) then httpClient.Document.SaveToFile(fFileName); fmMain.Memo1.Lines.Add(fFileName + ', has been downloaded'); httpClient.Free; end; {$R *.lfm} { TfmMain } procedure TfmMain.btGetClick(Sender: TObject); var httpClient: THTTPSend; begin httpClient:= THTTPSend.Create; if httpClient.HTTPMethod('GET', edURL.Text) then begin Memo1.Lines.LoadFromStream(httpClient.Document); end; httpClient.Free; end; procedure TfmMain.DownloadTerminiated(Sender: TObject); begin Memo1.Lines.Add('Thread finished'); btDownload.Enabled:= True; end; procedure TfmMain.btDownloadClick(Sender: TObject); var httpClient: THTTPSend; download: THTTPDownload; begin SaveDialog1.FileName:= ExtractFileName(edURL.Text); if SaveDialog1.Execute then begin btDownload.Enabled:= False; download:= THTTPDownload.Create(edURL.Text, SaveDialog1.FileName); download.OnTerminate:= @DownloadTerminiated; download.Resume; memo1.Lines.Add('Download started'); end; end; end.
…Thanks for the insight. I tried your concept and replaced the HTTP download functionality with a mysql query and it works pretty well. The application remains responsive as expected.
Then I tried the same concept with a synapse based “PING” function. For some reason the non-blocking delay of ping makes the application no responsive for a pc host that is not found. Is there something I am overlooking?
Could you please put the code of ping here to check it.
Thanks, below please find the relevant sections of the code:
You shouldn’t call pinger.Free at this position, you are trying to free the thread while it is working. so your code will be like this:
That sorted out the problem. I guess I actually introduced the anomaly myself. My attempt was to ensure that “pinger” is freed upon completion of the thread. But now I remember that the thread is actually freed by the “pinger.OnTerminate:= @PingTerminated” statement.
Thank you very much indeed.
not that Pinger.Resume will start the thread but it will not wait until execution or termination, it will go to the next step, which was Pinger.Free in your previous code.
Another note:
Don’t write immediately from Thread to Memo, specially if you have multiple instances of the thread. Instead put the code of display in a method like:
And call it using Synchronize from the thread:
Synchornize will ensure that no multiple instances of this thread will access Memo1 at the same time
I have implemented the Synchronize(Display) procedure as proposed and it also works. However, I had to remove the “(AText: String)” argument for the procedure to make it compile successfully.
I am satisfied with the progress. Thank you.
Hello, Thanks for a nice tutorial.
I wanted to know is there any way to show a progressbar showing the percentage of the file being downloaded? I didn’t find any working example.
I have found a progressbar implementation here: https://github.com/silvioprog/lazsolutions/tree/master/Demos/LSHTTPSend . Not tested yet though.