TForm i TApplication
25.08.1999
  • Dostosowywanie systemowego menu formy.

       Jest to raczej niezbyt częsta praktyka, nieliczne programy modyfikują systemowe menu formy (np. okienko MS-DOS). Jeśli zamierzasz jednak wykorzystać tą możliwość, to tu masz opis:

       Aby uzyskać uchwyt do systemowego menu użyjesz funkcji API GetSystemMenu. Potem dodasz albo odejmiesz określone pozycje menu. Przykładowy kod modyfikujący menu systemowe:

#define IDS_CUSTOMID 0x1000        // ID menu

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
  const AnsiString MenuString = "Własne Menu";
  MENUITEMINFO info = {  sizeof(MENUITEMINFO),
          MIIM_TYPE | MIIM_STATE | MIIM_ID ,
          MFT_STRING,                 // typ menu to string
          MFS_ENABLED,                // pozycja menu włączona
          IDS_CUSTOMID,               // id pozycji menu
          NULL,                       // bez pod-menu
          NULL,                       // bez bitmapy "check"
          NULL,                       // bez bitmapy "uncheck"
          0,                          // bez danych pozycji
          MenuString.c_str(),         // string pozycji
          0};                         // ostatnia pozycja nie używana


  // uchwyt systemowego menu
  HMENU SysMenu = GetSystemMenu(Handle, FALSE);

  // Wstawia nową pozycję za pozycją Zamknij
  InsertMenuItem (SysMenu, SC_CLOSE, TRUE, &info);
}
       Teraz musisz dodać kod odpowiedzialny za obsługę nowych pozycji menu. Dokonasz tego za pomocą mapy komunikatu:

//-------------------------------------------------------------
// W nagłówku
class TForm1 : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
  void __fastcall WMSysCommand(TWMSysCommand &Msg);
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);

BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER(WM_SYSCOMMAND,TWMSysCommand,WMSysCommand)
END_MESSAGE_MAP(TForm)
};
//-------------------------------------------------------------
//
// W źródle
void __fastcall TForm1::WMSysCommand(TWMSysCommand &Msg)
{
  if( Msg.CmdType == IDS_CUSTOMID)
  {
    Width -=5;
    Height -=5;
    Msg.Result = true;
  }
  else
    TForm::Dispatch(&Msg);
}
Uwaga: Kiedy dodajesz nowe pozycje do menu zwróć uwagę na to, by ID było mniejsze niż 0xF000. Unikniesz konfliktów z istniejącymi pozycjami menu.

Uwaga: Po uzyskaniu uchwytu do menu, możesz go używać we wszystkich funkcjach API dotyczących menu, to jest: kasowanie pozycji, podświetlanie, dodawanie bitmapy, itp.

Uwaga: Po wybraniu pozycji menu formy zostaje wysłany komunikat WM_COMMAND, natomiast po wybraniu pozycji menu systemowego wysyłany jest komunikat WM_SYSCOMMAND.

Uwaga: Parametr wParam komunikatu WM_SYSCOMMAND zawiera ID klikniętej pozycji. Struktura TWMSysCommand mapuje wParam do struktury CmdType.

Uwaga: Menu systemowe zawiera domyślne pozycje (Minimalizuj, Zamknij...) Te komendy mają wbudowane ID (SC_MINIMIZE, SC_CLOSE). Będziesz musiał przekazać komunikaty dla tych pozycji do domyślnego handlera. Inaczej pozycje te nie będą działały. Jeżeli chcesz przechwycić naciśnięcie konkretnej pozycji systemowej możesz to zrobić tak:

void __fastcall TForm1::WMSysCommand(TWMSysCommand &Msg)
{
  if( Msg.CmdType == IDS_CUSTOMID)
  {
    Width -=5;
    Height -=5;
    Msg.Result = true;
  }
  else if ( (Msg.CmdType & 0xFFF0) == SC_CLOSE)
    Application->MessageBox("Nie chcę zamykać!","test",MB_OK);
  else
    TForm::Dispatch(&Msg);
}
Uwaga: Powyższy sposób spowoduje również zablokowanie przycisku zamykającego okno - wtedy również jest wysyłany komunikat WM_SYSCOMMAND.

Uwaga: Menu które pokaże się przy kliknięciu prawym przyciskiem na ikonę zminimalizowanego programu na pasku zadań będzie inne od systemowego menu formy.