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

Тема в разделе "Delphi", создана пользователем WinHack, 23 ноя 2016.

  1. WinHack
    С помощью API Windows мы можем настраивать системное меню формы. Так, например, мы можем добавить свой пункт меню или удалить уже имеющийся, изменить пункт меню по умолчанию и даже добавить растровое изображение.

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

    Добавление пункта меню


    Следующий код демонстрирует исользование функции 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, когда будете добавлять свой пункт меню.

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


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

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

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

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


    Чтобы изменить заголовок пункта системного меню, мы должны вызвать функцию 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;

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


    Для этого выберите изображение в формате 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;
    Вот и все по работе с системным меню формы нашего приложения.