Jump to content
Nicolò Blunda

SplashForm freeze

Recommended Posts

Hello.
My app contains many Forms.
None Form take a long time to be create and show (i've checked this...).
But the app is very slow to open.
I've tryed with SplashForm.
This code, in .DPR file, works fine (the FormSplash.Close method is inside OnShow method of MainForm).
But, SpalshForm seems to be frozen until Main Form is shown: if i insert a TImage with TBitmapListAnimation (to show classical "wait wheel") animation freezes until MainForm close SpashForm.

Thank you.
 

BEGIN
  Application.Initialize;
  Application.Title:= 'My Slow App';
  FormSplash:= TFormSplash.Create(Application);
  try
    Application.CreateForm(TFormMain, FormMain);
    Application.CreateForm(TForm2, Form2);
    Application.CreateForm(TForm3, Form3);
    Application.CreateForm(TForm4, Form4);
    Application.CreateForm(TForm5, Form5);
    FormSplash.Show;
    Application.ProcessMessages;
  finally
  end;
  Application.Run;
END.

 

Share this post


Link to post

The Delphi VCL is not multi-threaded. The code that's running to create all those forms will block code like your animation from working.

Its rarely a good idea to actually 'create every form' on startup like this. I know that's how Delphi does it, but its less than ideal.

 

App startup will either be slow because

You have some code running in an initialization section somewhere, either in your code or the many libraries you may be using.

You have a database connection on a form, perhaps to a database that may not be connectable, and this is causing a delay until it times out when creating a form

 

Generally I would suggest these principles:

Create forms when they are first used rather than at startup or during an idle stage when the user won't notice

Move operations that aren't VCL/drawing related into threads, allowing the UI to still update whilst they run i.e. disk operations, database operations etc

 

If these things don't work, even though it will have other impacts, you could consider creating a launcher app that shows the splash screen whilst then launching the real app.

This will cause a few issues with taskbar/icons etc, but maybe a solution for a very slow startup that can't otherwise be coded around with the above 2 suggestions.

 

Delphi can sometimes encourage people to create enormous forms with thousands of components. This is the only reason I can think of in a modern computing environment other than an IO delay for any noticeable 'load time' during creation of forms on startup.

 

 

  • Like 2

Share this post


Link to post

Your problems is that you are trying to show splash form after all other forms are created. You should show it immediately upon construction.

 

 

BEGIN
  Application.Initialize;
  Application.Title:= 'My Slow App';
  FormSplash:= TFormSplash.Create(Application);
  FormSplash.Show;

  Application.CreateForm(TFormMain, FormMain);
  Application.CreateForm(TForm2, Form2);
  Application.CreateForm(TForm3, Form3);
  Application.CreateForm(TForm4, Form4);
  Application.CreateForm(TForm5, Form5);

  FormSplash.Free; // FormSplash is no longer needed
  
  Application.Run;
END.

 

There is also no point in having empty try...finally block, it serves no purpose. If construction of any of the forms fails, the application will just terminate. You could add some error handling in such case, but that is another story.

 

You should not use FormSplash variable anywhere else after you call Free on it as it will be a dangling pointer. That should not be too much of an issue since it is only a splash form and it is not supposed to be used anywhere else. Otherwise you would have to use FreeAndNil(FormSplash) to be sure that reference is niled when object is gone and the variable is still accessible to other code.

 

  • Like 1

Share this post


Link to post

I don't use FMX, but in my VCL apps, I make the Splash Screen more responsive simply by updating and repainting it after each Application.CreateForm call. I have not had problems doing this.

Share this post


Link to post

Thank to everyone!
I want to emphatize some issues:
Long time is effect of Application.run method. Above instruction, in DPR file (Form creation) are very fast.
Dalija Prasnikar: even showing Splash Foam BEFORE other Form creation, it appears, freezed, for very short time. The only way to show it is to insert Close or Free method in MainForm.OnShow event.
x DJSox: what method I can use for repaintig Splash Form? 

Share this post


Link to post

Thank to everyone!
I want to emphatize some issues:
Long time is effect of Application.run method. Above instruction, in DPR file (Form creation) are very fast.
@Dalija Prasnikar: even showing Splash Foam BEFORE other Form creation, it appears, freezed, for very short time. The only way to show it is to insert Close or Free method in MainForm.OnShow event.
@DJSox: what method I can use for repaintig Splash Form? 

Share this post


Link to post

Below is what I had used in the past. The splash screen had a label that was updated by the forms being loaded in their onCreate events. The forms updated the label, and invoked it paint event with label.repaint (might have been label.refresh). The Application.ProcessMessages allowed the paint events to run. Perhaps you could just do a SplashScreen.repaint after each form loads as well. If an individual form creation takes too long, perhaps you could force the splashscreen to update from within the forms onCreate event.

 

Dan

 

 

{$R *.RES}

begin
 Set8087CW($1332) ; //fix for floating point issue should be in all dpr's
 Application.Initialize;

  ESPlotsSplashForm :=TESPlotsSplashForm.create(nil);
  ESPlotsSplashForm.show;

  Application.Title := 'ES Plots';
  Application.HelpFile := 'D:\ESPlots\esplots.chm';
  Application.ProcessMessages;
  Application.CreateForm(TESPlotsMainForm, ESPlotsMainForm);
  Application.CreateForm(TSnoopForm, SnoopForm);
  Application.CreateForm(TDefineHeaderForm, DefineHeaderForm);
  Application.CreateForm(TFloatDisplayForm, FloatDisplayForm);
  Application.ProcessMessages;
  Application.CreateForm(TStoreDataForm, StoreDataForm);
  Application.ProcessMessages;
  Application.CreateForm(TESPlotsLoadDataForm, ESPlotsLoadDataForm);
  Application.ProcessMessages;
  Application.CreateForm(TSaveDataForm, SaveDataForm);
  Application.ProcessMessages;
  Application.CreateForm(TEditTextForm, EditTextForm);
  Application.ProcessMessages;
  Application.CreateForm(TChartForm, ChartForm);
  Application.ProcessMessages;
  ESPlotsSplashForm.Hide;
  ESPlotsSplashForm.free;

  ReportMemoryLeaksOnShutdown := DebugHook <> 0;

  Application.Run;
end.

 

Share this post


Link to post
On 10/13/2024 at 6:27 AM, Nicolò Blunda said:

even showing Splash Foam BEFORE other Form creation, it appears, freezed, for very short time. The only way to show it is to insert Close or Free method in MainForm.OnShow event.

If the form is not  completely painted, then you should call Application.ProcessMessages. The need to have that can depend on the controls and code you have on the splash form. Animation will depend on message processing, so using animation in splash form is not advisable. (I missed that part in your initial post).  If you insist on having animation, then you would have to call Application.ProcessMessages more frequently, like @DJSox proposed, but the animation might not be smooth depending on how much time is needed for constructing each form. 

 

Calling MainForm.Free (or Close depending on the code) will destroy the main form. Not to mention that even closing in OnShow would prevent main form from becoming visible, so this is not something you should be doing at all. It does not serve any purpose.

Share this post


Link to post

Perhaps using threads might help, to keep animations flowing.
But to be honest, I really would rather skip the whole SplashScreen idea at all, especially with animations.
Even using threads might get into nightmares, not worth the efford at all, for example splash screens might stay invisible, behind other processes etc.
From my experience, splash screens are a call for problems only.
It might confuse, en-nerve your users, waiting for something usable showing up.
My preferred strategy, if that is possible ( not always can be done like this ), show the main entry page as soon as possible in a greyed out manner maybe plus "loading ..." label,
and lazy-load the rest of the app afterwards.
This gives a much better, responsible user experience IMHO, which is not interruppted or cluttered by splash-screens, which always felt to be too long.
 

Edited by Rollo62

Share this post


Link to post
1 hour ago, Rollo62 said:

Perhaps using threads might help, to keep animations flowing.

Creating forms and running animation are all tasks that need to run in the main thread. Adding background threads would not help here.

  • Like 1

Share this post


Link to post
21 hours ago, Dalija Prasnikar said:

If the form is not  completely painted, then you should call Application.ProcessMessages. The need to have that can depend on the controls and code you have on the splash form. Animation will depend on message processing, so using animation in splash form is not advisable. (I missed that part in your initial post).  If you insist on having animation, then you would have to call Application.ProcessMessages more frequently, like @DJSox proposed, but the animation might not be smooth depending on how much time is needed for constructing each form. 

 

Calling MainForm.Free (or Close depending on the code) will destroy the main form. Not to mention that even closing in OnShow would prevent main form from becoming visible, so this is not something you should be doing at all. It does not serve any purpose.

Thanks. But I call SplashForm.Close in the MainForm.Show event, NOT MainForm.Close (none sense...).
And this works fine, showing SplashForm (freezed) until MainForm is visible.
Otherwise, SplashForm colses before the long "blind" time, until MainForm is showed..

Edited by Nicolò Blunda
  • Like 1

Share this post


Link to post
35 minutes ago, Nicolò Blunda said:

Thanks. But I call SplashForm.Close in the MainForm.Show event, NOT MainForm.Close (none sense...).

I misinterpreted your post. 

 

However, if you do that, then you must not call Free on SplashForm, but FreeAndNil and then check whether it is nil before calling Close. You could also just call FreeandNil in the MainForm.Show event as releasing the form would also free it. 

 

OnShow event can be triggered more than once and freeing the form without niling the reference would mean that you are accessing dangling pointer which can crash your application. FreeAndNil can be safely called on nil reference so you wouldn't have issues with that.

Share this post


Link to post
18 hours ago, Rollo62 said:

Perhaps using threads might help, to keep animations flowing.
But to be honest, I really would rather skip the whole SplashScreen idea at all, especially with animations.
Even using threads might get into nightmares, not worth the efford at all, for example splash screens might stay invisible, behind other processes etc.
From my experience, splash screens are a call for problems only.
It might confuse, en-nerve your users, waiting for something usable showing up.
My preferred strategy, if that is possible ( not always can be done like this ), show the main entry page as soon as possible in a greyed out manner maybe plus "loading ..." label,
and lazy-load the rest of the app afterwards.
This gives a much better, responsible user experience IMHO, which is not interruppted or cluttered by splash-screens, which always felt to be too long.
 

Thank you very much.
After a lot of investigation, i see more delay time (5/6 seconds), with NONE form showed (SpalsScreen apart) is cuased ONLY by Application.Run line.
The Forms creations take very little time (0,5/0,7 seconds).
Main form have two processes with potentially criticity (access to online websercices for autentication), but in different thread.
So, I don't understand why the appearance of MainForm take so long time, and i don't know how to show it (as you suggest) with "gray aspect".

Share this post


Link to post
1 hour ago, Dalija Prasnikar said:

I misinterpreted your post. 

 

However, if you do that, then you must not call Free on SplashForm, but FreeAndNil and then check whether it is nil before calling Close. You could also just call FreeandNil in the MainForm.Show event as releasing the form would also free it. 

 

OnShow event can be triggered more than once and freeing the form without niling the reference would mean that you are accessing dangling pointer which can crash your application. FreeAndNil can be safely called on nil reference so you wouldn't have issues with that.

Thank you!

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×