views:

430

answers:

6

In my Delphi form's OnShow method, I determine that a dialog must be opened automatically once the form is opened - and I should be able to do this by simulating a click on a menuitem.

However, calling menuitem.Click brings up the dialog before the main form has opened - which is not what I want.

I expect that should do what I want, but I cannot find what parameters to pass for "wparam" to send the click to my menuitem.

PostMessage(handle, WM_COMMAND, wparam, 0)

The MSDN WM_COMMAND docs talk about IDM_* identifiers, but how does that appear in Delphi?

+2  A: 

Perhaps you can try to open the dialog in the OnActivate event ? I am not really sure if the OnActivate gets fired again other than when the form is shown but if it does you can use :

procedure TForm1.FormActivate(Sender: TObject);
begin
  Form2.ShowModal;
  Self.OnActivate := nil;
end;
Aldo
Thanks - however this still fires before the main form actually appears, so the dialog appears 'orphaned'.
Roddy
I'm very sure OnActivate is fired after the form is shown, because if the form isn't shown how can it be activated.
Aldo
You're right: I have an interaction with a thrid-party component which was triggering activate early.
Roddy
+1 Oh cool, you learn something useful every day! :-)
robsoft
Onactivate can be fired more than once. A solution is to set the on activate event in the onshow and reset it on the onactivate proc. (Another solution is to work with a flag.)
Gamecat
A: 

Wouldn't you have to do this with a one-time timer, if you want the form to appear as per a normal Show/ShowModal, get drawn (etc) fully, and then immediately do something else?

tmrKickOff : a TTimer, 100 ms interval, disabled at design time, 
fires off a 'tmrKickOffTimer' event.


in form create,
tmrKickOff.Enabled:=false; //just in case something happened in IDE

in form show, at end of all other stuff;
tmrKickOff.Enabled:=true;

in tmrKickOffTimer
begin
  tmrKickOffTimer.Enabled:=false;
  menuItemClick(nil);
end;

with apologies for style, form and any error-trapping :-)

robsoft
A: 

Alternatively, handle the Application.OnIdle event with something along the lines of ...

if not DialogDone then
begin
    MyDialogForm.ShowModal; // or menuItem.Click ....
    DialogDone := true;
end;

OnIdle won't fire (for the first time) until the Form is shown and the message queue is empty.

MikeJ-UK
I do not reccommend this. OnIdle should be used for small status updates and possibly background processing. But not for single fire actions.
Gamecat
A: 

I don't think you can send a message directly to your menu item, but you can just post it to the main window and show your dialog from there. I do this and it works great so that the dialog box (in my case, a login prompt) appears on top of the main window to avoid confusion.

-Mark

procedure WMPostStartup(var Message: TMessage); message WM_POSTSTARTUP;

procedure TMainForm.WMPostStartup(var Message: TMessage);
begin
  Self.Refresh;
  // Now show the dialog box.
end;
MarkF
A: 

One method I have used, which is very simular to MarkF's solution, is to create a new user defined message type and send a message using that type to yourself when you determine that you need to perform this other process after your main form displays:

const
  wm_SpecialProc = wm_User + 1;

procedure TForm1.WMSpecialProc(var Message:tMessage); message wm_SpecialProc;
begin
  Form2.ShowModal;
end;

procedure TForm1.OnShow(Sender:tObject);
begin
  if true then
    PostMessage(Application.MainForm.Handle,wm_SpecialProc,0,0);
end;

The nice thing about this method is that you are in control of the message generation, so can populate ANY lparam or wparam you want to later use by your handler. I sent the message directly through the application.mainform but you could also just say handle for the current form.

skamradt
+2  A: 

(I know this is a very old question but despite being resolved in some way the real question has really gone unanswered.)
--

The command item identifier of a 'TMenuItem' is in the Command property. According to WM_COMMAND's documentation the high word of 'wParam' would be '0' and the low word would be the menu identifier;

PostMessage(Handle, WM_COMMAND, MakeWParam(MyMenuItem.Command, 0), 0);

or simply;

PostMessage(Handle, WM_COMMAND, MyMenuItem.Command, 0);


With a popup menu item there would be a slight difference: the VCL handles popup menus' messages with a different utility window. The global PopupList variable has the handle to it in its Window property;

PostMessage(PopupList.Window, WM_COMMAND, MyPopupMenuItem.Command, 0);
Sertac Akyuz
+1; gee thanks, I was just looking for something that does this today.
Jeroen Pluimers