Reputation: 865
The game that I'm developing does some pre-processing when first loading and I want to show the user a "loading %" to make it clear that the game is not frozen.
I am trying to do this by waiting for the main form to show for the user and then displaying an updating progress bar while performing the pre-processing.
For the pre-processing to work, I need two pieces of information:
1. The form is in it's final size (maximized across the entire display).
2. The form is visible to the user.
Here is a log showing the order of the form events being triggered as my game loads. Keep in mind that I'm not actually changing the form's size using code in any of these events:
FormCreate
FormResize, clientSize : 0x0
FormResize, clientSize : 0x0
FormResize, clientSize : 0x0
FormResize, clientSize : 0x0
FormShow
FormActivate
FormResize, clientSize : 360x640
Currently, I try to show the loading screen on the last resize (the one indicating the form is actually the size of the display), but at this point, the main form is still not visible (even after the FormShow and FormActivate) and I end up with the Android's default "gray gradient" screen showing until after my pre-processing code already finished, never showing the progress bar.
I tried calling "application.processmessages" after updating the progress bar, but it doesn't make a difference...
How do I detect when my main form is actually visible to the Android user?
[Update]
I created a small application to demonstrate this issue:
https://github.com/bLightZP/Test_Splash
Upvotes: 0
Views: 976
Reputation: 1217
How about BecameActive event (ApplicationEvent)? Use this article, translate it with Google Translate http://delphifmandroid.blogspot.com/2016/09/delphi-android.html
Starting app:
09-20 20:13:43.151: I/info(15893): FMX: Project1: FormCreate
09-20 20:13:43.151: I/info(15893): FMX: Project1: FormResize
09-20 20:13:43.151: I/info(15893): FMX: Project1: FormResize
09-20 20:13:43.161: I/info(15893): FMX: Project1: FormResize
09-20 20:13:43.161: I/info(15893): FMX: Project1: FormShow
09-20 20:13:43.161: I/info(15893): FMX: Project1: FormActivate
09-20 20:13:43.161: I/info(15893): FMX: Project1: Finished Launching
09-20 20:13:43.221: I/info(15893): FMX: Project1: FormPaint
09-20 20:13:43.231: I/info(15893): FMX: Project1: Became Active
09-20 20:13:43.261: I/info(15893): FMX: Project1: FormPaint
09-20 20:13:43.281: I/info(15893): FMX: Project1: FormPaint
09-20 20:13:43.311: I/info(15893): FMX: Project1: FormPaint
Upvotes: 1
Reputation: 3602
This example illustrates using OnIdle, and also how it should be implemented.
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm1 = class(TForm)
ProgressBar1: TProgressBar;
private
FShown: Boolean;
procedure ApplicationOnIdleHandler(Sender: TObject; var Done: Boolean);
procedure ExecutePreProcessing;
procedure ExecutePreProcessingSynchronized;
public
constructor Create(AOwner: TComponent); override;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
constructor TForm1.Create(AOwner: TComponent);
begin
inherited;
// Method 1: Use OnIdle to execute code when the main form is visible:
Application.OnIdle := ApplicationOnIdleHandler;
// Method 2: Use a thread to execute the preprocessing. Comment out the line above if using this method, and uncomment the line below
// TThread.CreateAnonymousThread(ExecutePreProcessingSynchronized).Start;
end;
procedure TForm1.ApplicationOnIdleHandler(Sender: TObject; var Done: Boolean);
begin
if not FShown then
begin
FShown := True;
ExecutePreProcessing;
end;
end;
procedure TForm1.ExecutePreProcessing;
var
I: Integer;
begin
for I := 1 to 100 do
begin
Sleep(50);
ProgressBar1.Value := I;
Application.ProcessMessages; // <---- Not the best idea
end;
end;
procedure TForm1.ExecutePreProcessingSynchronized;
var
I: Integer;
begin
for I := 1 to 100 do
begin
Sleep(50);
// Ensure UI updates happen in the main thread
TThread.Synchronize(nil,
procedure
begin
ProgressBar1.Value := I;
end
);
end;
end;
end.
Upvotes: 3