delphimenuhelp-system

How Do I Tell Which Menu Item is Open in Delphi?


I am implementing context sensitive help in my Delphi 2009 application. It works fine except in one case. I cannot identify that I am in the main menu, and which menu item has been opened.

What I want to do is if the user has opened the File menu and while its open presses F1, then I'll bring up my help on the File menu. If they open the Edit menu and press F1, then I'll bring up my help on the Edit menu, etc.

I am using ApplicationEventsHelp to process the user's pressing of F1 as follows:

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;

As I mentioned, this works for everything except the main menu. I've tried using

FindVCLWindow(Mouse.CursorPos)

and other such methods that identify the active control to see if they would identify the menu, but they don't seem to.

Is there a way to tell which menu item (if any) is open when the F1 key is pressed?


Thank you everyone for your help and good ideas.

Just to document my final solution, I found that the system is not particularly good at figuring out which control it is in and sometimes gets it wrong and passes incorrect data to ApplicationEventsHelp which brings up an inappropriate help page.

After experimenting and using the solution for handling the menus in the accepted answer, I found it was best to identify which control I was in to bring up the correct help item. I ended up not even using the HelpKeyword property, but hardcoding it. The code is clear and it works. I also have my the help for my RVEdit window bringing up different help pages depending on the section of the document you are in (my CurCursorID tells me that).

For anyone who wants to do this like I did, here is how:

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;

I did have to put 11 through 17 into the HelpContext property of the MenuItems in my 7 main menus so that the correct help would come up depending on which menu you were in. The detection of the menu item is the help the answer to this question provided me.

The nice thing is that this code is easy to follow (using HelpKeywords instead of HelpContext numbers) and will probably still work even after conversion to Delphi XE and FireMonkey.


Solution

  • Looking at Command = HELP_COMMAND and the cast of Data to PChar, it seems you work with a help system based on keywords rather then on context identifiers (HelpType = htKeyword).

    (Here in Delphi 7) Menu items do not have the HelpType and HelpKeyword properties, so you are bound to use the HelpContext property:

    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;