向TMenuItem发送WM_COMMAND消息

3
在我的 Delphi 表单的 OnShow 方法中,我确定一旦表单打开,必须自动打开对话框 - 我应该能够通过模拟菜单项的点击来实现这一点。
然而,调用 menuitem.Click 会在主窗体打开之前弹出对话框 - 这不是我想要的。
我期望应该能做到我想要的,但我找不到要传递给“wparam”的参数,以便将单击发送到我的菜单项。
PostMessage(handle, WM_COMMAND, wparam, 0)

MSDN WM_COMMAND文档中提到了IDM_*标识符,但在Delphi中如何使用呢?

6个回答

5

我知道这是一个非常老的问题,但尽管在某种程度上得到了解决,真正的问题仍然没有得到回答。

'TMenuItem'的命令项标识符在Command属性中。根据WM_COMMAND的文档,'wParam'的高位应为'0',低位应为菜单标识符;

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

或者简单地;
PostMessage(Handle, WM_COMMAND, MyMenuItem.Command, 0);

使用弹出菜单项会有一些不同:VCL使用一个不同的实用程序窗口来处理弹出菜单的消息。全局变量PopupList在其Window属性中具有其句柄。
PostMessage(PopupList.Window, WM_COMMAND, MyPopupMenuItem.Command, 0);

+1;哇,谢谢,我今天正好在找这个东西。 - Jeroen Wiert Pluimers

2

也许你可以尝试在OnActivate事件中打开对话框?我不确定除了表单显示时是否还会再次触发OnActivate事件,但如果它确实触发了,你可以使用:

procedure TForm1.FormActivate(Sender: TObject);
begin
  Form2.ShowModal;
  Self.OnActivate := nil;
end;

谢谢 - 不过这仍然在主窗体实际出现之前触发,因此对话框会出现“孤立”。 - Roddy
我非常确定OnActivate事件是在窗体显示后触发的,因为如果窗体没有显示,它怎么能被激活呢。 - zz1433
你说得对:我与第三方组件有交互,这导致了提前激活。 - Roddy
2
Onactivate 可以被触发多次。一个解决方案是在 onshow 中设置 on activate 事件,并在 onactivate 过程中重置它。(另一个解决方案是使用标志。) - Toon Krijthe

0
或者,您可以通过以下方式处理Application.OnIdle事件...
if not DialogDone then
begin
    MyDialogForm.ShowModal; // or menuItem.Click ....
    DialogDone := true;
end;

OnIdle 事件在窗体显示且消息队列为空时才会第一次触发。


我不建议这样做。OnIdle 应该用于小的状态更新和可能的后台处理,但不适用于单次触发操作。 - Toon Krijthe

0

我认为你不能直接向菜单项发送消息,但你可以将其发布到主窗口并从那里显示对话框。我这样做,效果很好,这样对话框(在我的情况下是登录提示)会出现在主窗口的顶部,以避免混淆。

-马克

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

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

0

我使用过的一种方法与MarkF的解决方案非常相似,即创建一个新的用户定义消息类型,并在确定需要在主窗体显示后执行此其他进程时,使用该类型发送消息给自己:

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;

这种方法的好处是您可以控制消息的生成,因此可以填充任何lparam或wparam以供稍后由处理程序使用。我直接通过application.mainform发送消息,但您也可以使用当前窗体的句柄。

0

如果您想要表单按照正常的Show/ShowModal方式呈现,完全绘制并立即执行其他操作,那么您是否必须使用一次性计时器来完成呢?

tmrKickOff:TTimer,100毫秒间隔,设计时处于禁用状态,触发'tmrKickOffTimer'事件。
在创建表单时, tmrKickOff.Enabled:=false; //以防万一在 IDE 中发生了什么问题
在表单显示时,在所有其他内容结束时; tmrKickOff.Enabled:=true;
在tmrKickOffTimer中 begin tmrKickOffTimer.Enabled:=false; menuItemClick(nil); end;

对于风格、形式和任何错误处理,我们深表歉意。:-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接