Recent

Author Topic: [SOLVED] Application.ProcessMessages does not work as expected  (Read 1362 times)

erol

  • New Member
  • *
  • Posts: 11
[SOLVED] Application.ProcessMessages does not work as expected
« on: January 22, 2025, 03:39:22 pm »
Hello All,
I have a simple form which has only a button. Function check if a number is prime number or not. I can move window but can not close. There is no value come back from function. If I comment out Application.ProcessMessages, function returns after a few secs. I use Lazarus 3.6 (64-bit) and Windows 10.

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;
  9. type
  10.  
  11.   { TForm1 }
  12.  
  13.   TForm1 = class(TForm)
  14.     Button1: TButton;
  15.     procedure Button1Click(Sender: TObject);
  16.   private
  17.  
  18.   public
  19.     function asal(x:dword):boolean;
  20.   end;
  21.  
  22. var
  23.   Form1: TForm1;
  24.  
  25. implementation
  26.  
  27. {$R *.lfm}
  28.  
  29. { TForm1 }
  30.  
  31. function TForm1.asal(x:dword):boolean;
  32. var i:dword;
  33. begin
  34.   if (x mod 2)=0 then
  35.      if x=2 then
  36.         result:=true
  37.      else
  38.         result:=false
  39.   else
  40.      begin
  41.        i:=3;
  42.        while i<x do
  43.        begin
  44.           if (x mod i)=0 then
  45.              begin
  46.                result:=false;
  47.                exit;
  48.              end;
  49.           i:=i+2;
  50.           Application.ProcessMessages;          
  51.        end;
  52.        result:=true;
  53.      end;
  54. end;
  55.  
  56. procedure TForm1.Button1Click(Sender: TObject);
  57. begin
  58.   if asal(587100037) then
  59.      showmessage('bu sayı asal')
  60.   else
  61.      showmessage('bu sayı asal değil')
  62. end;
  63. end.    
  64.  
« Last Edit: January 23, 2025, 03:46:52 pm by erol »

Thaddy

  • Hero Member
  • *****
  • Posts: 16556
  • Kallstadt seems a good place to evict Trump to.
Re: Application.ProcessMessages does not work as expected
« Reply #1 on: January 22, 2025, 03:44:40 pm »
If there is no room to process, Application.processmessages will not work.
It is not a magic wand. Your code is simply not correct.
But I am sure they don't want the Trumps back...

Gigatron

  • Full Member
  • ***
  • Posts: 183
  • Amiga Rulez !!
Re: Application.ProcessMessages does not work as expected
« Reply #2 on: January 22, 2025, 04:05:59 pm »
Hi,
 Application.ProcessMessages; freeze when the number is bigger in your code ;

try to comment this function;

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;
  9.     type
  10.      
  11.       { TForm1 }
  12.      
  13.       TForm1 = class(TForm)
  14.         Button1: TButton;
  15.         procedure Button1Click(Sender: TObject);
  16.       private
  17.      
  18.       public
  19.         function asal(x:dword):boolean;
  20.       end;
  21.      
  22.     var
  23.       Form1: TForm1;
  24.      
  25.     implementation
  26.      
  27.     {$R *.lfm}
  28.      
  29.     { TForm1 }
  30.      
  31.     function TForm1.asal(x:dword):boolean;
  32.     var i:dword;
  33.     begin
  34.       if (x mod 2)=0 then
  35.          if x=2 then
  36.             result:=true
  37.          else
  38.             result:=false
  39.       else
  40.          begin
  41.            i:=3;
  42.            while i<x do
  43.            begin
  44.               if (x mod i)=0 then
  45.                  begin
  46.                    result:=false;
  47.                    exit;
  48.                  end;
  49.               i:=i+2;
  50.        //       Application.ProcessMessages;   // freez application you can not move window or close during process !!      
  51.            end;
  52.            result:=true;
  53.          end;
  54.     end;
  55.      
  56.     procedure TForm1.Button1Click(Sender: TObject);
  57.     begin
  58.       if asal(587100037) then
  59.          showmessage('bu sayı asal')
  60.       else
  61.          showmessage('bu sayı asal değil')
  62.     end;
  63.     end.    
  64.      

Or try this code if it's working for you with Application.ProcessMessages;

Code: Pascal  [Select][+][-]
  1. function TForm1.asal(x: dword): boolean;
  2. var
  3.   i: dword;
  4. begin
  5.   if x < 2 then
  6.     Exit(False);
  7.   if x = 2 then
  8.     Exit(True);
  9.   if (x mod 2) = 0 then
  10.     Exit(False);
  11.  
  12.   i := 3;
  13.   while i * i <= x do
  14.   begin
  15.     if (x mod i) = 0 then
  16.       Exit(False);
  17.     i := i + 2;
  18.     Application.ProcessMessages;
  19.   end;
  20.  
  21.   Result := True;
  22. end;
  23.  
  24. procedure TForm1.Button1Click(Sender: TObject);
  25. begin
  26.       if asal(587100037) then
  27.      showmessage('bu sayı asal')
  28.   else
  29.      showmessage('bu sayı asal değil')
  30. end;    
  31.  

Good luck;
« Last Edit: January 22, 2025, 04:08:51 pm by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

alpine

  • Hero Member
  • *****
  • Posts: 1349
Re: Application.ProcessMessages does not work as expected
« Reply #3 on: January 22, 2025, 04:15:46 pm »
Quote
There is no value come back from function.
Are you sure? Did you wait long enough?
Calling Application.ProcessMessages in such a loop can slowdown by a factor of a thousand.
However, using it is not a good idea anyway - it can cause an indirect recursion and rather inexplicable GUI behavior.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10833
  • Debugger - SynEdit - and more
    • wiki
Re: Application.ProcessMessages does not work as expected
« Reply #4 on: January 22, 2025, 04:16:27 pm »
You don't really want to call   ProcessMessages that often => that takes to much time.

For the user it is enough, if you call it ever 50 to 100 milliseconds. But rather than taking the time you may simple say you call it every time you did e.g. 100 loop iterations (100 divisions is likely still much faster than 50 ms).

Something like
Code: Pascal  [Select][+][-]
  1. if (i and 127) = 0 then // or i and 255 // or i and 1023
  2.     Application.ProcessMessages;



As for being able to close the form => It will wait for your loop to finish.

You could add on an OnCloseQuery (not sure name maybe similar) event. That should be called during  ProcessMessages if the user tries to close the form.
In that you can set a flag (add a field FCloseRequestedByUser: boolean to the form). Then you can set that to true, and in your loop, after calling  ProcessMessages, you can do "if FCloseRequestedByUser then exit;"

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1470
    • Lebeau Software
Re: Application.ProcessMessages does not work as expected
« Reply #5 on: January 22, 2025, 04:30:12 pm »
Any time you need to resort to using ProcessMessages(), you should rethink your design.

If you need to process UI messages while doing a task, then you should simply do that task in a separate thread. Let the main UI thread do its job normally.

Have your button start a new thread to check the prime, and disable the button. Have the thread notify the main thread when it's finished so you can show the result and re-enable the button. If the user wants to exit the app, terminate the thread if it is still running.
« Last Edit: January 22, 2025, 04:31:52 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

dseligo

  • Hero Member
  • *****
  • Posts: 1462
Re: Application.ProcessMessages does not work as expected
« Reply #6 on: January 22, 2025, 09:45:24 pm »
Function check if a number is prime number or not.

You don't have to check all the way to the number 'x', it is enough to check to the square root of 'x'.

Curt Carpenter

  • Hero Member
  • *****
  • Posts: 598
Re: Application.ProcessMessages does not work as expected
« Reply #7 on: January 23, 2025, 03:49:57 am »
Any time you need to resort to using ProcessMessages(), you should rethink your design.

That's contrary to a number of things I've read which suggests using Application.ProcessMessages unless you can really make a case for threading.  For example in https://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial#Do_you_need_multi-threading?

Quote
If you are new to multi-threading and you only want to make your application more responsive while your application performs moderately long-running tasks, then multi-threading may be more than is required. Multi-threaded applications are always more difficult to debug and they are often much more complex; in many cases you don't need multi-threading. A single thread is enough. If you can split up the time-consuming task into several smaller chunks, then instead you should use Application.ProcessMessages. This method allows the LCL to handle all waiting messages and returns. The central idea is to call Application.ProcessMessages at regular intervals during the execution of a long-running task to determine whether the user has clicked on something, or a progress indicator must be repainted, and so on. 


440bx

  • Hero Member
  • *****
  • Posts: 5009
Re: Application.ProcessMessages does not work as expected
« Reply #8 on: January 23, 2025, 04:45:21 am »
That's contrary to a number of things I've read which suggests using Application.ProcessMessages unless you can really make a case for threading. 
Don't believe everything you read (including this post) but, one of the most important things to understand in a graphical application is that there is a user who will be immediately and directly affected by a poorly performing graphical interface.

Aside from the _valid_ argument that the GUI thread should not be saddled with activities that have nothing to do with taking care of the user interface, _not_ dedicating a separate thread to a time consuming task is, in the days of multiple core processors, guaranteed to take longer than otherwise.  If a time consuming task is performed by a separate thread, it's very often the case that the O/S will associate a different processor core to the task which will cause the task to be performed in less time.   

Contrary to what the article you quoted states, a multi-threaded application is quite often _simpler_ than _correctly_ implementing a single thread that is attempting to carry out multiple tasks, particularly when one of those tasks is taking care of a GUI.

That said, like everything, there is a little bit of work involved in creating an additional thread and managing it but, contrary to what some believe, it's usually very simple. 

In general, if some sequence of code may take 1/50 of a second or longer (on a _below average_ processor) then, dedicate a thread to it.  Why 1/50 of a second ? because a lot of people will be able to detect pauses in the U.I that range between 1/30 to 1/20 of a second.  Because of this, play it safe, use 1/50 (and that's presuming there is only 1 or 2 such tasks being performed by the U.I thread.)

An unresponsive interface leaves a bad impression and often tries the user's patience.  These are things to be avoided.
« Last Edit: January 23, 2025, 04:48:27 am by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

erol

  • New Member
  • *
  • Posts: 11
Re: Application.ProcessMessages does not work as expected
« Reply #9 on: January 23, 2025, 03:14:59 pm »
Thank you for the replies. It works as expected with the code below. Window can be closed after pressing button. (
Code: Pascal  [Select][+][-]
  1. if Application.Terminated
is required.) But I want to learn threads.

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;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     procedure Button1Click(Sender: TObject);
  17.   private
  18.  
  19.   public
  20.     function asal(x:dword):integer;
  21.   end;
  22.  
  23. var
  24.   Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TForm1 }
  31.  
  32. function TForm1.asal(x:dword):integer;
  33. var i:dword;
  34. begin
  35.   if (x mod 2)=0 then
  36.      if x=2 then
  37.         result:=1 //true
  38.      else
  39.         result:=2 //false
  40.   else
  41.      begin
  42.        i:=3;
  43.        while i<x do
  44.        begin
  45.           if (x mod i)=0 then
  46.              begin
  47.                exit(2);
  48.              end;
  49.           i:=i+2;
  50.  
  51.           if (i mod 500001) = 0 then
  52.              begin
  53.              Application.ProcessMessages;
  54.              if Application.Terminated then exit(3);
  55.              //untick :
  56.              //Project Options > Compiler options >
  57.              //Config and Target > Win32 gui application
  58.              //otherwise writeln gives error :
  59.              writeln('Current i : ' + inttostr(i));
  60.              end;
  61.        end;
  62.        result:=1;
  63.      end;
  64. end;
  65.  
  66. procedure TForm1.Button1Click(Sender: TObject);
  67. begin
  68.   if asal(587100037)=1 then
  69.      showmessage('it is prime')
  70.   else if asal(587100037)=2 then
  71.      showmessage('it is not prime')
  72.   else
  73.      showmessage('program terminated');
  74. end;
  75. end.          
  76.  

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10833
  • Debugger - SynEdit - and more
    • wiki
Re: [SOLVED] Application.ProcessMessages does not work as expected
« Reply #10 on: January 23, 2025, 04:52:44 pm »
One more thing you might want to do: In "Button1Click" do as very first thing
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   Button1.Enabled := False;
  4.   try
  5.     if asal(587100037)=1 then
  6.        showmessage('it is prime')
  7.     else if asal(587100037)=2 then
  8.        showmessage('it is not prime')
  9.     else
  10.        showmessage('program terminated');
  11.   finally
  12.     Button1.Enabled := True;
  13.   end;
  14. end;
  15.  
 

Thus a user can not restart the search while the search is still running.

Otherwise the user can click twice (or more) and then the first search will be paused, the 2nd will run and display its result, and then the first will continue and also display its result.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10833
  • Debugger - SynEdit - and more
    • wiki
Re: [SOLVED] Application.ProcessMessages does not work as expected
« Reply #11 on: January 23, 2025, 04:54:51 pm »
And also

MyIntVar :=  asal(587100037);
and use that in the "if then if then"

Or
case  asal(587100037) of
1:;
2:;
else
end;


Currently you run the search twice

erol

  • New Member
  • *
  • Posts: 11
Re: [SOLVED] Application.ProcessMessages does not work as expected
« Reply #12 on: January 23, 2025, 07:46:48 pm »
search runs only one time, because it is a prime number :o  I’m kidding, thank you for the good points.. I will post this code on an article correctly for my blog page. I already wrote an introduction page about free pascal :
 https://erolcum-blogspot-com.translate.goog/2025/01/free-pascal.html?m=1&_x_tr_sl=tr&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp
feel free to make me warn if something is wrong

 

TinyPortal © 2005-2018