Автоматически скрывающееся меню
В дизайне современных приложений меню занимает уже далеко не главное место, уступив первенство панелям инструментов. Такие тенденции наблюдаются например в Internet Explorer 7 и Windows Vista Explorer (Проводник).
В то же время меню у этих приложений есть, его можно показать, нажав клавишу Alt. Удобство такого подхода очевидно. На панели инструментов все команды на виду, их удобно искать и пользоваться ими. В то же время все команды, в том числе и отсуствующие на панели инструментов, доступны в полном меню, которое можно при необходимости отобразить на экране. При этом строка меню не отнимает место на экране. Особенно это актуально на широкоэкранных мониторах или для миниатюрных приложений, где даже пару десятков пикселей меню — лишнее место.
В Delphi VCL сделать такую возможность совсем не сложно. За отображение главного меню приложения отвечает компонент TMainMenu и свойство TForm.Menu. В компоненте хранятся элементы меню, а в свойстве указывается ссылка на этот компонент. Соотвественно, если указано свойство TForm.Menu, то меню отображается и наоборот.
Решение данной задачи можно разбить на следующие пункты:
- обеспечение простого способа скрытия и отображения меню;
- отображение и скрытие меню по нажатию клавиши Alt;
- скрытие меню при клике мышью в окне приложения.
Чтобы обеспечить удобную возможность скрытия меню, можно написать свойство MenuVisible для формы. Код получения значения данного свойства будет проверять, задано ли свойство TForm.Menu:
type TMyForm = class(TForm) MainMenu: TMainMenu; ... private function GetMenuVisible: Boolean; procedure SetMenuVisible(const Value: Boolean); public property MenuVisible: Boolean read GetMenuVisible write SetMenuVisible; end; implementation {$R *.dfm} function TMyForm.GetMenuVisible: Boolean; begin Result := Assigned(Menu); end;
Код установки значения свойства MenuVisible будет изменять свойство TForm.Menu, чтобы отобразить или скрыть главное меню. Вдобавок, если приложение не развернуто на весь экран, было бы удобно увеличивать высоту окна при появлении меню и уменьшать его при скрытии. Таким образом установленный пользователем размер рабочей области окна приложения не будет изменяться. Чтобы во время данных операций не наблюдалось мерцание, вышеописанный код следует обрамить блоком DisableAlign-EnableAlign.
procedure TMyForm.SetMenuVisible(const Value: Boolean); begin if Value = MenuVisible then Exit; DisableAlign; try if Value then Menu := MainMenu else Menu := nil; if WindowState <> wsMaximized then Height := Height + GetSystemMetrics(SM_CYMENU) * (Ord(Value) or Ord(not Value) * -1); finally EnableAlign; end; end;
Решение следующего пункта состоит в обработке нажатия клавиши Alt в событии OnKeyUp формы. Это решается простым кодом:
procedure TMyForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of VK_MENU: MenuVisible := not MenuVisible; VK_ESCAPE: MenuVisible := False; end; end;
В этом коде также добавлена обработка клавиши Esc, после нажатия которой меню скрывается. Почему именно OnKeyUp? Дело в том что обе клавиши, Alt и Esc, используются в самом меню, поэтому обработка OnKeyDown будет работать неправильно, а точнее через раз.
Следует обратить внимание, что в коде для обработки нажатия Alt используется не состояние служебных клавиш, передаваемое в параметре Shift типа TShiftState, а значение нажатой клавиши, передаваемое в параметре Key. Чтобы это событие работало не зависимо от того, какие и сколько компонентов на форуме, следует установить свойство TForm.KeyPreview в True.
Ну и последний вопрос — как обработать клик мыши в окне приложения, чтобы скрывать при этом меню. В этом нет ничего сложного и возможностей VCL здесь вполне достаточно. Нужно обработать свойство TForm.OnMouseActivate.
procedure TMyForm.FormMouseActivate(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y, HitTest: Integer; var MouseActivate: TMouseActivate); begin if MenuVisible then MenuVisible := False; end;

