1
votes

My system is windows 10 and Delphi 10.4.

I have several applications that work fine, they just look very ugly on startup.

The main issue is that I save the main window state when the application shuts down, such as window state, size, position etc and then restore them at start up.

I restore the main window parameters in the mainform oncreate event from an ini file and in the onactivate event, I load the program dynamic content from a project file.

Loading the project file may take 10 seconds or so, but in the meantime, the window has scaled to its final size (ie maximised) but all the main form visual components are still in their design time sizes.

It all sorts itself out once the project file has loaded, it just looks so ugly during that startup process.

I've tried all sorts of combinations of application.processmessages, update, refresh etc before loading the project file but nothing works in the onactivate event.

Weirdly, I tried to printscreen so I could post a picture of the effect but the resultant picture looked fine, so I am guessing it something held up in the graphics pipeline during application startup.

Is there an event that fires after the mainwindow has finished all its processing, so I can then start the dynamic content loading?

1
Load the settings in OnCreate -- not OnActivate (which may fire several times, not only on app startup).Andreas Rejbrand
I set a flag in onactivate so that it only gets called once and yes the settings are all loaded in oncreate.Andy k
Good. I almost consider that approach to be an idiom (or: set the OnActivate handler to nil). In any case, if loading takes 10 seconds, you should do it in a background thread. You shouldn't block the GUI thread that long. (I assume this 10-second loading does non-GUI stuff. If you are spending 10 seconds rearranging controls on a form, something is seriously wrong!)Andreas Rejbrand
When I encounter such an issue, I usually post a message back to my form that initiates the loading/processing. This message will be put at the end of the message queue, and thus all events that are currently in the queue will be processed before my message is processed. In a few cases, it has been necessary to also post a counter value that gets decremented in the message handler (f.ex. via the wParam value) and if it is greater than zero, I re-post the message to the back of the queue with this value one less, otherwise I do the processing.HeartWare
It seems to me that there is a missing event in the Form creation process. The issue can be duplicated by maximising the main form in the oncreate event and then putting a 10 second sleep in the onactivate event. You can clearly see the form is not in its final state until some time after onactivate has returned.Andy k

1 Answers

3
votes

Here is an example of the code I describe in the comment:

unit Unit83;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

CONST
  UM_LOADPROJECT = WM_USER+10;

type
  TForm83 = class(TForm)
    procedure FormActivate(Sender: TObject);
  private
    { Private declarations }
    procedure LoadProject(var Msg : TMsg); MESSAGE UM_LOADPROJECT;
    procedure LoadProjectFile;
  public
    { Public declarations }
  end;

var
  Form83: TForm83;

implementation

{$R *.dfm}

procedure TForm83.FormActivate(Sender: TObject);
begin
  OnActivate:=NIL;
  PostMessage(Handle,UM_LOADPROJECT,10,0)
end;

procedure TForm83.LoadProject(var Msg: TMsg);
begin
  IF Msg.wParam>0 THEN
    PostMessage(Handle,Msg.message,PRED(Msg.wParam),Msg.lParam)
  ELSE
    LoadProjectFile
end;

procedure TForm83.LoadProjectFile;
begin
  // Do the project file load
end;

end.

The "10" in the FormActivate's PostMessage is the number of times the message is put to the back of the queue. Start with the value 0 to test if it is necessary.