ďťż

Blog literacki, portal erotyczny - seks i humor nie z tej ziemi


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).
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • qualintaka.pev.pl
  •