Zdarzenia i komunikaty
3.08.1999
  • Odpowiadanie na komunikaty wysyłane do aplikacji.

       Jest kilka sposobów na przechwytywanie komunikatów Windows przekazywanych do Twoich programów. Możesz nadpisać wirtualną funkcję WndProc głównej formy, możesz stworzyć mapę komunikatów, możesz wreszcie stworzyć handler OnMessage dla Twojej aplikacji.



      Nadpisywanie WndProc: Wszyscy potomkowie TControl, włącznie z TForm, zawierają funkcję WndProc. Jest ona wirtualna, co oznacza, że możesz dostosować (nadpisać) ją do przechwytywania komunikatów. Argumentem tej funkcji jest struktura TMessage, przekazywana przez referencję, zawiera on identyfikację komunikatu i wartości WPARAM oraz LPARAM.

      Krok 1: Dodaj deklarację WndProc do nagłówka formy.
private:	    // User declarations
   void __fastcall WndProc(Messages::TMessage &Message);
		
      Krok 2: Wpisz kod funkcji. Dziedziczona funkcja WndProc powinna wywołać funkcję bazową TForm::WndProc, dla wszystkich komunikatów, które Cię nie interesują. Ta funkcja zapobiega uruchomieniu wygaszacza ekranu.
void __fastcall TForm1::WndProc(Messages::TMessage &Message)
 {
 if(  (Message.Msg    == WM_SYSCOMMAND) &&
         (Message.WParam == SC_SCREENSAVE)    )
  {
   Application->MessageBox("Nie chcemy wygaszcza!", "SCR No", MB_OK);
   Message.Result = true;
  }
 else
     TForm::WndProc(Message);
 }


      Tworzenie mapy komunikatu (Message Map): Mapy komunikatów pozwalają na pisanie funkcji, które otrzymują jedynie specyficzne komunikaty, a nie wszystkie, tak jak WndProc. Mapy komunikatów używają różnych struktur znajdujących się w \include\messages.hpp. Na przykład, mapa komunikatu WM_GETMINMAXINFO użyłaby struktury TWMGetMinMaxInfo. Te struktury są całkiem przyjemne, ponieważ wartości WPARAM i LPARAM zostały zdekodowane do bardziej zrozumiałych członków struktury.       Krok 1: Dodaj deklarację funkcji i mapę komunikatu do nagłówka.
private:     // User declarations
        void __fastcall WMSysCommand(TWMSysCommand &Message);
    public:      // User declarations
        __fastcall TForm1(TComponent* Owner);

    BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(WM_SYSCOMMAND,TWMSysCommand,WMSysCommand)
    END_MESSAGE_MAP(TForm)
      Krok 2: Wpisz kod funkcji. Jeżeli chcesz przekazać komunikat do klasy bazowej użyj funkcji Dispatch klasy bazowej.
void __fastcall TForm1::WMSysCommand(TWMSysCommand &Message)
 {
if(Message.CmdType == SC_SCREENSAVE)
  {
   Application->MessageBox("Nie chcemy wygaszcza!","SCR No",MB_OK);
   Message.Result = true;
  }
 else
     TForm::Dispatch(&Message);
    }
Uwaga: Upewnij się, że wywołujesz fukcję Dispatch należącą do klasy bazowej, a nie do klasy dziedziczonej. Mapy komunikatów są wyzwalane z funkcji Dispatch dziedziczonej klasy. Wywołanie tejże właśnie funkcji Dispatch spowoduje wykonywanie nieskończonej pętli.



      Tworzenie handlera OnMessage: Handler ten pozwala na obsługę komunikatu zanim zostanie on przetworzony przez aplikację.

      Krok 1: Dodaj deklarację funkcji OnMessage.
private:     // User declarations
 void __fastcall AppOnMessage(TMsg &Message,
                                   bool &Handled);
      Krok 2: Wpisz kod funkcji. Ustaw flagę Handled dla komunikatów, które obsługujesz.
void __fastcall TForm1::AppOnMessage(TMsg &Msg, bool &Handled)
 {
   if(  (Msg.message == WM_SYSCOMMAND) &&
        (Msg.wParam  == SC_SCREENSAVE)   )
  {
   Application->MessageBox("Nie chcemy wygaszcza!","SCR No",MB_OK);
   Handled = true;
   }
    else
        Handled = false;
    }
      Krok 3: W konstruktorze głównej formy przypisz funkcję AppOnMessage do zdarzenia OnMessage globalnego obiektu Application.
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        Application->OnMessage = AppOnMessage;
    }


Uwagi: Jak więc zdecydujesz, którego sposobu użyć? Nadpisanie metody WndProc jest dobre w przypadku gdy obsługujesz wiele komunikatów. Mapy komunikatów pozwalają skoncentrować się na pojedynczym komunikacie, a kod jest łatwy do odczytania. Wykorzystując handler OnMessage będziesz mógł przechwycić komunikat zanim przetworzy go program. Minusem jest to, że komunikaty wysłane przez SendMessage albo Perform nie są przekazywane do handlera OnMessage. Na dodatek handler ten może doprowadzić do zawieszenia systemu.

      Podsumowując, używaj raczej WndProc albo map komunikatów. Zaś handlera OnMessage jedynie w przypadkach, kiedy tylko on jest w stanie przechwycić komunikat. Jeżeli zachodzi konieczność użyj "subclassingu" - poprzez właściwość WindowProc klasy dziedziczonej z TControl.