Forum > Windows

SetTimer in a second form

(1/1)

engine32:
Hello,
I have the main form, with a button that when clicked, launches a second form with ShowModal.
On the second form, I set a timer with SetTimer and on WM_TIMER I add a new line to a memo. It compiles with no errors, but the timer message never arrives. In Delphi is working. Also, if I launch the second form with Show (not ShowModal) it is working as well. However, I would like to use ShowModal.
Here are the two units:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit testpas; {$ifdef fpc}  {$mode objfpc}{$H+}{$endif} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,  unit2; type   { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);  private   public   end; var  Form1: TForm1; implementation{$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject);var  a: Tfrm2;begin  a := Tfrm2.Create(Application);  try    a.ShowModal;  finally    a.Free;  end;end; end. 
and


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit unit2; {$ifdef fpc}  {$mode objfpc}{$H+}{$endif} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Windows; type  { TFrm2 }  TFrm2 = class(TForm)    mTest: TMemo;    procedure FormCreate(Sender: TObject);  private  public    procedure WndProc(var Msg: TMessage); override;  end; const  ctTimerId = 1; var  intTimerId: integer; implementation{$R *.lfm}{ TFrm2 }procedure TFrm2.FormCreate(Sender: TObject);begin  intTimerId := SetTimer(Handle, ctTimerId, 1000, nil);end; procedure TFrm2.WndProc(var Msg: TMessage);begin  if Msg.Msg = WM_TIMER then  begin    mTest.Lines.Add('timer');  end  else  begin    inherited WndProc(Msg);  end;end; end. 
Thank you.

howardpc:
Why not make it cross-platform?
Main unit:
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit testpas; {$mode objfpc}{$H+} interface uses  Forms, StdCtrls,  Unit2; type  TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);  end; var  Form1: TForm1;  Frm2: TFrm2; implementation {$R *.lfm} procedure TForm1.Button1Click(Sender: TObject);var  a: TFrm2;begin  a := TFrm2.Create(Nil);  try    a.ShowModal;  finally    a.Free;  end;end; end.Memo unit:
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit Unit2; {$mode ObjFPC}{$H+} interface uses  Forms, StdCtrls, ExtCtrls; type  TFrm2 = class(TForm)    mTest: TMemo;    Timer1: TTimer;    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  end; implementation {$R *.lfm} procedure TFrm2.FormCreate(Sender: TObject);begin  Timer1.Interval := 1000;  Timer1.Enabled := True;end; procedure TFrm2.Timer1Timer(Sender: TObject);begin  mTest.Lines.Add('timer');end; end.

engine32:
Thank you. I was / am aware about this solution, however, I am still looking for a solution for SetTimer. I see three outcomes:
1 I miss something and I would like to know what and to fix the problem
2 it's simply the way Lazarus works, in other words, suppressing timer messages when the form is shown in modal mode
3 there is a bug in Lazarus

My application also uses messages for serial communication (no component) and for Ethernet working with winsock directly. I am checking to see if those messages are passing through.

Remy Lebeau:

--- Quote from: engine32 on October 30, 2021, 05:45:27 pm ---I was / am aware about this solution, however, I am still looking for a solution for SetTimer.

--- End quote ---

Assuming ShowModal() is processing Win32 messages correctly, then I would guess that the 2nd Form's HWND is likely being recreated by ShowModal() after the OnCreate event has exited, thus losing your timer.  In which case, you can work around that by overriding the virtual CreateWnd() method instead to call SetTimer().


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit unit2; {$ifdef fpc}  {$mode objfpc}{$H+}{$endif} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Windows; type  { TFrm2 }  TFrm2 = class(TForm)    mTest: TMemo;  private    intTimerId: integer;  public    procedure WndProc(var Msg: TMessage); override;    procedure CreateWnd; override;  end;          implementation {$R *.lfm} const  ctTimerId = 1; { TFrm2 } procedure TFrm2.CreateWnd;begin  inherited;  intTimerId := SetTimer(Handle, ctTimerId, 1000, nil);end;     procedure TFrm2.WndProc(var Msg: TMessage);begin  if Msg.Msg = WM_TIMER then  begin    mTest.Lines.Add('timer');  end  else  begin    inherited WndProc(Msg);  end;end;     end.     

Otherwise, you should create your own hidden HWND using the Win32 CreateWindow/Ex() function directly just for the timer to use (that is what TTimer does internally).  Then you are not tied to the lifetime of the Form's HWND.

Of course, it would be easier to just use TTimer instead.


--- Quote from: engine32 on October 30, 2021, 05:45:27 pm ---My application also uses messages for serial communication (no component) and for Ethernet working with winsock directly. I am checking to see if those messages are passing through.

--- End quote ---

They should, if ShowModal() is running a proper Win32 message loop.  Unless you are tying those operations to the Form's HWND and it gets recreated after you setup the operations.  If there is one thing the VCL has taught me, and this probably applies to the LCL too, is that a Form's HWND is reliable for sending messages to at any given moment, but it is not reliable for persistent registrations over time, unless you override the CreateWnd()/DestroyWnd() methods to update those registrations every time the HWND is recreated by the framework, for whatever reason.

engine32:
  With CreateWnd both timer and winsock messages are working properly. Thank you.

Navigation

[0] Message Index

Go to full version