8
votes

I have a project which has a main form and some other forms. When the app loads it needs to carry out some tasks and show the results in a modal form on top of the main form. The problem I have is that if I put the call to the function to do the tasks / creates and Show the modal form in the main forms onshow event the modal form appears but the main form does not until the modal form is closed, which is what I would expect to happen. To counter this I have added a timer to the main form and start it on the main forms onshow event the timer calls the function to do the tasks / create and show the modal form. So now the main form appears before the modal form.

However I cannot see this being the best solution and was wondering if anyone could offer a better one.

I am using Delphi 7

Colin

3
sorry for the off-topic by why does this question shows "blurred" in the main questions list?kobik
@kobik: AFAIK questions show dimmed when they have a tag you ignore, and when they have a negative vote score that is beyond a certain limit. BTW questions about the way SO works are better asked on the meta site (see link in the main navigation).Marjan Venema
@Marjan, Thanks for the info.kobik

3 Answers

10
votes

One commonly used option is to post yourself a message in the form's OnShow. Like this:

const
  WM_SHOWMYOTHERFORM = WM_USER + 0;

type
  TMyMainForm = class(TForm)
    procedure FormShow(Sender: TObject);
  protected
    procedure WMShowMyOtherForm(var Message: TMessage); message WM_SHOWMYOTHERFORM;
  end;

...


procedure TMyMainForm.FormShow(Sender: TObject);
begin
  PostMessage(Handle, WM_SHOWMYOTHERFORM, 0, 0);
end;

procedure TMyMainForm.WMShowMyOtherForm(var Message: TMessage);
begin
  inherited;
  with TMyOtherForm.Create(nil) do begin
    try
      ShowModal;
    finally
      Free;
    end;
  end;
end;
2
votes

Why dont you use the MainForm OnActivate event like so?

procedure TMyMainForm.FormActivate(Sender: TObject);
begin
  //Only execute this event once ...
  OnActivate := nil;

  //and then using the code David Heffernan offered ...
  with TMyOtherForm.Create(nil) do begin
    try
      ShowModal;
    finally
      Free;
    end;
end;

Setting the event to nil will ensure that this code is only run once, at startup.

0
votes

The OnShow event is fired immediately before the call to the Windows API function ShowWindow is made. It is this call to ShowWindow that actually results in the window appearing on the screen.

So you ideally need something to run immediately after the call to ShowWindow. It turns out that the VCL code that drives all this is inside a TCustomForm message handler for CM_SHOWINGCHANGED. That message handler fires the OnShow event and then calls ShowWindow. So an excellent solution is to show your modal form immediately after the handler for CM_SHOWINGCHANGED runs. Like this:

type
  TMyMainForm = class(TForm)
  private
    FMyOtherFormHasBeenShown: Boolean;
  protected
    procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  end;

.....

procedure TMyMainForm.CMShowingChanged(var Message: TMessage);
begin
  inherited;
  if Showing and not FMyOtherFormHasBeenShown then begin
    FMyOtherFormHasBeenShown := True;
    with TMyOtherForm.Create(nil) do begin
      try
        ShowModal;
      finally
        Free;
      end;
    end;
  end;
end;