6

I want to create a splash screen (before the main form) that will be shown for x seconds but I don't want to delay the creation of the main form with x seconds.

So, I create the splash screen form, create the main form then after x seconds I close the splash form.
From what I understand the first form created with CreateForm is the main form. Is this right?

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := FALSE;
  Application.Title := AppName;
  frmSplash:= TfrmSplash.Create(NIL);         <----- not main form??
  Application.CreateForm(TfrmMain, frmMain);  <----- main form??
  frmMain.LateInitialization;
  frmMain.show;
  Application.Run;
end.

Closing the splash form
The splash screen has a TTimer. The timer does some animation in the splash form and after x seconds it closes the form:

procedure TfrmSplash.CloseSplashForm;
begin
 Timer.Enabled:= FALSE;
 Close;        <-- I do see the program reaching this point
end;

However, the application leaks mem at shutdown:

5 - 12 bytes: TMoveArrayManager<System.Classes.TComponent> x 4, Unknown x 2
13 - 20 bytes: TObservers x 1, TList x 3, Unknown x 3
21 - 36 bytes: TComponent.GetObservers$942$ActRec x 1, TPen x 2, TIconImage x 1, TPadding x 1, TBrush x 3, TTouchManager x 2, TMargins x 2, TSizeConstraints x 2, TList<System.Classes.TComponent> x 4, UnicodeString x 3, Unknown x 6
37 - 52 bytes: TDictionary<System.Integer,System.Classes.IInterfaceList> x 1, TPicture x 1, TGlassFrame x 1, TFont x 4
53 - 68 bytes: TIcon x 1
69 - 84 bytes: TControlScrollBar x 2
85 - 100 bytes: TTimer x 1
101 - 116 bytes: TControlCanvas x 2
149 - 164 bytes: Unknown x 2
437 - 484 bytes: TImage x 1
917 - 1012 bytes: TfrmSplash x 1

It looks like the frmSplash is not actually freed.

Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • The "Close" in CloseSplashForm does not automatically free the form.Do you free it when closing? – Andreas Aug 10 '17 at 10:36
  • 3
    I'm not sure why the Timer is needed here. Why not Free it manually once the main form is fully initialized (in the main from OnShow for example)? – kobik Aug 10 '17 at 11:44

3 Answers3

8

Add an OnClose event to the splash form and set

Action := caFree;
Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
  • Isn't the caFree the default behavior? I will try it anyway right now. – Gabriel Aug 10 '17 at 10:37
  • Yes. It worked.... partially... Now I have the leak if I close the main form while the splash is still visible. – Gabriel Aug 10 '17 at 10:42
  • 3
    The default behavior is _caHide_, except for MDI child forms where it is _caMinimize_ or _caNone_. – Uwe Raabe Aug 10 '17 at 12:00
  • 2
    @All for free: Use this and combine it with setting `Application` as the owner - this removes the leak while still releasing resources as soon as possible. – mghie Aug 10 '17 at 19:06
4

The splash form leaks because nothing destroys it. Some options:

  • Pass the Application object as the owner of the splash form when you create it.
  • Manually destroy it.
  • Ignore the leak. It doesn't much matter since you only create one splash form so failing to destroy it won't lead to any great consumption of resources.

With the first option the splash form won't be destroyed until the application ends. That's not all that different from intentionally leaking the form.

Choosing to destroy the form manually is a little more tricky. You'd want to do that when you close the splash form but you can't destroy an object from one of its own event handlers. So instead you could call the Release method of the form and queue the form's destruction. If you go this way you need to ensure that the form is destroyed even if the timer never expires. Making the form be owned by the Application object would get that done.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • First item (pass application) did it. Thanks! – Gabriel Aug 10 '17 at 10:43
  • 2
    *"Ignore the leak"* is a very bad suggestion. no matter how minor it is. – kobik Aug 10 '17 at 11:17
  • 1
    @kobik That's debatable. Why is it any worse than having the application object as owner? I personally would not do it, but there is a school of tough that says deallocation at process shutdown is a waste of resources. – David Heffernan Aug 10 '17 at 11:30
  • I wont go into this debate. "there is a school of tough..." - I'm not one of them and I know you especially are not either. ignoring leaks is an opening to very bad coding/programming style. – kobik Aug 10 '17 at 11:34
  • 1
    @kobik it's not a leak to skip deallocation at process termination. The argument in favour of tidying up is that if you suppress leak detection now, code may be modified in such a way to turn what was previously benign into an actual leak. So, no I would not do this, but there are people that would take a different view in some situations. There are programs which can spend significant time at termination simply deallocation memory. Skipping that improves performance. – David Heffernan Aug 10 '17 at 11:49
  • I give up. Let it leak. – kobik Aug 10 '17 at 22:32
  • @kobik You don't agree with my analysis in my previous comment? – David Heffernan Aug 11 '17 at 07:52
3

Since many years I use this construct:

program MyProg;
uses
  Vcl.Forms,
  MainFrm in 'MainFrm.pas' {Zentrale},
  // Your Forms are here
  SplashFrm in 'SplashFrm.pas' {Splash};

{$R *.res}

var
  Sp: TSplash;

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.Title := 'XXXXXX';

{$IFDEF RELEASE}
  SP := TSplash.Create(nil);
  SP.Show;
  SP.Update;
{$ENDIF}

  Application.CreateForm(TZentrale, Zentrale);
  // ... and more Forms 

{$IFDEF RELEASE}
  SP.Hide;
  SP.free;
{$ENDIF}

  Application.Run;
kobik
  • 21,001
  • 4
  • 61
  • 121
Christine Ross
  • 465
  • 5
  • 14
  • Yes, but my question states that "I need to show the splash for x seconds". With your code the splash will stay visible for miliseconds if the 'Zentrale' is not an overcrowded form. – Gabriel Aug 10 '17 at 20:38
  • You can add a timer to your splash form and hide it after x seconds. The timer could be enabled in the onshow event. In you timer event you call hide after it reached the limit. The rest keeps the same – Christine Ross Aug 11 '17 at 09:37
  • "You can add a timer" - this is what I did. Please DO read my question, this time carefully. As it is, your answer does not add anything to the discussion (it is a random answer and it does not answer my question at all). – Gabriel Aug 11 '17 at 10:39
  • Your "Question" contains only one question "Is this right? ". The answer is Yes. Under Project/options/forms you can change the sequence of the created forms. But the first form is the main form or the main form is the first form. For further details read the help. – Christine Ross Aug 11 '17 at 15:15
  • You missed something: "How to create a form before the MainForm?". Probably because of the small font :) :) :) Anyway, here on stackoverflow the "Question" is the whole body of the original question. You cannot extract whatever phrase you like and and answer to it as an isolated idea. Please DO READ one more time the entire Question. Anyway, the Question was solved by David and Uwe. You can still add something ORIGINAL that could extend their answer, but still remaining in the context!!!! – Gabriel Aug 13 '17 at 09:17