Recent

Author Topic: What is the correct way to execute instructions AFTER opening a form  (Read 10336 times)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11452
  • FPC developer.
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #15 on: May 31, 2016, 11:05:20 pm »
Such tricks (postmessage, queueasynccall etc) only work fine when no other components use something similar and trigger multiple times too.

Also IIRC very heavy scaling of forms might trigger a multitude of events.

Simplest is to set a timer for 100ms or so.




rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #16 on: May 31, 2016, 11:09:27 pm »
I didn't get any error and Lazarus shows " 0 unfreed memory blocks: 0"... so it looks good so far...
It might work in this simple example but I can guarantee you, you'll get into trouble at some point. You're freeing the ttimer after which the code returns to an already freed object (because you freed the ttimer in it's own event handler). Because in this small time-window the memory space isn't used, the code will run fine but that not always guaranteed. The rule is... Never ever free an object in it's own event handlers.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #17 on: May 31, 2016, 11:43:03 pm »
Quote
Never ever free an object in it's own event handlers.
OK, got that...

But then I don't see where I should free the timer... maybe that was the point I didn't see...
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #18 on: May 31, 2016, 11:49:21 pm »
The only (good) way to free the timer is outside it's evenr handler. You could do that with a postmessage (to the form itself and destroy the timer in there) or the before mentioned QueueAsyncCall. But that kind of defeats the purpose of the ttimer because you could have used that QueueAsyncCall to begin with :)

The only other option I see is to just leave the ttimer in memory and let it get destroyed by the form. If you do ttimer.create(self) (self is the form) it will be freed with the form. You could also free it in the form.destroy.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #19 on: May 31, 2016, 11:57:25 pm »
The behaviour as known to me is that a constant defined inside a local procedure keeps it value.

That is only true for typed constants, and only true in the {$J+} compiler state (as Thaddy pointed out), which is normally true, since {$J+} is the default FPC setting, for historical reasons of Delphi compatibility. With {$J+} typed constants are assignable wherever they are declared (whether in a local procedure or not).
As has been often noted, the word constant in "typed constant" is rather misleading in this case, since the 'constant' is actually an initialized variable. Of course it does remain constant ... until you change its value.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #20 on: June 01, 2016, 12:13:56 am »
@rvk
Thanks, that is working fine so far...
Code: Pascal  [Select][+][-]
  1. Unit uSoundAfterCreate;
  2.  {$mode objfpc}{$H+}
  3.  
  4. Interface
  5.  Uses
  6.   Classes, Windows, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;
  7.  
  8.  Type
  9.   TForm1 = Class(TForm)
  10.    Image1: TImage;
  11.  
  12.     Procedure FormCreate    (Sender: TObject);
  13.     Procedure FormPaint     (Sender: TObject);
  14.     Procedure tiPlaySoundDo (Sender: TObject);
  15.  
  16.      PRIVATE
  17.       SoundReady: Boolean;
  18.       Ti        : TTimer;
  19.  
  20.       Procedure WndProc(Var MSG: TMessage); Override;
  21.   End;
  22.  
  23.  CONST
  24.   FreeTimerMsg = WM_USER + 555;
  25.  
  26.  VAR
  27.   Form1     : TForm1;
  28. Implementation
  29.  {$R *.lfm}
  30.  
  31.  
  32. Procedure TForm1.FormCreate(Sender: TObject);
  33.  Begin
  34.   Ti         := TTimer.Create(Nil);
  35.   Ti.Interval:= 30;
  36.   Ti.Enabled := False;
  37.   Ti.OnTimer := @tiPlaySoundDo;
  38.  
  39.   SoundReady:= False;
  40.   Ti.Enabled:= True;
  41.  End;
  42.  
  43.  
  44. Procedure TForm1.FormPaint(Sender: TObject);
  45.  Begin
  46.   SoundReady:= True;
  47.  End;
  48.  
  49.  
  50. Procedure TForm1.tiPlaySoundDo(Sender: TObject);
  51.  Begin
  52.   If SoundReady
  53.   Then
  54.    Begin
  55.     Ti.Enabled:= False;
  56.     Sleep(400);
  57.     Windows.Beep(800, 800);
  58.  
  59.     PostMessage(Form1.Handle, FreeTimerMsg, 0,0);
  60.    End;
  61.  End;
  62.  
  63.  
  64. Procedure TForm1.WndProc(Var MSG: TMessage);
  65.  Begin
  66.   If MSG.Msg = FreeTimerMsg
  67.   Then Ti.Free
  68.   Else Inherited WndProc(MSG);
  69.  End;
  70.  
  71.  
  72. End.                    
  73.  
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #21 on: June 01, 2016, 10:41:20 pm »
The behaviour as known to me is that a constant defined inside a local procedure keeps it value.

That is only true for typed constants, and only true in the {$J+} compiler state (as Thaddy pointed out), which is normally true, since {$J+} is the default FPC setting, for historical reasons of Delphi compatibility. With {$J+} typed constants are assignable wherever they are declared (whether in a local procedure or not).
As has been often noted, the word constant in "typed constant" is rather misleading in this case, since the 'constant' is actually an initialized variable. Of course it does remain constant ... until you change its value.
Uhm... pardon me in advance, but i believe i misunderstood the first part of what you just wrote as it doesn't seem to add up for me (most probably wrong interpretation on my part).

In mode J- you are not allowed to change the value of a constant. So, we can rule out that it ever changes, and therefor will always contain the last assigned value (it keeps it value).

In mode J+ you are allowed to change the value of a constant but only when type defined. If it is not type defined the compiler does not allow you to change it during runtime and in case it is type defined it will keep its value (that was last assigned to it).

I admit i could perhaps have been more explicit in my wording: The behaviour as known to me is that a constant will always contain the value that was last assigned to it.

With regards to the second part of your message i agree that the name constant is misleading but on the other hand such constants behave differently as variables do when the circumstances are similar (e.g. variables defined in same way 'initializes' itself to again on re-entry of the procedure/function).

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #22 on: June 01, 2016, 11:10:56 pm »
In mode J- you are not allowed to change the value of a constant. So, we can rule out that it ever changes, and therefor will always contain the last assigned value (it keeps it value).

In mode J+ you are allowed to change the value of a constant but only when type defined. If it is not type defined the compiler does not allow you to change it during runtime and in case it is type defined it will keep its value (that was last assigned to it).

You summarize  the possibilities well. We were both rather imprecise in what we wrote earlier.

bruce.button

  • Jr. Member
  • **
  • Posts: 59
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #23 on: June 04, 2016, 01:22:22 pm »
A big thank you to everyone who posted on this thread. I've learned a lot!

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #24 on: September 26, 2017, 05:30:02 pm »
This works for me very fine....

Without "Application.QueueAsyncCall(@AsyncSound, 0);" the Beep-sound plays but the window is not fully visible...
Code: Pascal  [Select][+][-]
  1. UNIT Unit1;
  2. {$MODE OBJFPC}{$H+}{$J-}
  3.  
  4. Interface
  5.  USES
  6.   Windows, Classes,  SysUtils,
  7.   Forms,   Controls, StdCtrls;
  8.  
  9.  TYPE
  10.   TForm1 = Class(TForm)
  11.  
  12.    Button1: TButton;
  13.    Procedure Button1Click (Sender: TObject);
  14.  
  15.     PRIVATE
  16.      Procedure AsyncSound(Data: PtrInt);
  17.   End;
  18.  
  19.  VAR
  20.   Form1: TForm1;
  21.  
  22. Implementation
  23.  {$R *.LFM}
  24.   USES Unit2;
  25.  
  26. Procedure TForm1.Button1Click(Sender: TObject);
  27.  Begin
  28.   Form2:= TForm2.Create(Self);
  29.   Form2.Show;
  30.  
  31.   // After FormCreation do whatever you like !!!
  32.   Form2.StaticText1.Caption:= 'I am Form2...';
  33.   Form2.Button1.Caption    := 'I am the first button';
  34.   Form2.Edit1.Text         := 'Hello Hello Hello';
  35.  
  36.   // Windows.Beep(800, 1000);
  37.   Application.QueueAsyncCall(@AsyncSound, 0);
  38.  End;
  39.  
  40.  
  41. Procedure TForm1.AsyncSound(Data: PtrInt);
  42.  Begin
  43.   Windows.Beep(800, 1000);
  44.  End;
  45.  
  46. END.

It's probably a good idea to use a second thread or a sound lib to play longer sounds. Then the user can use the form while playing the sound...
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: What is the correct way to execute instructions AFTER opening a form
« Reply #25 on: September 26, 2017, 11:50:44 pm »
Widows has a PlaySound with Async option, what that means is the call will return to
allow the app to continue on.
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018