Как мне узнать, какой пункт меню открыт в 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, чтобы проверить, находится ли мышь над пунктом меню, и вызвать соответствующий раздел справки.