如何判断哪个菜单项在Delphi中打开?

时间:2011-10-22 04:11:24

标签: delphi menu help-system

我正在Delphi 2009应用程序中实现上下文相关帮助。除一例外,它工作正常。我无法确定我在主菜单中,以及哪个菜单项已打开。

我想要做的是,如果用户打开了“文件”菜单并且打开了F1按钮,那么我将在“文件”菜单上显示我的帮助。如果他们打开编辑菜单并按F1,那么我将在编辑菜单等上显示我的帮助。

我正在使用ApplicationEventsHelp来处理用户按下F1,如下所示:

function MainForm.ApplicationEvents1Help(Command: Word; Data: Integer;
  var CallHelp: Boolean): Boolean;
begin
  if Command = HELP_COMMAND then begin
    Application.HelpSystem.ShowTopicHelp(PChar(Data), Application.CurrentHelpFile);
    CallHelp := false;
  end;
  Result := true;
end;

正如我所提到的,这适用于除主菜单之外的所有内容。我尝试过使用

FindVCLWindow(Mouse.CursorPos)

和其他此类方法识别活动控件以查看它们是否会识别菜单,但它们似乎并不存在。

当按下F1键时,有没有办法告诉哪个菜单项(如果有的话)打开?


感谢大家的帮助和好主意。

为了记录我的最终解决方案,我发现系统并不是特别擅长弄清楚它在哪个控件中并且有时会出错并将不正确的数据传递给ApplicationEventsHelp,这会产生不适当的帮助页面。

在尝试并使用解决方案处理接受的答案中的菜单后,我发现最好确定我所处的控件以显示正确的帮助项目。我最终甚至没有使用HelpKeyword属性,而是硬编码。代码清晰,有效。我也帮助我的RVEdit窗口显示不同的帮助页面,具体取决于您所在的文档部分(我的CurCursorID告诉我)。

对于任何想要像我一样做的人,请按以下方式进行:

function TLogoAppForm.ApplicationEvents1Help(Command: Word; Data: Integer;
  var CallHelp: Boolean): Boolean;
var
  HelpKeyword: string;
  SType: string;

begin
  if Command = HELP_COMMAND then begin
    if PtInRect(RVEdit.ClientRect, RVEdit.ScreenToClient(Mouse.CursorPos)) then begin
      if CurCursorID = 'H' then HelpKeyword := 'RefTopReport'
      else if CurCursorID = 'T' then HelpKeyword := 'RefTableContents'
      else if CurCursorID = '~HNAME' then HelpKeyword := 'RefIndexNames'
      else if copy(CurCursorID, 1, 2) = 'N+' then HelpKeyword := 'RefIndexNames'
      else if CurCursorID = 'B' then HelpKeyword := 'RefBottomReport'
      else if CurCursorID <> '' then HelpKeyword := 'RefInformationArea'
      else HelpKeyword := 'RefEverythingReport';
      Application.HelpSystem.ShowTopicHelp(HelpKeyword, Application.CurrentHelpFile);
    end
    else if PtInRect(ElTree.ClientRect, ElTree.ScreenToClient(Mouse.CursorPos)) then
      Application.HelpSystem.ShowTopicHelp('RefTreeView', Application.CurrentHelpFile)
    else if PtInRect(TopToolbar.ClientRect, TopToolbar.ScreenToClient(Mouse.CursorPos)) then
      Application.HelpSystem.ShowTopicHelp('RefTopToolbar', Application.CurrentHelpFile)
    else if PtInRect(BottomToolbar.ClientRect, BottomToolbar.ScreenToClient(Mouse.CursorPos)) then
      Application.HelpSystem.ShowTopicHelp('RefBottomToolbar', Application.CurrentHelpFile)
    else
      Application.HelpSystem.ShowTopicHelp('RefMainWindow', Application.CurrentHelpFile);
    CallHelp := false;
  end
  else if Command = HELP_CONTEXTPOPUP then begin
    case Data of
      0: HelpKeyword := 'RefMenuBar';
      11: HelpKeyword := 'RefFileMenu';
      12: HelpKeyword := 'RefEditMenu';
      13: HelpKeyword := 'RefSearchMenu';
      14: HelpKeyword := 'RefNavigateMenu';
      15: HelpKeyword := 'RefViewMenu';
      16: HelpKeyword := 'RefOrganizeMenu';
      17: HelpKeyword := 'RefHelpMenu';
      else HelpKeyword := '';
    end;
    if HelpKeyword <> '' then begin
      Application.HelpSystem.ShowTopicHelp(HelpKeyword, Application.CurrentHelpFile);
      CallHelp := false;
    end;
  end;
  Result := true;
end;

我必须将11到17放入我的7个主菜单中的MenuItems的HelpContext属性中,以便根据您所在的菜单提供正确的帮助。检测菜单项是帮助答案提出这个问题。

好处是这个代码很容易遵循(使用HelpKeywords而不是HelpContext数字),即使在转换为Delphi XE和FireMonkey之后,它仍然可以工作。

3 个答案:

答案 0 :(得分:3)

查看Command = HELP_COMMAND以及DataPChar的演员表,您似乎使用的是基于关键字的帮助系统,而不是上下文标识符(HelpType = htKeyword)。

(在Delphi 7中)菜单项没有HelpTypeHelpKeyword属性,因此您必须使用HelpContext属性:

function TForm1.ApplicationEvents1Help(Command: Word; Data: Integer;
  var CallHelp: Boolean): Boolean;
begin
  if Command = HELP_COMMAND then
  begin
    //Application.HelpSystem.ShowTopicHelp(PChar(Data), Application.CurrentHelpFile);
    //Doesn't this do the same?
    Application.HelpKeyword(PChar(Data));
    CallHelp := False;
  end
  else if Command = HELP_CONTEXT then
  begin
    // Convert the context identifier to your keyword, or:
    Application.HelpContext(Data);
    CallHelp := False;
  end;
  Result := True;
end;

答案 1 :(得分:2)

通过捕获Windows消息“WM_MENUSELECT”,可以跟踪所选的菜单项。

有关详细信息,请参阅menuitemhints

示例:

 type
    TForm1 = class(TForm)
    ...
    private
      fMyCurrentSelectedMenuItem : TMenuItem;
      procedure WMMenuSelect(var Msg: TWMMenuSelect) ; message WM_MENUSELECT;
    end

procedure TForm1.WMMenuSelect(var Msg: TWMMenuSelect) ;
 var
    menuItem : TMenuItem;
    hSubMenu : HMENU;
 begin
    inherited; // from TCustomForm (so that Application.Hint is assigned)

    menuItem := nil;
    if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then
    begin
      if Msg.MenuFlag and MF_POPUP = MF_POPUP then
      begin
        hSubMenu := GetSubMenu(Msg.Menu, Msg.IDItem) ;
        menuItem := Self.Menu.FindItem(hSubMenu, fkHandle) ;
      end
      else
      begin
        menuItem := Self.Menu.FindItem(Msg.IDItem, fkCommand) ;
      end;
    end;

    //miHint.DoActivateHint(menuItem) ;
    fMyCurrentSelectedMenuItem := menuItem;
 end; (*WMMenuSelect*)

因此,当按下F1按钮时,您可以使用fMyCurrentSelectedMenuItem激活正确的帮助。

答案 2 :(得分:1)

您可以使用GetMenuItemRect函数:
  1.浏览主菜单中的所有项目并调用GetMenuItemRect以获取项目位置。仅当显示项目时,功能才有效   2.使用GetCursorPos和PtInRect检查鼠标是否超出菜单项并调用相应的帮助主题。