Recent

Author Topic: [SOLVED] Show progress on another form during data processing  (Read 2140 times)

Jiří Huňáček

  • New Member
  • *
  • Posts: 28
Re: Show progress on another form during data processing
« Reply #15 on: November 03, 2024, 09:59:18 am »
Thank you Benny,

I will go through your code and try to learn something from it. :) It will definitely come in handy in the future. However, it doesn't solve my current problem, when the MEMO control element is needed, because the data is exported to the clipboard from another application and it probably won't work if it has to be saved in TXT before importing.

But in the end I tried an option that didn't occur to me right away and the problem is solved. As Bart wrote a bit above, you need to set the position of the ProgressBar twice, and after each setting you need to call the code from Handoko. Changed code in the PB demo project (in the attachment) - total number of lines in MEMO 139,678 converted in 5s.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
  9.   LCLIntf, LCLType;
  10.  
  11. type
  12.  
  13.   { TfrmForm1 }
  14.  
  15.   TfrmForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Label1: TLabel;
  18.     Label2: TLabel;
  19.     Label3: TLabel;
  20.     Label4: TLabel;
  21.     Label5: TLabel;
  22.     Memo1: TMemo;
  23.     ProgressBar1: TProgressBar;
  24.     procedure Button1Click(Sender: TObject);
  25.   private
  26.  
  27.   public
  28.  
  29.   end;
  30.  
  31. var
  32.   frmForm1: TfrmForm1;
  33.  
  34. implementation
  35.  
  36. {$R *.lfm}
  37.  
  38. { TfrmForm1 }
  39.  
  40. procedure TfrmForm1.Button1Click(Sender: TObject);
  41. var
  42.   i: Integer;
  43. begin
  44.   Label5.Caption := ''; // text READY after ending the loop (visual indication only - not needed)
  45.   Label5.Font.Color := clRed;
  46.  
  47.   Label4.Caption := FormatFloat('# ### ###', Memo1.Lines.Count);
  48.   ProgressBar1.Min := 0;
  49.   ProgressBar1.Max := Memo1.Lines.Count;
  50.  
  51.   for i := 0 to Memo1.Lines.Count - 1 do
  52.   begin
  53.     Label2.Caption := FormatFloat('# ### ###', i + 1);
  54.  
  55.     // the first setting of the ProgressBar
  56.     ProgressBar1.Position := i+1;
  57.     if i < (Memo1.Lines.Count-1) then
  58.     begin
  59.         if (i mod 50) <> 0 then Continue; // this line is for better performance
  60.     end;
  61.     Application.ProcessMessages;
  62.  
  63.     // the second ProgressBar setting
  64.     ProgressBar1.Position := i;
  65.     if i < (Memo1.Lines.Count-1) then
  66.     begin
  67.         if (i mod 50) <> 0 then Continue; // this line is for better performance
  68.     end;
  69.     Application.ProcessMessages;
  70.  
  71.     if GetKeyState(VK_ESCAPE) < 0 then Break; // Allow user cancellation
  72.   end;
  73.  
  74.   Label5.Caption := 'Ready';
  75. end;
  76.  
  77. end.

Thank you all for your willingness to help
« Last Edit: November 03, 2024, 10:16:44 am by Jiří Huňáček »
Best regards / mit freundlichen Grüßen / s pozdravem
Jiří Huňáček (George)

Lazarus v3.6 and FPC v3.2.2 on Windows 10 x64

Handoko

  • Hero Member
  • *****
  • Posts: 5378
  • My goal: build my own game engine using Lazarus
Re: Show progress on another form during data processing
« Reply #16 on: November 03, 2024, 11:04:31 am »
Thank you for reporting back.

Jiří Huňáček

  • New Member
  • *
  • Posts: 28
Re: Show progress on another form during data processing
« Reply #17 on: November 03, 2024, 12:52:27 pm »
I still tried to do the procedure to make it easier.

Code: Pascal  [Select][+][-]
  1. procedure ProgressBarUpdate(pbProgressBar: TProgressBar; pbPosition: LongInt);
  2. var
  3.   i: Integer;
  4. begin
  5.   for i := 1 to 1 do
  6.   begin
  7.     // the first setting of the ProgressBar
  8.     pbProgressBar.Position := pbPosition + 1;
  9.     if pbPosition < (pbProgressBar.Max - 1) then
  10.     begin
  11.         if (pbPosition mod 50) <> 0 then Continue; // this line is for better performance
  12.     end;
  13.     Application.ProcessMessages;
  14.  
  15.     // the second setting of the ProgressBar
  16.     pbProgressBar.Position := pbPosition;
  17.     if pbPosition < (pbProgressBar.Max - 1) then
  18.     begin
  19.         if (pbPosition mod 50) <> 0 then Continue; // this line is for better performance
  20.     end;
  21.     Application.ProcessMessages;
  22.   end;
  23. end;
« Last Edit: November 03, 2024, 12:54:46 pm by Jiří Huňáček »
Best regards / mit freundlichen Grüßen / s pozdravem
Jiří Huňáček (George)

Lazarus v3.6 and FPC v3.2.2 on Windows 10 x64

Handoko

  • Hero Member
  • *****
  • Posts: 5378
  • My goal: build my own game engine using Lazarus
Re: [SOLVED] Show progress on another form during data processing
« Reply #18 on: November 03, 2024, 01:37:33 pm »
I am not sure but how about this:

Code: Pascal  [Select][+][-]
  1. procedure TfrmForm1.Button1Click(Sender: TObject);
  2. var
  3.   i: Integer;
  4. begin
  5.   Label5.Caption := ''; // text READY after ending the loop (visual indication only)
  6.   Label5.Font.Color := clRed;
  7.  
  8.   Label4.Caption := FormatFloat('# ### ###', Memo1.Lines.Count);
  9.   ProgressBar1.Min := 0;
  10.   ProgressBar1.Max := Memo1.Lines.Count;
  11.  
  12.   for i := 0 to Memo1.Lines.Count - 1 do
  13.   begin
  14.     Label2.Caption := FormatFloat('# ### ###', i + 1);
  15.  
  16.     ProgressBar1.Position := i+1;
  17.     if (i >= (Memo1.Lines.Count-1)) or ((i mod 50) = 0) then
  18.       Application.ProcessMessages;
  19.  
  20.     if GetKeyState(VK_ESCAPE) < 0 then Break; // Allow user cancellation
  21.   end;
  22.  
  23.   Label5.Caption := 'Ready';
  24. end;

Jiří Huňáček

  • New Member
  • *
  • Posts: 28
Re: [SOLVED] Show progress on another form during data processing
« Reply #19 on: November 03, 2024, 07:36:11 pm »
I tried your change but it doesn't work see screenshot. There is still a bit to touch when the value is at its maximum. Maybe it's seriously because I'm testing it on Windows 10.

But the important thing is that we have chosen a functional variant for Windows.  :)
Best regards / mit freundlichen Grüßen / s pozdravem
Jiří Huňáček (George)

Lazarus v3.6 and FPC v3.2.2 on Windows 10 x64

Handoko

  • Hero Member
  • *****
  • Posts: 5378
  • My goal: build my own game engine using Lazarus
Re: [SOLVED] Show progress on another form during data processing
« Reply #20 on: November 03, 2024, 08:10:50 pm »
So, it seems the problem only happens on Windows 10 not on Linux nor Windows 7. Give me some days, I will try to find a Win10 computer to test the issue.

Jiří Huňáček

  • New Member
  • *
  • Posts: 28
Re: [SOLVED] Show progress on another form during data processing
« Reply #21 on: November 03, 2024, 08:49:37 pm »
Thanks a lot, but I'm not sure it makes sense to pursue this further. Yesterday afternoon Bart wrote that
Quote
On Windows the progressbar lacks behind because MS made it animated.

I would see a functional solution for Windows 10 in my post a bit above, where a procedure with two settings of the ProgressBar is created. I tried it on several cases and this solution worked 100% so far, both on one form and on the original project with a separate form for information. It's possible that the simpler way won't even work, because, let's face it, Microsoft is no longer what it used to be. Unfortunately, there are people among us (like me) who have to use Windows for some reason (for example work). :)
« Last Edit: November 03, 2024, 08:51:46 pm by Jiří Huňáček »
Best regards / mit freundlichen Grüßen / s pozdravem
Jiří Huňáček (George)

Lazarus v3.6 and FPC v3.2.2 on Windows 10 x64

LV

  • Full Member
  • ***
  • Posts: 159
Re: [SOLVED] Show progress on another form during data processing
« Reply #22 on: November 03, 2024, 09:32:20 pm »
I tried your change but it doesn't work see screenshot. There is still a bit to touch when the value is at its maximum. Maybe it's seriously because I'm testing it on Windows 10.

But the important thing is that we have chosen a functional variant for Windows.  :)

Out of curiosity, I decided to run the program on Windows 11.

LV

  • Full Member
  • ***
  • Posts: 159
Re: [SOLVED] Show progress on another form during data processing
« Reply #23 on: November 04, 2024, 12:39:20 am »
I tested this version of the program with an execution time of 4.5 seconds

I am not sure but how about this:

Code: Pascal  [Select][+][-]
  1. procedure TfrmForm1.Button1Click(Sender: TObject);
  2. var
  3.   i: Integer;
  4. begin
  5.   Label5.Caption := ''; // text READY after ending the loop (visual indication only)
  6.   Label5.Font.Color := clRed;
  7.  
  8.   Label4.Caption := FormatFloat('# ### ###', Memo1.Lines.Count);
  9.   ProgressBar1.Min := 0;
  10.   ProgressBar1.Max := Memo1.Lines.Count;
  11.  
  12.   for i := 0 to Memo1.Lines.Count - 1 do
  13.   begin
  14.     Label2.Caption := FormatFloat('# ### ###', i + 1);
  15.  
  16.     ProgressBar1.Position := i+1;
  17.     if (i >= (Memo1.Lines.Count-1)) or ((i mod 50) = 0) then
  18.       Application.ProcessMessages;
  19.  
  20.     if GetKeyState(VK_ESCAPE) < 0 then Break; // Allow user cancellation
  21.   end;
  22.  
  23.   Label5.Caption := 'Ready';
  24. end;

I have provided my program version with an execution time of 0.25 seconds (see attachment).

LV

  • Full Member
  • ***
  • Posts: 159
Re: [SOLVED] Show progress on another form during data processing
« Reply #24 on: November 04, 2024, 09:41:00 am »
I want to share some thoughts on this topic.

The issues mentioned by the original poster (@Jiří Huňáček) can be categorized into three main points:

1. The indicator lags behind the data processing.
@Bart answered that.

2. Visuals need to be displayed without freezing.
   2.1. One approach is using `Application.ProcessMessages`, as suggested by @Jiří Huňáček and @Handoko.
   2.2. Another method is to start a worker thread for data processing, as mentioned by @cdbc and @ASerge.

You can then use `Synchronize` to update visuals without freezing.

3. Performance is another critical aspect.
I have never used `Application.ProcessMessages` for big data, only (2.2). The example provided in Adv.zip is proof of that. 

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: [SOLVED] Show progress on another form during data processing
« Reply #25 on: November 04, 2024, 10:08:05 am »
Hi
@LV: Are you seriously accessing GUI-controls inside the worker thread code?!? That defeats / undermines your use of 'synchronize'!!!!!
What the H*LL?!?!
Code: Pascal  [Select][+][-]
  1. procedure TThreadCalc.Execute;
  2. var
  3.   i: Integer;
  4. begin
  5.  
  6.   TimeStart := Now;
  7.  
  8.   Form_Control.Label3.Font.Color := clRed;
  9.  
  10.   Form_Control.Label2.Caption := FormatFloat('# ### ###',
  11.     Form_Control.Memo1.Lines.Count);
  12.  
  13.   Form_Control.ProgressBar1.Min := 0;
  14.   Form_Control.ProgressBar1.Max := Form_Control.Memo1.Lines.Count;
  15.  
  16.   for i := 0 to Form_Control.Memo1.Lines.Count - 1 do
  17.   begin
  18.     step := i;
  19.     if (i mod 50) = 0 then Synchronize(@Update);
  20.   end;
  21.   Synchronize(@Update);
  22.   Form_Control.Label3.Caption := 'Ready';
  23.   Form_Control.Label4.Caption := 'Time = ' +
  24.     FormatDateTime('hh:mm:ss:zzz', Now - TimeStart);
  25. end;
Tsk Tsk Tsk  >:D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

LV

  • Full Member
  • ***
  • Posts: 159
Re: [SOLVED] Show progress on another form during data processing
« Reply #26 on: November 04, 2024, 10:51:42 am »
@cdbc, it's important to stay calm :)

syncs here

Code: Pascal  [Select][+][-]
  1. for i := 0 to Form_Control.Memo1.Lines.Count - 1 do
  2.   begin
  3.     step := i;
  4.     if (i mod 50) = 0 then Synchronize(@Update);
  5.   end;
  6.   Synchronize(@Update);
  7.  

To maintain clean code, other chunks should be executed before and after the thread. Sorry, I was careless.

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: [SOLVED] Show progress on another form during data processing
« Reply #27 on: November 04, 2024, 11:18:52 am »
Hi
Real calm here  :D
Especially with 'threading' code, it's crucial to show *correct* implementations, so that people who are trying to learn, get it right from the 'GetGo'. Bad habbits, they'll /learn/pickup/ all on their lonesome  ;D
Threading is hard enough, as it is...  %)
Everybody knows: The LCL / VCL is NOT threadsafe! Don't access it in thread code!!!
Just saying...
Regards Benny
edit: typo
« Last Edit: November 04, 2024, 11:23:02 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

LV

  • Full Member
  • ***
  • Posts: 159
Re: [SOLVED] Show progress on another form during data processing
« Reply #28 on: November 04, 2024, 11:21:12 am »
@cdbc. Thanks.
Would this code be better?
Best regards

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: [SOLVED] Show progress on another form during data processing
« Reply #29 on: November 04, 2024, 11:31:54 am »
Hi
Ahemmm... What's this?!?
Code: Pascal  [Select][+][-]
  1.   for i := 0 to Form_Control.Memo1.Lines.Count - 1 do
But, Yes it's better(ish).
You have to separate the data, the thread's working on, from anything GUI!
That's why I coded my example the way I did and to avoid having 19 MB stuck into the form's streaming data...
If I didn't care about memory, I'd just copy the memo.lines into a stringlist and work on that...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

 

TinyPortal © 2005-2018