Главная > Статьи > Автоматически скрывающееся меню

Автоматически скрывающееся меню

В дизайне современных приложений меню занимает уже далеко не главное место, уступив первенство панелям инструментов. Такие тенденции наблюдаются например в Internet Explorer 7 и Windows Vista Explorer (Проводник).

Windows Vista Explorer Internet Explorer 7 under Windows Vista

В то же время меню у этих приложений есть, его можно показать, нажав клавишу 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;

Статьи

  1. Пока что нет комментариев.
  1. Пока что нет уведомлений.