1

I have a MainForm, that while activating will call another Form to change app date (modal, show, close), and then make some checks and display a message if it applies in response to the checking.

Is there a way to show (paint) the MainForm, after closing the first Form, but before showing the messages?

Today:

  • MainForm.Activate
  • DateForm use
  • display MessageDlg over desktop (or other apps)
  • MainForm painted and visible

I want something like this, but I can figure out how:

  • MainForm.Activate
  • DateForm use
  • MainForm painted and visible
  • display MessageDlg over MainForm

Thanks for any idea!

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Speaker
  • 189
  • 2
  • 10
  • It would help if you could show the code you are using. But what I would probably do in this situation is use [`TThread.ForceQueue()`](http://docwiki.embarcadero.com/Libraries/en/System.Classes.TThread.ForceQueue) or equivalent to delay displaying the `MessageDlg()` until after the MainForm is ready, eg: `TThread.ForceQueue(nil, procedure begin MessageDlg(...); end);` – Remy Lebeau Jun 11 '21 at 00:02
  • You say: *Is there a way to show (paint) the MainForm, after closing the first Form, but before showing the messages?* **after** closing the first form, but **before** showing the messages. If you are showing the messages in the date-set-check-something form, how can they be shown if the form is closed. And why do you need a form to check the date? You really should show your code as you have it now. – Tom Brunberg Jun 11 '21 at 06:53
  • What about using OnShow instead of OnActivate? (Can't test myself right now) – Delphi Coder Jun 11 '21 at 16:17

1 Answers1

2

Post a delayed message to the MainForm in its OnActivate event, and then display the MessageDlg when that message is received and processed. Deactivate the OnActivate handler after the first use, or otherwise make sure that the message cannot be posted again.

const
  WM_DISPLAY_MSG = WM_APP + 1000;

type
  TMainForm = class(TForm)
    procedure FormActivate(Sender: TObject);
  private
    procedure WMDisplayMsg(var Message: TMessage); message WM_DISPLAY_MSG;
  end;

var
 MainForm: TMainForm;

implementation

{$R *.dfm}

uses
  DateForm;

procedure TMainForm.FormActivate(Sender: TObject);
var
  frm: TDateForm; 
begin
  OnActivate := nil;
  frm := TDateForm.Create(Self);
  try
    frm.ShowModal;
    if (some condition) then
      PostMessage(Handle, WM_DISPLAY_MSG, 0, 0);
  finally
    frm.Free;
  end;
end;

procedure TMainForm.WMDisplayMsg(var Message: TMessage);
begin
  MessageDlg('Message Here', mtInformation, [mbOK], 0);
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
USauter
  • 295
  • 1
  • 9
  • There is absolutely no reason for calling FormActivate(Self) from WMPostActivate instead of directly running appropriate code within that message handler. – Dalija Prasnikar Jun 11 '21 at 09:03
  • @DalijaPrasnikar It's a matter of taste. An outsider will suspect and search for the event in FormActivate. He will be happy if he has found the relevant code quickly. – USauter Jun 11 '21 at 09:18
  • While `PostMessage()` is certainly a valid solution to this problem, this code doesn't quite match the OP's description. It is the `MainForm` that is using `OnActivate` to show a second Form modally and then display a `MessageDlg()` after that second Form is closed. If you update your example to move `OnActivate` to the `MainForm`, and move `PostMessage()` to the `MainForm` after `Form2.ShowModal()` exits, then I'll upvote. – Remy Lebeau Jun 11 '21 at 14:51
  • @RemyLebeau `procedure TForm2.Start` added. – USauter Jun 11 '21 at 15:41