Как узнать, какой пункт меню открыт в Delphi? - PullRequest
3 голосов
/ 22 октября 2011

Я внедряю контекстно-зависимую помощь в моем приложении 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 ]

3 голосов
/ 22 октября 2011

Глядя на 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;
2 голосов
/ 22 октября 2011

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

1 голос
/ 22 октября 2011

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

...