Zprávy
Objekty mezi sebou komunikují posíláním zpráv (message). Zpráva se typicky skládá z
POZOR !
Povšimněte si zásadního rozdílu oproti klasickému programování: vlastní provedení operace zde není zavoláno přímo, ale nepřímo tím, že se vyšle příslušná zpráva. Vždy se tedy nejprve hledá příjemce zprávy, tzn. dohledává se, která metoda se aplikuje (díky dědičnosti to může být i velmi složitý proces). Teprve na příjemci zprávy záleží, jak bude zprávu interpretovat.
Zprávy ve Windows
Je třeba vědět, že za realizaci zpráv, jejich předávání a práci s nimi je zodpovědný operační systém, v tomto případě Windows. Zprávy jsou také jedním ze stěžejních (a také nejvíce nespolehlivých) částí Windows. Protože ale práce se zprávami prostřednictvím služeb Windows je složitá a má četná úskalí, tvů
rci Delphi zapouzdřili windowsovský systém zpráv do objektů v Delphi, se kterými se pracuje jednodušeji. V Delphi se jim říká události.Popišme si nejprve zprávy tak, jak je realizují windows. Ve windows je zpráva record, který má následující části:
Pro vysvětlení práce se zprávami Windows si musíme vysvětlit 3 základní pojmy:
Obsluha windowsovských zpráv
Obsluha zpráv v Delphi je daleko jednodušší než ve Windows: místo jedné procedury
window procedure, která obsluhuje všechny zprávy, má v Delphi každá zpráva svou vlastní proceduru. Aby procedura mohla být obsluhou zprávy, musí splňovat 3 podmínky:Příklad:
ve Form1:
procedure Prekresli (var Msg: TwmPaint); message wm_Paint;
za begin:
procedure TForm1.Prekresli (var Msg: TwmPaint);
begin
MessageBeep(0);
inherited;
end;
Pozor, obsluha zpráv není bez zá
vazků! Kdybychon v proceduře Prekresli vynechali inherited, nezavolala by se procedura pro obsluhu zprávy wm_Paint z rodiče, tzn. z formuláře TForm. To by mělo fatální důsledky: Windows by nedostaly požadovanou návratovou hodnotu, a proto by aplikace zamrzla (nebo celý počítač).Posílání windowsovských zpráv
V Delphi existují 3 způsoby, jak lze poslat windowsovskou zprávu:
Uživatelem
definované zprávyUvnitř jedné aplikace není problém poslat zprávu; číslo zprávy si libovolně vybereme z dovoleného rozmezí wm_User+100 až $7FFF (což je rozsah, který Windows rezervují pro uživatelem definované zprávy).
Pokud potřebujeme posílat zprávy mezi aplikacemi (na jednom počítači!), musí se číslo zprávy zaregistrovat ve Windows. V každé aplikaci, mezi kterými si chceme posílat zprávy, zavoláme proceduru RegisterWindowsMessage s parametrem - libovolným (ale u všech aplikací stejným) řetězcem. Window
s zprávě přidělí číslo v rozsahu $C000 až $FFFF.Hook
Zprávy v Delphi a události
Delphi zapouzdřují zprávy do recordu Tmessage:
Tmessage = record
Msg: word;
case integer of
0: (
wParam: word;
lParam: LongInt;
Result: LongInt);
1: (
wParamLo, wParamHi: byte;
lParamLo, lParamHi: word;
ResultLo, ResultHi: word);
end;
Povšimněte si, že Tmessage má méně údajů, než bylo v původní TMsg; to proto, že Delphi některé údaje zpracovávají interně a nemusíme se o ně starat. Do Result se napíše výsledek v případě, že Windows požadují návratovou hodnotu - o doručení se už postarají Delphi.
Vedle typu TMessage definují Delphi ještě specifické typy zpráv, které obsahují úplnější specifickou informaci. Typicky TwmMouse obsahuje Msg:TmsgParam, Keys:word, Xpos a Ypos: i
nteger a Result:longint.Obsluha zpráv v Delphi
V Delphi má každý objekt proceduru WndProc, což je vlastně
window procedura. Ta se postará o to, aby zpráva byla rozeslána do oken, kterých se týká. Uvnitř okna nastane obsluha zprávy a poté, co je zpráva obsloužena, tak se označí jako vyřízená. Všechny zprávy, které nejsou v objektech obslouženy, se sbírají a přivedou se do procedury DefaultHandler.O tyto podrobnosti se běžný programátor v Delphi nemusí nijak starat. Pro něj obsluha událostí začíná a končí zjištěním, že Delphi zprávu doručí do správného objektu a uvnitř tohoto objektu že zpráva vyvolá obsluhu zprávy.
Události
Zprávy, které jsou zapouzdřeny a zpracovány systémem Delphi a které jsou doručeny do správných objektů, se nazývají
události, anglicky event. Protože události jsou opracované zprávy, nikoho asi nepřekvapí, že každé zprávě Windows odpovídá jedna událost v Delphi:
OnActivate |
wm_Activate |
OnClick |
wm_xButtonClick |
OnCreate |
wm_Create |
OnDblClick |
wm_xButtonDblClick |
OnKeyDown |
wm_KeyDown |
onKeyUp |
wm_KeyUp |
OnKeyPress |
wm_Char |
OnPaint |
wm_Paint |
OnResize |
wm_Size |
OnTimer |
wm_Timer |
Obsluha událostí - handler
Smysl a funkci událostí jsme popsali v předcházejícím odstavci. Nyní si ukážeme, jak jsou události v Delphi implementovány.
Některé handlery jsou v Delphi předdefinovány, např. handler pro ošetření události Click. Pokud chceme či potřebujeme standardní chování modifikovat, můžeme. Protože handler je metoda jako každá jiná, můžeme ji ve zděděných třídách zmodifikovat - třeba
override, přeřídit. Je třeba dodržet 2 podmínky, bez kterých by obsluha událostí byla nespolehlivá:
Zprávy klávesnice a KeyPreview
Při stisknutí klávesy vznikne událost OnKeyDown, při jejím uvolnění OnKeyUp. Pokud dojde ke stisknutí a uvolnění klávesy, vygeneruje se událost OnKeyPress. Bohužel, OnKeyPress funguje jen na "normální" klávesy, jako jsou písmena, tlačítka apod. Příklad je
zde.Kdybychom potřebovali zpracovat stisknutí některé řídicí klávesy, jako je Home, End, šipky a podobně, museli bychom napsat
handler pro událost OnKeyDown.Někdy je velmi omezující, že událost z klávesnice je směrována přímo k objektu, kterého se týká; kdybychom například v předcházejících příkladech nenastavili u objektu Memo1 vlastnost Enabled:=False, tak bychom se chování OnKeyDown nedočkali. Důvod je prostý - OnKeyDown jsme nastavili ve Form1, ale událost z klávesnice se tam vůbec nedostane, protože Delphi ji oděšlou přímo na Memo1, kam pa
tří. Chceme-li se tomu vyhnout, použijeme KeyPreview.KeyPreview ve formuláři
nastavíme na True. Tím se zajistí, že než událost dojde k objektu pro který je určena, tak se ještě předtím zpracuje ve Form.OnKeyPress. Na jiné události než na ty, na které reaguje OnKeyPress, tato vlastnost nefunguje.Ošetření výjimek a chyb
Vygenerování výjimky