LEKCJA 41: JAK TWORZY SI� APLIKACJ� DLA Windows? ________________________________________________________________ W trakcie tej lekcji dowiesz si�, jak "posk�ada�" aplikacj� dla Windows z podstawowych funkcji interfejsu API i jakie komunikaty s� najwa�niejsze dla naszych aplikacji. ________________________________________________________________ Przy tworzeniu programu zwr��my szczeg�ln� uwag� na to, co dzieje si� w programie po otrzymaniu komunikatu WM_PAINT (nale�y narysowa� okno). Jest to ��danie ze strony Windows, by program narysowa� obszar roboczy (client area) swojego okna. Program otrzyma komunikat WM_PAINT zawsze na pocz�tku, kiedy powinien narysowa� swoje okno po raz pierwszy i p�niej powt�rnie, za ka�dym razem, gdy trzeba b�dzie odtworzy� okno na ekranie. Je�li inne okno przesuwane po ekranie przys�oni okno naszego programu, po ods�oni�ciu naszego okna Windows prze�l� do programu komunikat WM_PAINT - odtw�rz swoje okno - narysuj go powt�rnie (redraw, repaint). Je�li zechcemy wyprowadzi� na ekran napis "Hello World" tak�e b�dziemy musieli narysowa� okno od nowa. Nie zawsze "od�wie�enia" wymaga ca�e okno. W ka�dej z sytuacji: - ca�e okno zosta�o przys�oni�te i ods�oni�te - cz�� okna wymaga od�wie�enia - okno jest rysowane po raz pierwszy Windows prze�l� do programu ten sam komunikat - WM_PAINT. Je�li odtworzenia wymaga tylko cz�� okna, taka cz�� okna nazywa si� niewa�n�-nieaktualn� (ang. invalid). W Windows takie nieaktualne fragmenty okna zawsze maj� kszta�t prostok�t�w. Wyobra�my sobie, �e jakie� inne okno przes�oni�o naro�nik okna naszego programu. Je�li u�ytkownik usunie to przes�aniaj�ce okno, ods�oni�ty obszar b�dzie potraktowany przez Windows jako nieaktualny. Windows prze�l� do aplikacji komunikat WM_PAINT ��daj�cy odtworzenia okna. ��daj�c odtworzenia okna Windows powinny nas poinformowa� kt�ra cz�� naszego okna zosta�a na ekranie "zepsuta". Wsp�rz�dne prostok�ta na ekranie Windows przeka�� przy pomocy specjalnej struktury nazywanej struktur� rysunku (ang. paint structure - PAINTSTRUCT). Struktur� rysunku mo�emy nazwa� w programie np.: PAINSTRUCT ps; W funkcji WindowProc() obs�uga komunikatu WM_PAINT rozpoczyna si� od wyczyszczenia p�l struktury rysunku ps. Struktura predefiniowanego typu PAINTSTRUCT (w WINDOWS.H) zawiera informacje o rysunku. PAINTSTRUCT ps; { switch (Message) { case WM_CREATE: ..... break; case WM_MOVE: .... break; case WM_SIZE: .... break; case WM_PAINT: /* Obs�uga rysowania okna */ memset(&ps, 0x00, sizeof(PAINTSTRUCT); .... break; //Koniec obs�ugi WM_PAINT case WM_CLOSE: .... break; default: ..... } } Nast�pnie pola struktury rysunku zostaj� wype�nione poprzez okienkow� funkcj� BeginPaint() - RozpocznijRysowanie. Zwr�� uwag�, �e do poprawnego dzia�ania funkcji potrzebne s� informacje o tym, kt�re okno trzeba od�wie�y� (Windows powinny wiedzie� wobec kt�rego okna ��damy informacji o "zepsutym" prostok�cie) i adres naszej struktury rysunku. Aby przekaza� te informacje post�pujemy tak: case WM_PAINT: memset(&ps, 0x00, sizeof(PAINTSTRUCT)); hDC = BeginPaint(hWnd, &ps); .... Teraz funkcja BeginPaint() mo�e wype�ni� nasz� struktur� rysunku ps danymi. Pola struktury typu PAINTSTRUCT wygl�daj� nast�puj�co: typedef struct tagPAINTSTRUCT { HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BYTE rgbReserved[16]; } PAINTSTRUCT; Przy pomocy pola typu RECT (ang. rectangle - prostok�t) Windows przekazuj� do programu wsp�rz�dne wymiary (ang. dimensions) "zepsutego" na ekranie prostok�ta. Typ RECT oznacza nast�puj�c� struktur�: typedef struct tagRECT { int left; //wsp�rz�dna lewa - x int top; //wsp�rz�dna g�rna - y int right; //wsp�rz�dna prawa - x int bottom; //wsp�rz�dna dolna - y } RECT; G�rny lewy r�g nieaktualnego prostok�ta (invalid rectangle) ma dwie wsp�rz�dne (left, top) a dolny prawy r�g prostok�ta ma wsp�rz�dne (right, bottom). Te wsp�rz�dne ekranowe mierzone s� w pikselach i s� to wsp�rz�dne wzgl�dne - wzgl�dem lewego g�rnego naro�nika okna aplikacji. Lewy g�rny naro�nik okna aplikacji ma wi�c wsp�rz�dne (0,0). Zwr��my uwag� na warto�� zwracan� przez funkcj� BeginPaint() - zmienn� hDC: case WM_PAINT: memset(&ps, 0x00, sizeof(PAINTSTRUCT)); hDC = BeginPaint(hWnd, &ps); .... Wszystnie operacje graficzne b�d� wymaga� nie kodu okna hWnd a w�a�nie kodu-identyfikatora kontekstowego hDC. Na pocz�tku pracy programu, gdy okno jest rysowane po raz pierwszy, Windows generuj� komunikat WM_PAINT i ca�y obszar roboczy okna jest uznawany za nieaktualny. Kiedy program otrzyma ten pierwszy komunikat, mo�emy wykorzysta� to do umieszczenia w oknie np. napisu. Je�li tekst ma rozpoczyna� si� od lewego g�rnego naro�nika okna aplikacji, funkcja TextOut() u�ywana w Windows do wykre�lania tekstu (w trybie graficznym) powinna rozpoczyna� wyprowadzanie tekstu od punktu o (pikselowych) wsp�rz�dnych (0,0). case WM_PAINT: ... TextOut(hDC, 0, 0, (LPSTR) "Tekst", strlen("Tekst")); EndPaint(hWnd, &ps); break; Funkcja TextOut() (wyprowad� tekst) pobiera pi�� parametr�w: hDC - identyfikator-kod prostok�ta, kt�ry nale�y narysowa� x - wsp�rz�dna pozioma (w pikselach) y - wsp�rz�dna pionowa pocz�tku naszego napisu W tym przypadku wsp�rz�dne wynosz� (0,0). LPSTR - wska�nik do �a�cucha znak�w "Hello world." LPSTR = long pointer to string (wska�nik typu far). Wska�nk ten przekazujemy do funkcji poprzez forsowanie typu: ... (LPSTR) "Tekst"; Zgodnie z definicj� typu w pliku WINDOWS.H spowoduje to zamian� wska�nika do �a�cucha typu near char* (bliski) na wska�nik typu far (daleki). Ostatni parametr funkcji to d�ugo�� wyprowadzanego tekstu - tu obliczana przez funkcj� strlen(). Prze�led�my etapy powstawania aplikacji. Funkcja MainWin() rejestruje i tworzy g��wne okno programu oraz inicjuje globalne zmienne i struktury. Funkcja WinMain() zawiera p�tl� pobierania komunikat�w. Ka�dy komunikat przeznaczony dla g��wnego okna (lub ewentualnych nastepnych okien potomnych) jest pobierany, ewentualnie poddawany translacji i przekazywany do funkcji obs�uguj�cej dialog z Windows. Przed zako�czeniem programu funkcja WinMain() kasuje utworzone wcze�niej obiekty, zwalnia pami�� i pozosta�e zasoby. UWAGA: "Obiekty" nie s� tu u�yte w sensie stosowanym w OOP. "Obiekt" oznacza tu np. struktur�. int PASCAL WinMain(HANDLE hInstance, hPrevInstance, LPSTR lpszCmLine, int nCmdShow) { ... HANDLE hInstance - identyfikator bie��cego pojawienia si� danej aplikacji. Poniewa� w Windows program mo�e by� uruchamiany wielokrotnie, stosuje sie pojecie tzw. "Instancji" - wyst�pienia - uruchomienia programu. HANDLE hPrevInstance - identyfikator poprzedniego wyst�pienia danej aplikacji LPSTR lpszCmdLine - daleki wska�nik do parametr�w wywo�ania programu z linii rozkazu int nCmdShow - spos�b pocz�tkowego wy�wietlenia okna (pe�ne okno, b�d� ikona) Deklaracja struktury typu MSG (Message) do przechowywania komunikat�w. MSG msg; Nadanie nazwy aplikacji: strcpy(szAppName, "Nazwa Aplikacji"); Rejestrujemy struktury okien je�li jest to pierwsze uruchomienie danej aplikacji i sprawdzamy, czy rejestracja powiod�a si�: if(!PrevInstance) { if((int nRc = RegisterClass() ... Utworzenie g��wnego okna programu (mo�e si� nie uda�): hWndMain = CreateWindow(....); if(hWndMain == NULL) { MessageBox(0, "Klops", "Koniec", MB_OK); return (FALSE); } Wy�wietlenie g��wnego okna na ekranie: ShowWindow(hWndMain, nCmdShow); P�tla komunikat�w wykrywaj�ca komunikat WM_QUIT: while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } G��wna procedura obs�ugi okna WindowProc(). Instrukcja switch prze��cza do odpowiedniego wariantu dzia�ania - obs�ugi odpowiedniego komunikatu. Musz� tu znajdowa� sie procedury obs�ugi wszystkich interesujacych nas dzia�a� uzytkownika i og�lnych komunikatow Windows (np. WM_CLOSE). Je�li wyst�pi taki komunikat, kt�rego obs�uga nie zosta�a przewidziana, obs�uga jest przekazywana, do funkcji okienkowej DefWindowProc() - obs�ug� przejmuj� Windows. Komunikaty inicjowane przez u�ytkownika s� rozpatrywane zasadniczo jako WM_COMMAND. Rozkaz wybrany z menu lub odpowiadaj�ca mu kombinacja klawiszy jest przekazywana przy pomocy pierwszego parametru komunikatu - wParam. Kod odpowiadaj�cy rozkazowi z menu nazywa sie "control menu ID", a identyfikator kombinacji klawiszy - "accelerator ID". Procedura obs�ugi komunikat�w powinna zawiera� case (WM_COMMAND): ..... break; Wewn�trz przy pomocy instrukcji switch{...} nale�a�oby rozpatrywa� kolejne warianty, wykorzystuj�c identyfikator wybranego z menu rozkazu - ID. Obs�uga komunikatow �wiadcz�cych o wyborze przez u�ytkownika rozkazu z menu stanowi zwykle g��wn� robocz� cze�� programu. LONG FAR PASCAL WindowProc(HWND hWnd, WORD Message, WORD wParam, LONG lParam) { HMENU hMenu=0; /* Identyfikator menu */ HBITMAP hBitmap=0; /* Identyfikator mapy bitowej */ ...
mikomil