lekcjaA 3O3XEAH56JUSPEKEVGLDH2FH6VKKWN3WUKVVSRY


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 */

HDC hDC; /* Identyfikator kontekstowy */

PAINSTRUCT ps; /* Struktura rysunku */

int nRc=0; /* Zwrot kodu przez funkcje */

switch (message)

{

case WM_CREATE:

Gdy okno jest tworzone Windows przesyłają jeden raz komunikat WM_CREATE do okna. Procedura obsługi nowego okna (new window procedure) otrzymuje ten komunikat po utworzeniu okna, ale jeszcze zanim okno pojawi sie na ekranie.

lParam - Wskaźnik do struktury CREATESTRUCT o postaci:

typedef struct {

LPSTR lpCreateParams;

HANDLE hInst;

HANDLE hMenu;

HWND hwndParent;

int cy;

int cx;

int y;

int x;

LONG style;

LPSTR lpszName;

LPSTR lpszClass;

DWORD dwExStyle;

} CREATESTRUCT; */

Kod obsługi powiekszania/zmniejszania case WM_SIZE. wParam zawiera kod operacji - zmniejsz/powiększ lParam zawiera nową wysokość i szerokość okna

case WM_PAINT:

Pobranie kontekstowego identyfikatora urządzenia. Funkcja BeginPaint() spowoduje w razie potrzeby wysłanie komunikatu WM_ERASEBKGND (Erase Background - skasuj tło).

memset(&ps, 0x00, sizeof(PAINTSTRUCT));

hDC = BeginPaint(hWnd, &ps);

Set Background Mode - ustaw rodzaj tła (tu: przezroczyste):

SetBkMode(hDC, TRANSPARENT);

Aplikacja powinna wykreślić obszar roboczy okna posługując sie grafiką GDI i (Graficzny Interfejs Urządzenia - analogia do graficznego standardu BGI w środowisku DOS). Struktura ps typu PAINSTRUCT zwrócona przez BeginPaint() wskazuje prostokąt do zamalowania. Wypisanie tekstu w głównym oknie aplikacji:

TextOut(hDC, 0, 0, (LPSTR) "Hello, world.", strlen("Hello, world."));

Funkcja TextOut() pracuje w trybie graficznym, więc (podobnie jak inne funkcje graficzne Windows API) otrzymuje jako argument tzw. "kontekst urządzenia" - hDC. Zamykanie okna:

case WM_CLOSE:

DestroyWindow(hWnd);

if (hWnd == hWndMain)

PostQuitMessage(0);

Jeśli zamknięte zostało główne okno aplikacji, funkcja PostQuitMessage() wysyła do Windows komunikat, że aplikacja zakończyła działanie i okno aplikacji zostało usunięte. W tym stadium stosuje się funkcje PostQuitMessage() i PostAppMessage(). Pozostale przypadki są obsługiwane przez wariant domyślny - default. Przekazanie komunikatu do obsługi przez Windows.

default:

return (DefWindowProc(hWnd, Message, wParam, lParam));

Funkcja rejestrująca wszystkie klasy wszystkich okien związanych z bieżącą aplikacja (nazwiemy ją roboczo FRegisterClasses()). Jesli operacja sie powiodła - funkcja zwraca kod błędu.

int FRegisterClasses(void)

{

WNDCLASS wndclass; /* Struktura do definiowania klas okien. */

memset(&wndclass, 0x00, sizeof(WNDCLASS));

Ustawienie parametrów okna w strukturze:

wndclass.style = CS_HRDRAW | CS_VRDRAW;

wndclass.lpfnWindowProc = WindowProc;

Dodatkowa pamięć dla klasy Window i obiektów klasy Window.

Dołączanie innych zasobów odbywa się przy pomocy funkcji:

LoadBitmap() - załaduj mapę bitową

LoadIcon() - załaduj ikonkę

LoadCurcor(), LoadMenu(), itp. ...

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInst;

wndclass.hIcon = LoadIcon(NULL, ID_ICON);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

Utworzenie pędzla (brush) dla tła:

wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

wndclass.lpszMenuName = szAppName;

wndclass.lpszClassName = szAppName;

if (!RegisterClass(&wndclass)) return -1;

}

Typowe obiekty ze składu Windows to

HBRUSH Pędzel; i

HPEN Ołówek;

Należy tu zwrócić uwagę jeszcze na dwa szczegóły techniczne. DC i GDI - Device Context, Graphics Device Interface - to tzw. kontekst urządzenia i graficzny interfejs urządzenia. Pozwala to Windows działać skutecznie w trybie "Device Independent" (niezależnym od sprzętu).

4



Wyszukiwarka

Podobne podstrony:
Lekcja kliniczna 2 VI rok WL
Lekcja Przysposobienia Obronnego dla klasy pierwszej liceum ogólnokształcącego
Lekcja wychowania fizycznego jako organizacyjno metodyczna forma lekcji ruchu
Lekcja kliniczna nr 2 VI rok WL
04 Lekcja
PF7 Lekcja2
lekcja52
Printing bbjorgos lekcja41 uzupelnienie A
lekcja 18 id 265103 Nieznany
Hydrostatyka i hydrodynamika lekcja ze wspomaganiem komputerowym
Lekcja 6 Jak zapamietywac z notatki Tajemnica skutecznych notatek
lekcja 20
lekcja20
Lekcja 04 Szene 04
LINGO ROSYJSKI raz a dobrze Intensywny kurs w 30 lekcjach PDF nagrania audio audio kurs
Printing bbjorgos lekcja01 05 A
'Half Life', czyli pół życia przed monitorem zagrożenia medialne foliogramy gim modul 3 lekcja 5
Lekcja od mamy
lekcja 3 id 265134 Nieznany

więcej podobnych podstron