Изменение системного меню

WinHack

Администратор
23 Фев 2015
2,664
1,913
bsfo.ru
С помощью API Windows мы можем настраивать системное меню формы. Так, например, мы можем добавить свой пункт меню или удалить уже имеющийся, изменить пункт меню по умолчанию и даже добавить растровое изображение.

app-change-sysmenu.png

Для того, чтобы получить доступ к системному меню, нужно использовать функцию GetSystemMenu API Windows. Также далее мы будем использовать AppendMenu, SetMenuItemInfo, а также структуру TMenuItemInfo. После добавления своего пункта меню, нужно добавить ловушку на сообщение WM_SYSCOMMAND, чтобы узнать, когда будет выбран наш пункт меню.

Добавление пункта меню
[hr][/hr]

Следующий код демонстрирует исользование функции AppendMenu для добавления нового пункта в системное меню формы. Для начала, нам нужно определить новую константу SC_MyMenuItem, которая будет идентифицировать наш новый пункт меню.

Код:
const
    SC_MyMenuItem = WM_USER + 1;

{ ... }

procedure TForm1.btnAddItemClick(Sender: TObject);
const
  sItemCaption = 'Новый пункт меню';
var
  sysMenu: HMenu;
begin
  { Получаем идентификатор системного меню }
  sysMenu:= GetSystemMenu(Handle, false);
  { Добавляем разделитель меню }
  AppendMenu(sysMenu, MF_SEPARATOR, 0, '');
  { Добавляем наше меню }
  AppendMenu(sysMenu, MF_STRING, SC_MyMenuItem, sItemCaption);
end;
После добавления пункта меню, мы должны отловить сообщение WM_SYSCOMMAND для обработки щелчка.

Код:
private
  { Private declarations }
  procedure WMSysCommand(
      var Msg: TWMSysCommand); message WM_SYSCOMMAND;

{ ... }

procedure TForm1.WMSysCommand(var Msg: TWMSysCommand);
begin
  if Msg.CmdType = SC_MyMenuItem then
    { Здесь идет код для пункта меню }
    ShowMessage('Щелкнули по новому пункту меню!')
  else
    inherited;
end;
Примечание: при сворачивании приложения, значок представляет собой приложение, а не форму. Поэтому, чтобы измененное меню работало и в свернутом виде, нужно использовать Application.Handle, а не просто Handle, когда будете добавлять свой пункт меню.

Удаление системного пункта меню
[hr][/hr]

При удалении пункта системного меню, мы также удаляем возможность выполнения его из системного меню формы. При помощи DeleteMenu давайте удалим пункт Переместить.

Обратите внимание: после удаления этого пункта меню, мы не сможем больше перемещать форму. Это не самый лучший способ удаления меню.

Код:
procedure TForm1.btnDeleteItemClick(Sender: TObject);
const
  mnuCommand = SC_MOVE;
var
  sysMenu: HMenu;
begin
  sysMenu:= GetSystemMenu(Handle, false);
  DeleteMenu(sysMenu, mnuCommand, MF_BYCOMMAND);
end;

Изменение заголовка пункта меню
[hr][/hr]

Чтобы изменить заголовок пункта системного меню, мы должны вызвать функцию SetMenuItemInfo и отправить ей структуру TMenuItemInfo, которая содержит информацию о пункте меню.

Давайте изменим заголовок пункта меню Закрыть.

Код:
procedure TForm1.btnChangeItemCaptionClick(Sender: TObject);
const
  sCaption = 'Закрыть наше окно';
var
  sysMenu: HMenu;
  menuItemInfo: TMenuItemInfo;
begin
  sysMenu:= GetSystemMenu(Handle, false);

  FillChar(MenuItemInfo, SizeOf(TMenuItemInfo), #0);
  with MenuItemInfo do
  begin
    cbSize:= SizeOf(TMenuItemInfo);
    fMask:= MIIM_TYPE or MIIM_ID or MIIM_STATE;
    fType:= MFT_STRING;

    wID:= SC_CLOSE;
    dwTypeData:= sCaption;
    cch:= Length(sCaption);
  end;
  SetMenuItemInfo(sysMenu, SC_CLOSE, false, MenuItemInfo);
end;

Добавление изображения в пункт меню
[hr][/hr]

Для этого выберите изображение в формате bmp и поместите его в папку с проектом. Я взял изображение, которое идет вместе с Delphi и находится в папке Program Files\Common Files\Borland Shared\Images\Icons и называется CHEM16.BMP.



Запишите следующий код:

Код:
private
  { Private declarations }
  myBmp: TBitmap;

 { ... }

procedure TForm1.FormCreate(Sender: TObject);
begin
  myBmp:= TBitmap.Create;
  myBmp.LoadFromFile('CHEM16.BMP');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  myBmp.Free;
end;

procedure TForm1.btnChangeItemCaptionClick(Sender: TObject);
const
  sCaption = 'Закрыть наше окно';
var
  sysMenu: HMenu;
  menuItemInfo: TMenuItemInfo;
begin
  sysMenu:= GetSystemMenu(Handle, false);

  FillChar(menuItemInfo, SizeOf(TMenuItemInfo), #0);
  with menuItemInfo do
  begin
    cbSize:= SizeOf(TMenuItemInfo);
    fMask:= MIIM_TYPE or MIIM_ID or MIIM_STATE;
    fType:= MFT_STRING;

    wID:= SC_CLOSE;
    dwTypeData:= sCaption;
    cch:= Length(sCaption);
  end;
  SetMenuItemInfo(sysMenu, SC_CLOSE, false, menuItemInfo);
end;
Вот и все по работе с системным меню формы нашего приложения.