Как мне узнать, какой пункт меню открыт в Delphi?

Я внедряю контекстно-зависимую помощь в моем приложении 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 в свойство HelpContext MenuItems в моих 7 основных меню, чтобы в зависимости от того, в каком меню вы работали, должна была появиться правильная справка. Обнаружение пункта меню - это помощь, ответ на этот вопрос предоставил мне.

Приятно, что за этим кодом легко следовать (используя HelpKeywords вместо чисел HelpContext) и, вероятно, все еще будет работать даже после преобразования в Delphi XE и FireMonkey.

3 ответа

Решение

Смотря на Command = HELP_COMMAND и актерский состав Data в PCharПохоже, вы работаете с системой справки, основанной на ключевых словах, а не на идентификаторах контекста (HelpType = htKeyword).

(Здесь, в Delphi 7) пункты меню не имеют HelpType а также HelpKeyword свойства, поэтому вы обязаны использовать 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;

Улавливая окно сообщения "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, чтобы активировать правильную справку.

Вы можете использовать функцию GetMenuItemRect:
1. Просмотрите все элементы в главном меню и вызовите GetMenuItemRect, чтобы получить позицию элемента. Функция будет работать, только если элемент отображается.
2. Используйте GetCursorPos и ​​PtInRect, чтобы проверить, находится ли мышь над пунктом меню, и вызвать соответствующий раздел справки.

Другие вопросы по тегам