【问题标题】:Sending WM_COMMAND to a TMenuItem将 WM_COMMAND 发送到 TMenuItem
【发布时间】:2009-08-11 11:04:45
【问题描述】:

在我的 Delphi 表单的 OnShow 方法中,我确定必须在打开表单后自动打开一个对话框 - 我应该能够通过模拟对菜单项的单击来做到这一点。

但是,调用 menuitem.Click 会在主窗体打开之前打开对话框 - 这不是我想要的。

我希望这应该做我想做的事,但我找不到要为“wparam”传递哪些参数以将点击发送到我的菜单项。

PostMessage(handle, WM_COMMAND, wparam, 0)

MSDN WM_COMMAND docs 谈论 IDM_* 标识符,但它在 Delphi 中是如何出现的?

【问题讨论】:

    标签: delphi winapi postmessage tmenuitem


    【解决方案1】:

    (我知道这是一个非常古老的问题,但尽管以某种方式解决了 真正的问题,但确实没有得到解答。)
    --

    “TMenuItem”的命令项标识符位于Command 属性中。根据 WM_COMMAND 的documentation,“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;哎呀,谢谢,我只是在寻找今天能做到这一点的东西。
    【解决方案2】:

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

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

    【讨论】:

    • 谢谢 - 但是这仍然会在主窗体实际出现之前触发,因此对话框显示为“孤立”。
    • 我很确定 OnActivate 在表单显示后被触发,因为如果表单没有显示如何激活它。
    • 你说得对:我与第三方组件进行了交互,该组件提前触发了激活。
    • Onactivate 可以多次触发。一个解决方案是在 onshow 中设置 on activate 事件并在 onactivate proc 上重置它。 (另一种解决方案是使用标志。)
    【解决方案3】:

    如果您希望表单按照正常的 Show/ShowModal 显示,您是否必须使用一次性计时器执行此操作,完全绘制(等),然后立即然后做点别的吗?

    tmrKickOff :一个 TTimer,100 ms 间隔,在设计时禁用, 触发“tmrKickOffTimer”事件。 在形式上创造, tmrKickOff.Enabled:=false; //以防万一IDE中发生了什么 在表格展示中,在所有其他内容结束时; tmrKickOff.Enabled:=true; 在 tmrKickOffTimer 开始 tmrKickOffTimer.Enabled:=false; 菜单项点击(无); 结尾;

    对风格、形式和任何错误陷阱表示歉意:-)

    【讨论】:

      【解决方案4】:

      或者,使用类似...的方式处理 Application.OnIdle 事件

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

      在显示表单并且消息队列为空之前,OnIdle 不会触发(第一次)。

      【讨论】:

      • 我不推荐这个。 OnIdle 应该用于小的状态更新和可能的后台处理。但不适用于单火行动。
      【解决方案5】:

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

      -马克

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

      【讨论】:

        【解决方案6】:

        我使用的一种方法,与 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 发送消息,但您也可以只说当前表单的句柄。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-27
          • 2023-03-04
          相关资源
          最近更新 更多