• Nie Znaleziono Wyników

Procedura zdarzeniowa to najważniejszy, ale nie jedyny składnik klasy okna - oprócz niego występuje jeszcze kilka innych. Wszystkie one są polami specjalnej struktury WNDCLASSEX; definicja tego typu wygląda zaś tak106:

struct WNDCLASSEX {

UINT cbSize;

HINSTANCE hInstance;

LPCTSTR lpszClassName;

WNDPROC lpfnWndProc;

UINT style;

HICON hIcon;

HICON hIconSm;

HCURSOR hCursor;

HBRUSH hbrBackground;

LPCTSTR lpszMenuName;

int cbClsExtra;

int cbWndExtra;

};

Mamy w nim aż tuzin różnych pól, zadeklarowanych ku radości każdego kodera ;D Ich znaczenie przedstawia nam poniższa tabelka:

typ nazwa opis

UINT cbSize

W tym polu należy wpisać rozmiar struktury WNDCLASSEX. Wymóg ten może się wydawać dziwaczny, niemniej jest prawdziwy i trzeba mu się podporządkować.

A zatem pierwszym krokiem w pracy ze strukturą WNDCLASSEX powinno być ustawienie pola cbSize na sizeof(WNDCLASSEX). Podobnie rzecz ma się z innymi

strukturami w WinAPI, które posiadają te pole.

Jeżeli struktura w Windows API posiada pole cbSize, należy koniecznie ustawić je na wartość równą rozmiarowi owej struktury, jeszcze zanim przekażemy ją jakiejkolwiek

funkcji WinAPI.

HINSTANCE hInstance

Tutaj podajemy uchwyt do instancji programu. Tak, jest to ten sam uchwyt, jaki dostajemy w pierwszym parametrze funkcji WinMain(). Musimy zatem oddać

Windowsowi, co od Windowsa pochodzi ;)

LPCTSTR lpszClassName

To pole jest przeznaczone dla nazwy klasy okna. Nazwa ta powinna być unikalna w skali procesu, gdyż w przeciwnym wypadku rejestracja okna nie powiedzie się.

Dobrym pomysłem jest więc wpisywanie jakiejś kombinacji nazwy pisanego programu i grupy koderskiej, której jest

on dziełem.

Nazwę tę dobrze jest też zachować w odrębnej zmiennej lub stałej, bo będzie nam potrzebna przy tworzeniu okna.

106 Naprawdę wygląda ona inaczej, jako że składnia struct { ... }; jest niepoprawana w C. Definicja podana tutaj jest jednak w pełni równoważna, jeśli używamy języka C++ (a używamy :)). Dlatego też kolejne definicje struktur będą podane właśnie w ten, C++’owy sposób.

typ nazwa opis WNDPROC lpfnWndProc

Oto najważniejsze pole tej struktury: wskaźnik na procedurę zdarzeniową. Musi być ona zadeklarowana zgodnie z prototypem podanym w poprzednim akapicie,

jako funkcja globalna lub statyczna metoda klasy.

UINT style

Jest to kombinacja flag bitowych określających pewne szczególne opcje klasy. Najczęściej zostawiamy to pole

wyzerowane lub ustawiamy je na CS_HREDRAW | CS_VREDRAW.

Część dostępnych flag zaprezentujemy w następnym rozdziale.

Wszystkie są wyliczone i opisane w MSDN.

HICON hIcon

W tym polu określamy ikonę, jaką będą opatrzone okna przynależne rejestrowanej klasie. Dokładniej mówiąc, podajemy tu uchwyt do ikony o wymiarach co najmniej

32×32 pikseli. O tym, skąd wziąć taką ikonę, dowiesz się za moment.

HICON hIconSm

To pole jest uchwytem do małej ikony okna, pojawiającej się w jego lewym górnym rogu. Spokojnie

możemy tu podać tę samą wartość, co w hIcon (także NULL, wtedy zostanie użyta właśnie ikona z hIcon).

HCURSOR hCursor

Kolejne pole z gatunku wystroju graficznego okna - tym razem jest to uchwyt do kursora. Strzałka myszy przyjmie jego wygląd, gdy będzie przelatywać ponad oknem należącym do definiowanej klasy. O uzyskiwaniu

uchwytu do kursora też sobie zaraz powiemy.

Wartość NULL w tym polu oznacza natomiast całkowity brak kursora myszy.

HBRUSH hbrBackground

W tym miejscu podajemy uchwyt do pędzla, wypełniającego wnętrze okna. Pędzel (ang. brush) jest do obiektem pochodzącym z Windows GDI; w skrócie można go określić jako sposób wypełniania jakiejś powierzchni kolorem oraz deseniem (kropkami, kreskami, itp.). Sposób

ten zostanie zastosowany do całego wnętrza okna.

Najczęściej stosuje się tu wartość COLOR_WINDOW (zrzutowaną na typ HBRUSH), gdyż wówczas okno ma domyślny, jednolity kolor. Podanie NULL spowoduje zaś

powstanie przezroczystego okna107.

LPCTSTR lpszMenuName

Zasadniczo jest to nazwa zasobu paska menu, który to pasek ma posiadać każde okno klasy. Wiem, że w tej chwili

robisz wielkie oczy, zatem na razie uznaj, że należy w polu wpisywać NULL :) O zasobach powiemy sobie natomiast za

czas jakiś (długi :D).

int cbClsExtra Określa ilość dodatkowych bajtów, jakie zostaną zaalokowane dla klasy. Prawie zawsze wpisuje się tu zero.

int cbWndExtra

To z kolei ilość bajtów alokowanych wraz z każdym tworzonym oknem klasy. Również wpisuje się tu często

zero.

Tabela 23. Pola struktury WNDCLASSEX

107 Chyba że będzie ono poprawnie odrysowywało swoją zawartość w reakcji na komunikat WM_PAINT lub WM_ERASEBKGND.

Huh, to jest dopiero struktura, co się zowie :) Jak widać Windows żąda nadzwyczaj dużo informacji w trakcie rejestrowania klasy okna. Podajmy je więc; oto, jak w naszym programie przebiega wypełnianie struktury WNDCLASSEX:

// deklaracja i wyzerowanie struktury WNDCLASSEX KlasaOkna;

ZeroMemory (&KlasaOkna, sizeof(WNDCLASSEX));

// zapisanie wartości do pól

KlasaOkna.cbSize = sizeof(WNDCLASSEX); // 1

KlasaOkna.hInstance = hInstance; // 2

KlasaOkna.lpfnWndProc = WindowEventProc; // 3 KlasaOkna.lpszClassName = g_strKlasaOkna.c_str(); // 4 KlasaOkna.hCursor = LoadCursor(NULL, IDC_ARROW); // 5 KlasaOkna.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 6 KlasaOkna.hbrBackground = (HBRUSH) COLOR_WINDOW; // 7

Rozpoczynamy od jej wyzerowania: funkcja ZeroMemory() wypełnia zerami podany jej obszar pamięci o wyznaczonym rozmiarze - przekazujemy jej zatem wskaźnik do naszej struktury i jej wielkość w bajtach.

Dalej zapisujemy ową wielkość (1) w polu cbSize - jak wspomniałem w tabeli, jest to konieczne i trzeba to uczynić. Podobne w polu hInstance umieszczamy (2) uchwyt do instancji naszego programu.

W kolejnym przypisaniu (3) ustalamy procedurę zdarzeniową dla okien naszej klasy. W tym celu w polu lpfnWndProc zapisujemy wskaźnik do uprzednio napisanej funkcji WindowEventProc() - jak wiemy, wystarczy tutaj napisać po prostu nazwę funkcji bez końcowych nawiasów okrągłych.

Wreszcie w polu lpszClassName podajemy nazwę rejestrowanej klasy (4). Zapisaliśmy ją w globalnej zmennej typu std::string, lecz struktura żadą tutaj napisu w stylu C i dlatego posługujemy się skrzętnie metodą c_str().

Następne ustalenia są już bardziej skomplikowane. Oto wybieramy (5) obrazek, jaki będzie pojawiał się nad naszym oknem, gdy przesunie się tam kursor myszy.

Posługujemy się do tego funkcją LoadCursor(); potrafi ona wczytać obrazek kursora i zwrócić doń uchwyt typu HCURSOR. Wczytujemy natomiast standardową bitmapę strzałki, będącą kursorem systemowym, oznaczonym przez IDC_ARROW. Jako że nie posługujemy się tutaj własnym rysunkiem, lecz korzystamy z tych udostępnianych przez Windows, w pierwszym parametrze funkcji wpisujemy NULL.

Bardzo podobnie przebiega ustawienie ikony okna (6). Tym razem posługujemy się funkcją LoadIcon(), działającą jednak niemal identycznie: pierwszy parametr to znowu NULL, gdyż posłużymy się ikonami systemowymi. IDI_APPLICATION wskazuje zaś, że pragniemy wydobyć domyślną ikonę aplikacji Windows.

Naturalnie Windows posiada znacznie więcej wbudowanych ikon i kursorów.

Odpowiadające im stałe można znaleźć w dokumentacji funkcji LoadIcon() i LoadCursor().

Możliwe jest rzecz jasna stosowanie własnych ikon i kursorów w tworzonych oknach - w tym celu trzeba posłużyć się mechanizmem zasobów (ang. resources).

Ostatnie ustawienie (7) związane jest ze sposobem graficznego wypełnienia wnętrza okna. Jak to zostało nadmienione w opisie pola hbrBackground, stosujemy tutaj standardowy kolor okna Windows, reprezentowany poprzez stałą COLOR_WINDOW rzutowaną na typ HBRUSH.

Na tym kończymy wypełnianie treścią struktury WNDCLASSEX, chociaż nie zajęliśmy każdym z jej dwunastu pól. Pozostałe otrzymały wszelako zadowalające nas wartości w wyniku początkowego wyzerowania całej struktury.

W następnym rozdziale przyjrzymy się jednak dokładniej każdemu polu tejże struktury oraz wartościom, jakie może ono przyjmować.

Gdy mamy już gotowe wszystkie informacje o klasie okna, przychodzi czas na jej

zarejestrowanie. Jest to operacja nadzwyczaj prosta i ogranicza się do wywołania jednej funkcji:

RegisterClassEx (&KlasaOkna);

Funkcja RegisterClassEx() potrzebuje jedynie wskaźnika na przygotowaną strukturę WNDCLASSEX - i tą właśnie daną przekazujemy jej. Po pomyślnym wykonaniu funkcji nasza klasa okna jest już zarejestrowana i możemy wreszcie przystąpić do tworzenia samego okna.

Powiązane dokumenty