Delphi __ Kompendium __ Roz5.pdf

(850 KB) Pobierz
Delphi :: Kompendium :: Roz...
Delphi :: Kompendium :: Rozdział 5 - 4programmers.net
http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_5
Logowanie | Rejestracja | Forum | Pomoc | Reklama | Szukaj
Strona główna :: Delphi :: Kompendium
Rozdział 5
Edytuj
Historia
Delphi
Artykuły
Kompendium
Gotowce
FAQ
.NET
Turbo Pascal
FAQ
PHP
FAQ
Java
FAQ
C/C++
Artykuły
FAQ
C#
Wprowadzenie
Assembler
FAQ
(X)HTML
CSS
JavaScript
Z pogranicza
Algorytmy
WIĘCEJ »
Komunikaty, bo to one będą tematem niniejszego rozdziału, nie są technologią zbyt często używaną przez
programistów Delphi, a to ze względu na możliwość zastąpienia ich przez zdarzenia. Jest to jednak trochę
bardziej zaawansowany element programowania, z którego nieraz możesz skorzystać w swoich aplikacjach.
Spis treści
1 Czym są komunikaty?
2 Rodzaje komunikatów
2.1 Komunikaty okienkowe
2.2 Komunikaty powiadamiające
2.3 Komunikaty definiowane przez użytkownika
3 Jak działają komunikaty?
4 Obsługa komunikatów
4.1 Przechwytywanie komunikatów
4.2 Struktura TMsg
4.3 Struktura TMessage
4.3.1 Funkcje LOWORD i HIWORD
5 Specyficzne struktury typów
6 Zdarzenie OnMessage
7 Wysyłanie komunikatów
7.1 Perform
7.1.1 Odczyt tekstu z kontrolki
7.2 Funkcje SendMessage i PostMessage
7.2.1 Pobieranie uchwytu okna
7.2.2 Różnice pomiędzy SendMessage i PostMessage
7.2.2.1 Przykład użycia
8 Komunikaty rozgłaszające
9 Deklarowanie własnych komunikatów
9.1 Obsługa komunikatu
10 Funkcje operujące na uchwytach
10.1 CloseWindow
10.2 EnableWidow
10.3 GetClientRect
10.4 GetDesktopWindow
10.5 GetForegroundWindow
10.6 GetParent
10.7 GetWindowText
10.8 IsIconic
10.9 IsWindow
10.10 IswindowVisible
10.11 MoveWindow
10.12 OpenIcon
10.13 SetForegroundWindow
10.14 SetWindowText
10.15 ShowWindow
11 'Zahaczanie' okien
11.1 Zakładanie globalnego hooka
11.2 Funkcja obsługująca hooka
12 Podsumowanie
Delphi
C/C++
Turbo Pascal
Assembler
PHP
Programy
Dokumentacja
Kursy
Komponenty
WIĘCEJ »
W tym rozdziale:
dowiesz się, czym są komunikaty Windows;
nauczysz się wysyłać oraz obsługiwać komunikaty;
nauczysz się obsługiwać kilka funkcji związanych z uchwytami;
Twoja aplikacja przechwyci wszystkie klawisze, jakie są naciskane w systemie.
Czym są komunikaty?
Słowo komunikat jest często stosowane w języku użytkowników komputerów. Tematem tego rozdziału nie
będą jednak - jak początkowo mogłoby się wydawać - komunikaty w postaci okienek systemu Windows.
Wszystko to, co dzieje się w systemie (mówimy tu na razie o systemie Windows) jest wynikiem komunikatów -
czy to naciśnięcie klawisza, czy ruch myszki lub otwarcie jakiegoś programu.
Jak zapewne zauważyłeś, w Delphi odzwierciedleniem komunikatów są zdarzenia - możemy na przykład
wykorzystać w naszym programie zdarzenie OnClose , które jest wynikiem zamknięcia okna. W rzeczywistości
jest to komunikat WM_CLOSE . Nie wszystko da się zrealizować za pomocą zdarzeń Delphi - dlatego właśnie
nieraz będziesz zmuszony skorzystać z komunikatów. Oto kolejny przykład: użytkownik klika lewym klawiszem
myszy w obszarze okna aplikacji. W tym momencie system wysyła do tego okna komunikat WM_LBUTTONDOWN ,
w którym zawarte są pewne informacje, takie jak np. współrzędne myszki. Zadaniem aplikacji jest
odpowiednie zareagowanie na ten komunikat.
Jeżeli tylko będziesz miał okazję, stosuj zdarzenia zamiast korzystać z komunikatów. Jest to
pewniejszy oraz szybszy sposób reagowania na określone sytuacje.
Rodzaje komunikatów
1 z 17
2009-03-14 15:32
77985786.010.png 77985786.011.png 77985786.012.png 77985786.013.png 77985786.001.png 77985786.002.png 77985786.003.png
Delphi :: Kompendium :: Rozdział 5 - 4programmers.net
http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_5
W rzeczywistości komunikaty są jedynie zwykłymi stałymi o określonych wartościach, które są jakby
identyfikatorem danego komunikatu. Komunikaty możliwe do wykorzystania w Delphi zdefiniowane są w
module Message.pas .
Copyright © 2000-2006 by Coyote Group 0.9.3-pre3
Czas generowania strony: 1.7169 sek. (zapytań SQL:
12)
Komunikaty okienkowe
Podstawowym typem komunikatów są tzw. komunikaty okienkowe, które posiadają przedrostek WM_ (ang.
Windows Message ). Ten typ komunikatów używany jest do komunikacji pomiędzy oknami - informują one np.
o naciśnięciu klawisza lub o przesunięciu kursora myszy w obszarze danego okna.
Najpopularniejsze (najczęściej stosowane) komunikaty przedstawione są w tabeli 5.1.
Nazwa Opis
WM_CREATE Komunikat jest wysyłany w momencie tworzenia okna
WM_DESTROY Komunikat jest wysyłany w momencie zamykania okna
WM_MOVE Komunikat stanowi informację dla aplikacji, że okno jest właśnie przemieszczane
WM_SIZE Komunikat stanowi informację dla aplikacji, że zmieniany jest właśnie rozmiar okna
WM_ACTIVATE Nastąpiła aktywacja okna
WM_CLOSE Komunikat jest wysyłany w momencie, gdy okno powinno zostać zamknięte
WM_QUIT Program zostaje zakończony
WM_CHAR Naciśnięcie klawisza. Odpowiednik zdarzenia OnKeyPress
WM_KEYDOWN Wciśnięcie klawisza. Odpowiednik zdarzenia OnKeyDown
WM_KEYUP Puszczenie klawisza. Odpowiednik zdarzenia OnKeyUp
WM_MOUSEMOVE Nastąpiło przesunięcie kursora myszy
WM_LBUTTONDOWN Lewy przycisk myszy został naciśnięty
WM_LBUTTONUP Lewy przycisk myszy został puszczony
Naturalnie jest to tylko część z możliwych do zastosowania komunikatów. W rzeczywistości są ich setki!
Wystarczy zajrzeć do modułu Message.pas. Nie musisz pamiętać ich wszystkich - wystarczy, że w razie
potrzeby zajrzysz do systemu pomocy Delphi lub do tego rozdziału.
Komunikaty powiadamiające
Każda kontrolka Windows posiada własne typy komunikatów, które przesyłane są z okna macierzystego
(formularz Delphi) do danej kontrolki. Komunikaty takie mogą zawierać informacje o tym, że nastąpiło
przesunięcie suwaka, naciśnięto przycisk albo np. została wyświetlona lista rozwijalna.
Jak już pisałem, każda kontrolka ma swój zestaw komunikatów - z każdą z tych kontrolek związany jest inny
przedrostek.
Tabela 5.2. Najczęściej używane komunikaty związane z kontrolkami Windows
Nazwa
Opis
Przycisk
BN_CLICKED Kliknięto przycisk.
BN_PAINT Obraz przycisku musi zostać odświeżony
BN_DISABLE Przycisk został zablokowany
BN_DOUBLECLICKED Nastąpiło podwójne kliknięcie w obszarze komponentu
BN_SETFOCUS Obiekt stał się aktywny
BN_KILLFOCUS Obiekt przestaje być aktywny
Lista wyboru (ListBox)
LBN_SELCHANGE Komunikat pojawia się w momencie, gdy użytkownik zamierza zmienić zawartość
zaznaczonej pozycji
LBN_SELCANCEL Komunikat pojawia się w momencie, gdy użytkownik rezygnuje z zaznaczenia pozycji
Kontrolka rozwijalna
CBN_SELCHANGE Komunikat pojawia się w momencie, gdy użytkownik zaznaczył pozycję i próbuje ją
zmienić
CBN_DBLCLK Nastąpiło podwójne kliknięcie w obszarze kontrolki
CBN_EDITCHANGE Występuje w przypadku, gdy użytkownik zmienił treść kontrolki
CBN_DROPDOWN Nastąpiło rozwinięcie listy rozwijalnej
CBN_CLOSEUP Lista rozwijalna została zamknięta
CBN_SELENDOK Komunikat występuje po wybraniu jakiegoś elementu z listy
Kontrolka edycyjna
EN_CHANGE Zmieniony został edytowany tekst
EN_UPDATE Komunikat zawiera informację o odświeżeniu tekstu
EN_ERRSPACE Nie można zadeklarować wystarczającej ilości pamięci!
EN_MAXTEXT Tekst wykracza poza kontrolkę edycyjną
EN_HSCROLL
Kliknięto poziomy pasek przewijania
EN_VSCROLL
Kliknięto pionowy pasek przewijania
2 z 17
2009-03-14 15:32
RSS | Forum | Pastebin |
Regulamin | Pomoc | Usuń
cookies | Prawa autorskie |
Kontakt | Reklama
77985786.004.png 77985786.005.png
Delphi :: Kompendium :: Rozdział 5 - 4programmers.net
http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_5
W opisach z tabeli 5.2 starałem się unikać powtarzania komunikatów. Dla każdej bowiem kontrolki występuje
np. komunikat _SETFOCUS . Wystarczy tylko zmienić prefiks (czyli dodać odpowiednie EN , CBN ), aby komunikat
był prawidłowo wykryty przez system.
W tabeli 5.2 zamieściłem jedynie komunikaty powiadamiające ( notification messages ), które zawierają
informacje o zdarzeniach związanych z kontrolkami. Istnieje wiele komunikatów służących do bezpośredniego
operowania na danych (np. do zamiany wpisanego tekstu itp.). Komunikaty te są używane podczas tworzenia
programów działających jako WinAPI, ale jeżeli jesteś ciekawy ich działania, zajrzyj do projektu ChildMsg.dpr
umieszczonego na płycie CD-ROM.
WinAPI to skrót od słów Windows Application Programming Interface. Jest to metoda
programowania polegająca na wykorzystywaniu jedynie narzędzi dostępnych w systemie -
bez korzystania z VCL. Jeżeli chcesz się dowiedzieć czegoś więcej na ten temat, zajrzyj do
rozdziału 12.
Często możesz spotkać się z określeniem Win32 . Oznacza ono po prostu system Windows
działający w środowisku 32-bitowym (czyli Windows 95 i nowsze wersje).
Komunikaty definiowane przez użytkownika
Nieraz niezbędna okaże się komunikacja pomiędzy dwiema aplikacjami. Można ją zrealizować w dość prosty i
przejrzysty sposób - za pomocą komunikatów! Nie musimy korzystać wyłącznie z tych komunikatów, które
zadeklarowane są już w module Message.pas - możliwe jest także deklarowanie własnych. W gruncie rzeczy
sprowadza się ono jedynie do zadeklarowania stałej. Istnieje tylko jeden warunek: wartości komunikatów nie
mogą się powtarzać, aby ze sobą nie kolidowały. Komunikatami definiowanymi przez użytkownika zajmiemy się
w dalszej części tego rozdziału.
Jak działają komunikaty?
Dla nas - programistów - istotną sprawą jest obsługa samego komunikatu. To, jak komunikat działa, może
wydać się już mniej interesujące. Mimo to warto dowiedzieć się czegoś o zasadach funkcjonowania takiego
systemu. Otóż pierwszym krokiem podejmowanym po wystąpieniu określonego zdarzenia (np. kliknięcia
myszą) jest zakwalifikowanie rodzaju zdarzenia przez system. Następnie system umieszcza komunikat w tzw.
kolejce komunikatów (system Windows przechowuje dla każdej aplikacji oddzielną kolejkę). Kolejnym krokiem
jest wykonywanie pętli, która przekazuje kolejno wszystkie komunikaty do konkretnego okna. Tutaj za
obsłużenie komunikatu odpowiedzialna jest sama aplikacja.
Obsługa komunikatów
Obsługa komunikatów jest o tyle trudniejsza od zdarzeń, że trzeba samodzielnie 'rozgryzać' wartości
parametrów. W zdarzeniach wszystko podane jest jak należy - w postaci parametrów i procedur zdarzeniowych.
Przechwytywanie komunikatów
Zadaniem Twojego pierwszego programu związanego z komunikatami będzie przechwycenie komunikatu
WM_LBUTTONDOWN , występującego w momencie naciśnięcia przez użytkownika lewego przycisku myszy!
W sekcji private klasy formularza dodaj następujący wiersz:
procedure WmLButtonDown ( var Msg : TMessage ) ; message WM_LBUTTONDOWN;
Jest to deklaracja procedury, która obsługiwać będzie zdarzenie. Zasada konstruowania procedur obsługujących
komunikaty polega na dodaniu na końcu deklaracji słowa kluczowego message . Po słowie tym należy wpisać
nazwę komunikatu - w naszym przypadku WM_LBUTTONDOWN .
Przyjęło się specyficzne nazewnictwo procedur obsługujących komunikaty, które polega na
nadawaniu procedurze takiej samej nazwy jak nazwa komunikatu, tyle że bez znaku
podkreślenia (_).
Nie przejmuj się na razie parametrem Msg powyższej procedury - omówię go nieco później.
Definicja procedury WmLButtonDown powinna zatem wyglądać tak:
procedure TMainForm. WmLButtonDown ( var Msg: TMessage ) ;
begin
lblInfo. Caption := 'Użytkownik wcisnął lewy klawisz myszy!' ;
end ;
Możesz już uruchomić program. Po kliknięciu lewym przyciskiem myszy w obszarze formularza wykonana
zostanie procedura WmLButtonDown , a co za tym idzie, wyświetlona zostanie także stosowna informacja w
etykiecie ( TLabel ). Cały kod źródłowy modułu znajduje się w listingu 5.1.
Zwróć uwagę, że w definicji procedury nie stosujemy klauzuli message - tak, jak ma to
miejsce w deklaracji.
Listing 5.1. Kod modułu przechwytującego komunikat
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TMainForm = class ( TForm )
lblInfo: TLabel;
private
procedure WmLButtonDown ( var Msg : TMessage ) ; message WM_LBUTTONDOWN;
public
3 z 17
2009-03-14 15:32
77985786.006.png
Delphi :: Kompendium :: Rozdział 5 - 4programmers.net
http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_5
{ Public declarations }
end ;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
{ TMainForm }
procedure TMainForm. WmLButtonDown ( var Msg: TMessage ) ;
begin
lblInfo. Caption := 'Użytkownik wcisnął lewy klawisz myszy!' ;
end ;
end .
Struktura TMsg
W poprzednim przykładzie procedura posiadała parametr Msg , który był typu TMessage . Ta struktura
identyfikuje właśnie komunikat i jego zawartość (parametry). VCL (typ TMessage należy do bibliotek VCL)
zwalnia nas w większej części od programowania bardziej zaawansowanych aspektów związanych z
komunikatami, jak pobieranie komunikatu z pętli itp. W środowisku WinAPI obowiązuje inny rekord, który jest
pierwowzorem dla TMessage :
type
TMsg = packed record
hwnd: HWND;
message : UINT;
wParam: WPARAM;
lParam: LPARAM;
time : DWORD;
pt: TPoint ;
end ;
Rekord ten zadeklarowany jest w module Windows.pas , i zawiera informacje dotyczące samego komunikatu.
hwnd - uchwyt okna, do którego komunikat jest kierowany.
message - identyfikator komunikatu.
wParam - 32-bitowa liczba, określająca dodatkowe parametry związane z komunikatem.
lParam - kolejne 32-bitowe pole, określające dodatkowy parametr przekazywany wraz z komunikatem.
time - czas wysłania komunikatu.
pt - współrzędne kursora myszy.
Przy okazji omawiania tej struktury należy się parę słów objaśnienia. Pierwszym parametrem jest tzw. uchwyt
okna. Jest to 32-bitowa liczba, określającą dane okno w systemie Windows. Każde okno posiada swój unikalny
numer - dzięki temu możemy 'porozumiewać' się z danym programem np. właśnie dzięki komunikatom.
Komunikat może zawierać w sobie pewne dane, jak np. współrzędne kursora myszy czy informacja określająca,
jaki klawisz jest w tej chwili dodatkowo wciśnięty. Jednak są też komunikaty, które nie posiadają żadnych
dodatkowych parametrów.
Struktura TMessage
W Delphi nie będziemy zajmowali się strukturą TMsg , lecz skorzystamy z dobrodziejstw VCL i rekordu TMessage ,
który zadeklarowany jest w module Message.pas .
type
TMessage = packed record
Msg: Cardinal ;
case Integer of
0 : (
WParam: Longint ;
LParam: Longint ;
Result : Longint ) ;
1 : (
WParamLo: Word ;
WParamHi: Word ;
LParamLo: Word ;
LParamHi: Word ;
ResultLo: Word ;
ResultHi: Word ) ;
end ;
Na pozór struktura TMessage przedstawia się bardzo skomplikowanie, lecz nie zawiera tylu elementów, co TMsg .
Mamy tu jedynie informację przekazywaną w komunikacie, zawierającą parametry lParam i wParam .
Rekord TMessage zawiera dodatkowo parametr Result . Czasami system oczekuje od komunikatu uzyskania
informacji zwrotnej o jego przebiegu. Wówczas mamy możliwość nadania określonej wartości polu Result :
Msg. Result := 1 ;
Pozostało jeszcze objaśnienie kwestii specyficznej budowy rekordu, a mianowicie dodanie instrukcji case. Dla
pola LParam zadeklarowane są jeszcze dwie wartości: LParamLo i LParamHi ; tak samo ma się sprawa z
pozostałymi parametrami - WParam i Result . Aby lepiej to zrozumieć, polecam wykonanie pewnego ćwiczenia.
Podczas odbierania komunikatu WM_LBUTTONDOWN parametr lParam zawiera współrzędne kursora myszy, które są
jakby 'zakodowane' w postaci 32-bitowej liczby. Sam możesz się o tym przekonać:
procedure TMainForm. WmLButtonDown ( var Msg: TMessage ) ;
4 z 17
2009-03-14 15:32
77985786.007.png 77985786.008.png
Delphi :: Kompendium :: Rozdział 5 - 4programmers.net
http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_5
begin
lblInfo. Caption := 'Współrzędne myszy: ' + IntToStr ( Msg. LParam ) ;
end ;
W takim wypadku podczas pobierania komunikatu w etykiecie wyświetlona zostanie jakaś 'kosmiczna' liczba -
np. 2490472. Żeby uzyskać z tej liczby rzeczywiste położenie kursora, należy skorzystać z funkcji LOWORD i
HIWORD .
Funkcje LOWORD i HIWORD
Funkcje LOWORD i ksłużą do uzyskiwania tzw. wyższego oraz niższego wyrazu liczby 32-bitowej. Za pomocą tych
funkcji możemy 'odkodować' parametr, który przykładowo określa współrzędne kursora myszy:
LOWORD ( 2490472 ) ; { da liczbę 104 }
HIWORD ( 2490472 ) ; { da liczbę 38 }
W powyższy sposób uzyskujemy rzeczywiste położenie kursora myszy - 104 (w poziomie) i 38 (w pionie).
Struktura TMessage zwalnia nas od takich zadań dzięki parametrom LParamLo i LParamHi , które zawierają już
'odkodowane' wartości. Listing 5.2 przedstawia program z listingu 5.1 już po dokonaniu modyfikacji, a sam
program w trakcie działania, przedstawiony został na rysunku 5.1
Listing 5.2. Uzyskiwanie współrzędnych kursora myszy z komunikatu
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TMainForm = class ( TForm )
lblInfo: TLabel;
private
procedure WmLButtonDown ( var Msg : TMessage ) ; message WM_LBUTTONDOWN;
public
{ Public declarations }
end ;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
{ TMainForm }
procedure TMainForm. WmLButtonDown ( var Msg: TMessage ) ;
begin
lblInfo. Caption := 'Współrzędne myszy: ' + IntToStr ( Msg. LParamLo ) + ' i ' +
IntToStr ( Msg. LParamHi ) ;
end ;
end .
Rysunek 5.1. Program w trakcie działania
Specyficzne struktury typów
Nie jest konieczne mozolne rozszyfrowanie parametrów lParam i wParam za każdym razem. Delphi udostępnia
specyficzne dla niektórych komunikatów struktury danych, dzięki którym możemy uzyskać informację na temat
parametrów. Przykładowo zamiast używać - jak w poprzednim przykładzie - rekordu TMessage , wystarczyło
skorzystać z TWMMouse :
type
TWMMouse = packed record
Msg: Cardinal ;
Keys: Longint ;
case Integer of
0 : (
XPos: Smallint ;
YPos: Smallint ) ;
1 : (
Pos : TSmallPoint ;
Result : Longint ) ;
end ;
Osobny rekord jest zadeklarowany praktycznie dla większości standardowych komunikatów Windows. Nie
musisz pamiętać typów właściwych dla nich wszystkich - wystarczy znać nazwę komunikatu, a nazwę struktury
można utworzyć, dodając na samym początku literę T i usuwając znak _. Przykładowo dla komunikatu
WM_LBUTTONDOWN odpowiednią strukturą będzie TWmLButtonDown .
Nic nie stoi oczywiście na przeszkodzie, aby korzystać ze struktury TMessage , która pasuje do każdego rodzaju
komunikatu.
Zdarzenie OnMessage
5 z 17
2009-03-14 15:32
77985786.009.png
Zgłoś jeśli naruszono regulamin