Sunteți pe pagina 1din 28

1.

Noiuni elementare de WinApi


1.1. Introducere - cum arat un program de windows? Un program de windows este alctuit dintr-o fereastr principal cu o structur standard (de obicei). Aceast fereastr se afl pe ecran pe parcursul ntregii desfurri a aplicaiei, ateptnd input de la utilizator/system la care reacioneaz n mod adecvat.. Aplicaiile windows sunt aplicaii care au la baz evenimente (event driven), de exemplu de la mouse, menu, tastatur, butoane etc. Evenimentele genereaz mesaje, care sunt plasate ntr-o coad de mesaje, urmnd a fi procesate secvenial. Coada de mesaje ateapt mesaje pe parcursul ntregii durate a aplicaiei

1.2. Structura de baz a unui program windows Un program windows conine cel puin dou funcii de baz:
(1) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) (2) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

(1) Funcia WinMain (echivalent cu void main() in C): Observaii: Creeaz o clas window pentru fereastra principal i nregisteaz aceast clas. Creeaz o nou fereastr ca instan a acestei clasei window. Afiaz fereastra creat pe ecran. Lanseaz bucla de mesaje

Fiecare fereastr are un handle (identificator de fereastr) pe baza creia poate fi refereniat Fiecare fereastr aparine unei instane a programului Evenimentele unei ferestre sunt gestionate de ctre procedura de ferastr (2) Funcia WndProc (poate avea orice nume! Nu doar WndProc): Reprezint procedura de fereastr Determin rspunsul la diferitele mesaje generate de evenimente

Exemplu: minapp.cpp
#include #include #include #include #include #include <windows.h> "definitions.h" "FrameGrabber.h" "resource.h" "loadsave.h" "result.h" // // // // // Include Include Include Include Include definitions FrameGrabber class resources headers of load and save functions hader for result window

// // Prototipe of the window procedure, which handles the events // LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); FrameGrabber *fg; bool passthruOn; HWND hwndmain; HINSTANCE myinstance; BYTE *buffer1,*buffer2; // FrameGrabber object // Only for image aquisition // Handle of the main window //Current instrance // Buffers for the image pixels

// // Main function int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { myinstance=hInstance; WNDCLASS wcmain; // Structure of window class MSG msg; // Variable for messages char * szWindowTitle = "Digital Image Processing"; //Window title char * szClassName = "dbvapp"; //Window class name int xPos = 100, yPos = 100; //Coordinates of main window on screen int width = MAX_COL+20 ,height = MAX_ROW + 50; //width and height of //main window buffer1 = new BYTE[ALL_PIXELS]; buffer2 = new BYTE[ALL_PIXELS]; // Test if there was a previous instance of the application if (hPrevInstance == 0) { wcmain.style = CS_BYTEALIGNWINDOW|CS_HREDRAW|CS_VREDRAW| CS_DBLCLKS; //Window stiles wcmain.lpfnWndProc = WndProc; //Sets the window procedure wcmain.cbClsExtra = 0; wcmain.cbWndExtra = 0; wcmain.hInstance = hInstance; //Sets the instance wcmain.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcmain.hCursor = LoadCursor(NULL, IDC_ARROW); wcmain.hbrBackground= (HBRUSH) GetStockObject(BLACK_BRUSH); wcmain.lpszMenuName = MAKEINTRESOURCE(IDR_DBVAPP); //Sets menu wcmain.lpszClassName= szClassName; //Sets name foe window class //Each new class has to be registered if (!RegisterClass(&wcmain)) { //Pixel buffers for image pixels

MessageBox(NULL,TEXT("Programm works with Unicode and requires Windows NT!"),szClassName, MB_ICONERROR); return 0; } } // Create main window. Returns as result the handle to the window! hwndmain = CreateWindow( szClassName, // Name of the corresponding class szWindowTitle, //String which will appear in the title //bar WS_SYSMENU|WS_CAPTION|WS_OVERLAPPED|WS_BORDER|WS_MINIMIZEBOX, //stiles of the window xPos, yPos, // Coordinates of upper left corner of //the window on the screen width, height, // Dimensions of the window NULL, // handle to parent Window (none) LoadMenu(hInstance, MAKEINTRESOURCE(IDR_DBVAPP)), //Menu hInstance, // Instance to which it belongs NULL); // Test if the window was created successfully if (hwndmain == NULL) { MessageBox(NULL, TEXT("Window could not be opened!"), szClassName, MB_ICONERROR); return 0; } // Initialize the Framegrabber (instance of the FrameGrabber class) if (!(fg = new FrameGrabber("dbv"))) { MessageBox(NULL, TEXT("Framegrabber could not be initialized!"), szClassName, MB_ICONERROR); return 0; } // Create to frames for the FrameGrabber object fg->NewFrame(); fg->NewFrame(); // Show and update created window ShowWindow(hwndmain, iCmdShow); UpdateWindow(hwndmain); // Message queue while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam;

//Window Procedure. Has as parameters the handle of the window to which //it belongs, the message received and suplimentar information about the //message LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) {

// message generated when creating the window case WM_CREATE: return 0; // medssage genrated when destroying the window case WM_DESTROY: delete fg; PostQuitMessage(0); // ends the program by sending WM_QUIT message return 0; // message generated when drawing or redrawing the window case WM_PAINT: HDC hdc; //handle to a device context PAINTSTRUCT ps; hdc = BeginPaint(hwnd, &ps); //painting has allways to begin with //this function fg->DrawFrame(1,hwnd); //draws the pixels saved in frame 1 in the //window with the handle hwnd EndPaint(hwnd, &ps); //painting has to end with this function return 0; // wenn Menuepunkte angewaelt werden case WM_COMMAND: switch(LOWORD(wParam)) { case ID_OPEN: LoadImage(hwnd); break; case ID_SAVE: SaveImage(hwnd); break; case ID_CLOSE: // Verschickt die WM_DESTROY Nachricht an das Fenster hwnd DestroyWindow(hwnd); return 0; default: // Nachrichten weiterleiten return DefWindowProc(hwnd, message, wParam, lParam); } default: // Nachrichten weiterleiten return DefWindowProc(hwnd, message, wParam, lParam); } return 0; }

1.3. Explicitarea structurii programului principal

Funcia WinMain
(1) Explicitatea parametrilor Funcia WinMain are 4 parametri: hInstance (instance handle) : - reprezint un numr care identific n mod unic programul aflat n execuie (este posibil ca utilizatorul s ruleze mai multe copii ale aceluiai program, copii denumite instane. Fiecare instan are o valoare hInstance diferit). hPrevInstance

- este identificatorul celei mai recente instane anterioare instanei curente. Dac nu exist instane anterioare hPrevInstance are valoarea 0/NULL szCmdLine este o variabil pointer care puncteaz ctre un ir de caractere ce conine parametrii din linia de comand i care sunt transferai programului iCmdShow este un numr ce reprezint modul de afiare al primei ferestre executate (1=normal/7=pictogram)

(2) Crearea unei ferestre Definirea clasei de ferestre O fereastr este creat dintr-o clas window. O astfel de clas se creaz prin definirea caracteristicilor ei, printer care i a procedurii de fereastr care prelucreaz mesajele transmise de fereastra creat. Dup crearea clasei este necesar s o nregistrm prin apelarea funciei RegisterClass. Doar prima instan a unui program trebuie s nregistreze clasa window. WNDCLASS este o structur care mi permite s definesc clase de obiecte de tip fereastr. Acest tip conine 10 cmpuri (variabile).care descriu caracteristicile tuturor ferestrelor create pe baza acestei clase. Nume cmp Style lpfnWndProc cbClsExtra cbWndExtra hInstance hIcon hCursor hbrBackground lpszMenuName lpszClassName Stilul ferestrei Numele procedurii de fereastr. Dou cmpuri care permit rezervarea de spaiu suplimentar n structura class i n structura window. Un program poate utiliza acest spaiu n scopuri personale. n general nu avem nevoie de acest spaiu suplimentar i setm cmpurile la 0. Identificatorul instanei ferestrei Stabilete o pictogram pentru toate ferestrele create pe baza clasei window. Stabilete o pictogram pentru cursor Specific culoarea de fundal a ferestrei Specific meniul feresteri Specific numele ferestrei Semnificaie

Pentru crearea unei clase de ferestre trebuie iniializate aceste 10 cmpuri. Acest lucru se face numai la nceput, nainte de crearea primei ferestre (deci nainte de prima instan). Dup iniializarea cmpurilor trebuie nregistrat clasa cu ajutorul funciei RegisterClass(). Acest lucru se face de asemenea doar pentru prima instan. De aceea nainte de aceste operaii se verific condiia hPrevInstance= =NULL (adic nu exist instan anterioar). n continuare este explicat iniializarea cmpurilor n cazul programului minapp.cpp Stilul ferestrei
wcmain.style = CS_BYTEALIGNWINDOW|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS

fereastra va fi reactualizat complet la fiecare modificare orizontal sau vertical i recunoate double-click de mouse (CS = class style) Procedura de fereastr este WndProc. Ea trateaz mesajele transmise de fereastra curent
wcmain.lpfnWndProc = WndProc

Instana ferestrei: este instana curent hInstance (dat de primul parametru al WinMain())
wcmain.hInstance = hInstance;

Pictograma pentru toate ferestrele create pe baza clasei wcmain se obine prin ncrcarea unei pictograme (o imagine de tip bitmap) cu funcia LoadIcon. Pentru obinerea unei pictograme predefinite se folosete funcia LoadIcon cu primul parametru NULL, iar al doilea este un identificator cu prefixul IDI (IDentificator de Icon) i este definit n fiierul windows.h
wcmain.hIcon = LoadIcon(NULL, IDI_APPLICATION);

Cursorul pentru fereastr se obine prin ncrcarea unui cursor (o imagine de tip bitmap) cu funcia LoadCursor. Pentru obinerea unui cursor predefinit valoarea primul parametru al funciei este NULL iar al doilea este un identificator care ncepe cu prefixul IDC i este definit n fiierul windows.h
wcmain.hCursor = LoadCursor(NULL, IDC_ARROW);

hbrBackground este un handle ctre o pensul (hbr = h + br unde h este pentru handle i br pentru brush) pentru culoarea de fundal. O pensul reprezint un model colorat de pixeli utilizat n umplerea unei zone. Exist mai multe pensule standard, care pot fi obinute cu funcia GetStockObject (cu care pot fi obinute i alte obiecte grafice).
wcmain.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);

Menu:
wcmain.lpszMenuName = MAKEINTRESOURCE(IDR_DBVAPP);

Dac nu avem menu atunci: wcmain.lpszMenuName = NULL; Numele clasei:- definesc numele clasei de ferstre
wcmain.lpszClassName= szKlassenName;

Urmeaz nregistrarea clasei de ferestre, prin transmiterea adresei variabilei wcmain: RegisterClass(&wcmain) i se testeaz dac a putut fi nregistrat clasa. n caz contrar se returneaz mesaj de eroare.

Crearea unei ferestre din clasa definit Crearea unei instane a clasei definite anterior se realizeaz cu ajutorul funciei CreateWindow. Aceast funcie returneaz un handle (o referin) la obiectul fereastr creat. Funcia CreateWindow are ca parametri: numele clasei de ferestre creia i aparine obiectul fereastr creat: szClassName titlul ferestrei (care apare n bara de titlu): szWindowTitle stilul ferestrei: WS_SYSMENU|WS_CAPTION|WS_OVERLAPPED|WS_BORDER|
WS_MINIMIZEBOX,

coordonatele colului stnga sus: xPos, yPos dimensiunea ferestrei: width, height referina ctre fereastra printe: NULL (pentru c nu avem fereastr printe) referina ctre meniu: LoadMenu(hInstance, MAKEINTRESOURCE(IDR_DBVAPP))

instana creia i aparine fereastra: hInstance (parametru al funciei WinMain) creation parameters: NULL

Referina (handle) ctre fereastra creat este n exemplul de mai sus hwndmain i este de tip HWND (handle to a window). Fiecare fereastr are un handle propriu, pe baza cruia se poate stabili de unde vine un mesaj sau unde se efectueaz anumite operaii. Pot crea mai multe ferestre pe baza aceleiai clase, dar fiecare va avea un handle diferit. Dup ce creez fereastra cu ajutorul funciei CreateWindow, testez dac programul a putut s o creeze. Altfel (if(hwndmain==NULL)) se returneaz eroare.

(3) Afiarea unei ferestre Dup ce am creat obiectul de tip fereastr, acesta trebuie afiat pe ecran. Acest lucru se face prin apelul succesiv a dou funcii:
ShowWindow(hwndmain, iCmdShow);

afieaz fereastra pe ecran. Primul parametru specific fereastra care este afiat, iar al doilea tipul de afiare (SW_SHOWNORMAL = normal sau SW_SHOWMINNOACTIVE = pictogram).
UpdateWindow(hwndmain);

transmite ctre procedura de fereastr un mesaj de tip WM_PAINT, care are ca rezultat redesenarea ferestrei (reactualizarea zonei client a ferestrei).

(4) Bucla de mesaje Programul trebuie s prelucreze date primite de la utilizator prin intermediul tastaturii i a mouse-ului. Cu ajutorul tastaturii i a mouse-ului se produc evenimente de intrare care sunt transmise procedurii de fereastr sub form de mesaje. Sistemul Windows include o structur de date message queue (coad de mesaje) care convertete fiecare aciune a utilizatorului ntr-un mesaj i l plaseaz n coada de mesaje. Cu ajutorul funciei GetMessage pot extrage mesajul aflat la nceputul cozii ntr-o structur de tip MSG. Acest mesaj este convertit cu ajutorul funciei Translate Message i apoi acesta este transmis ctre procedura de fereastr cu ajutorul funciei DispatchMessage. Pentru preluarea mesajelor de fereastr se definete o bucl de mesaje, care este activ pe tot parcursul existenei ferestrei:
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); // Traducerea mesajului DispatchMessage(&msg); // Transmiterea mesajului ctre //procedura de fereastr }

Variabila msg este o structur de tip MSG i are urmtoarele cmpuri:


HWND hwnd identific fereastra de la care vine mesajul UINT message este o constant ce identific mesajul. Aceste constante ncep cu

prefixul WM (Window Message) (de ex. WM_PAINT sau WM_LBUTTONDOWN)


WPARAM wParam un parametru (pe 16 bii) LPARAM lParam un parametru (pe 32 bii). Aceti 2 param. depind de tipul

mesajului i furnizeaz informaii suplimentare referitoare la mesaj DWORD time conine momentul de timp la care mesajul a fost plasat n coada de mesaje POINT pt conine coordonatele mouse-ului la momentul generrii mesajului

Parametrii 2, 3 i 4 se seteaz la NULL respectiv 0, 0 pentru a indica faptul c sunt recepionate mesaje de la toate ferestrele create de program.

Pentru orice mesaj n afar de WM_QUIT funcia GetMessage( ) returneaz o valoare diferit de 0. Mesajul WM_QUIT determin ieirea din bucl, iar programul returneaz cmpul wparam al structurii msg.

Prelucrarea mesajelor cu procedura de fereastr


(1) Procedura de fereastr Procedura de fereastr (n cazul nostru WndProc) determin coninutul ce va fi afiat n zona client a ferestrei corespunztoare i modul de rspuns al ferestrei la evenimentele produse de utilizator (de ex. click de mouse, apsarea unui buton, selectarea unei opiuni de meniu etc.). O procedur de fereastr este ntotdeauna asociat unei clase window particular i poate avea orice nume. Definiia procedurii de fereastr:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

Procedura are 4 parametri:


HWND hwnd identific fereastra de la care a primit mesajul UINT message identific mesajul primit (de ex. WM_PAINT) WPARAM wParam LPARAM lParam aceti 2 parametri conin informaii suplimentare despre mesaj i

depind de fiecare mesaj n parte. (2) Generarea i prelucrarea mesajelor Att sistemul de operare ct i aplicaia n sine pot genera mesaje. care sunt plasate n coada de mesaje ale aplicaiei (mesage application queue). Ulterior aceste mesaje sunt extrase din coad de ctre aplicaie (prin funcia GetMessage( ) ) i expediate ctre procedura de fereastra, care le prelucreaz. Exist anumite mesaje care nu sunt plasate n coada de mesaje ci sunt trimise direct ctre procedura de fereastr (unqueued messages). De exemplu funcia CreateWindow( ) transmite un mesaj WM_CREATE procedurii de fereastr (fr ca acest mesaj s fie plasat nti n coada de mesaje). Extragerea mesajelor din coada de mesaje se face cu ajutorul funciei GetMessage n bucla de mesaje discutat mai sus. Fiecare mesaj este prelucrat de ctre procedura de fereastr. Acest lucru se ntmpl ntr-o construcie de tip switch, care n funcie de mesaj efectueaz anumite operaii (stabilite de ctre programator).

Exemplu: Scrie n fereastr mesajul Primul program


switch (message) { case WM_PAINT: HDC hdc; //contextul grafic PAINTSTRUCT ps; RECT rect; //Obiect dreptunghi hdc = BeginPaint(hwnd, &ps); //Obinerea contextului grafic GetClientRect(hwnd,&rect); //Obinerea suprafeei de desenare //Scrierea unui text n fereastr DrawText(hdc,"Primul program",-1,&rect,DT_CENTER|DT_VCENTER); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: // Alte mesaje sunt trimise ctre funcia implicit de //tratare return DefWindowProc(hwnd, message, wParam, lParam);

n general programatorul va stabili operaii numai pentru anumite mesaje, caz n care se va returna valoarea 0 (adic mesajul a fost prelucrat). Mesajele care nu sunt prelucrate n mod explicit de ctre procedura de fereastr, trebuie pasate ctre funcia implicit de prelucrare a mesajelor DefWindowProc.

(3) Mesajul WM_PAINT Acest mesaj genereaz redesenarea zonei client a ferestre. El este transmis atunci cnd o anumit poriune a zonei client este invalid i trebuie redesenat, de exemplu atunci cnd: se creeaz o fereastr pentru prima dat (generat de funcia UpdateWindow) se redimensioneaz fereastra (atunci cnd cmpul style al structurii wcmain a fost definit de tip CS_HREDRAW i CS_VREDRAW adic invalidarea ntregii ferestre n cazul redimensionrii orizontale sau verticale) se minimizeaz i apoi se restaureaz fereastra atunci cnd se deplaseaz fereastra atunci cnd se revine la fereastra aplicaiei dup ce aceasta a fost acoperit de alte ferestre

Obinerea i eliberarea contextului graphic (BeginPaint / EndPaint) Pentru a putea desena n fereastr este necesar obinerea unui context graphic (device context) pstrat ntr-o variabil hdc de tip HDC. Pentru aceasta se apeleaz funcia BeginPaint:
hdc = BeginPaint(hwnd, &ps);

Primul parametru hwnd identific fereastra care a generat mesajul. Al doilea parametru este un pointer ctre o structur de tip PAINTSTRUCT, care conine informaii ce pot fi utilizate la redesenarea ferestrei. Cmpurile structurii PAINTSTRUCT sunt: HDC hdc handle ctre un dispozitiv de ieire (vezi mai jos) BOOL fErase pentru tergerea zonei client RECT rcPaint dreptunghiul care reprezint zona invalid a zonei client. Acest cmp mi permite de ex. s realizeze redesenarea numai a poriunii invalide, nu neaprat a ntregii zone client. BOOL fRestore BOOL fIncUpdate BYTE rgbReserved[6] ultimele trei cmpuri sunt rezervate pentru sistemul Windows. Aceste cmpuri sunt iniializate de ctre funcia BeginPaint. Funcia BeginPaint realizeaz tergerea zonei client prin acoperirea ei cu culoarea setat la cmpul hbrBackground al structurii wcmain. Apoi este validat zona client i se napoiaz o variabil hdc denumit handle to a device context, adic un handle ctre un dispozitiv de ieire (de ex. ecran sau imprimant). nainte de ncheierea prelucrrii mesajului, trebuie eliberat contextual graphic prin intermediul funciei EndPaint.
EndPaint(hwnd,&ps) ;

Obinerea zonei client pentru desenare Funcia GetClientRect(hwnd, &rect) permite plasarea n variabila rect (structur de tip rectangle) a dimensiunilor zonei client a ferestrei. Structura rect conine 4 cmpuri: left, top, right i bottom.
Left i top sunt fixate la valoarea 0 i reprezint colul din stnga sus al zonei client. Right

i bottom conin limea i respectiv nlimea zonei client (dau colul dreapta jos) msurate n pixeli.

Mesajul WM_DESTROY Mesajul rezult n urma selectrii opiunii Close din meniul System aferent programului sau prin apsarea combinaiei de taste Alt+F4 sau dac am o opiune de meniu/buton cruia i asociez distrugerea ferestrei. Acest mesaj semnaleaz programului c urmeaz distrugerea ferestrei. Tratarea mesajului se face n mod standard prin apelarea funciei PostQuitMessage(0) care insereaz n coada de mesaje un mesaj WM_QUIT. Atunci cnd funcia GetMessage va extrage mesajul WM_QUIT, va returna valoarea 0, ceea ce va determina ncheierea buclei de mesaje i implicit terminarea programului.

2. Elemente de grafic i afiare de text 2.1. Despre zona client


Zona client ocup tot spaiul ferestrei ce nu include bara de titlu, cadrul de redimensionare, bar de meniu i barele de navigare. Zona client reprezint acea poriune de fereastr n care utilizatorul poate efectua diverse operaii grafice. n general operaiile grafice sunt efectuale n urma generrii unui mesaj de tip WM_PAINT (dar nu numai). Acest mesaj informeaz procedura de fereastr c a fost invalidat o poriune a zonei client i c aceasta este pregtit pentru reactualizare (deci pentru efectuarea de operaii grafice). Un mesaj WM_PAINT este generat n urmtoarele cazuri: o zon a ferestrei acoperit anterior este readus n prim plan fereastra este redimensionat, iar stilul ferestrei este de tip CS_HREDRAW/CS_VREDRAV sunt utilizate bare de navigare programul folosete funcia InvalidateRect/InvalidateRegion pentru a genera n mod explicit un mesaj WM_PAINT este nchis o caset de dialog/mesaj care se suprapunea peste zona client un meniu popup este selectat i apoi eliberat etc.

Observaie: observm c putem genera n mod explicit un mesaj WM_PAINT prin apelul funciei InvalidateRect!!! Dimensiunile zonei client Dimensiunile zonei client variaz de la fereastr la fereastr i depind evident de dimensiunea ferestrei. Ori de cte ori se modific dimensiunea ferestrei, sistemul Windows trimite un mesaj WM_SIZE procedurii de fereastr. n acest caz variabila dat de parametrul procedurii de fereastr, lParam, conine dimensiunile zonei client, i anume: LOWORD(lParam) = limea ferestrei HIWORD(lParam) = nlimea ferestrei. Obinerea acestor dimensiuni se poate face cu urmtorul cod:
static short cxClient, cyClient; //alte instruciuni, iar n instruciunea switch(message) { //alte mesaje

case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; //alte mesaje default: return DefWindowProc(hwnd, message, wParam, lParam); }

Observaie: variabilele cxClient i cyClient conin dimensiunile zonei client i sunt de tip static pentru a putea fi utilizate ulterior la prelucrarea altor mesaje.

2.2. Contextul dispozitiv (Display Context DC)


La apelul funciei BeginPaint se obine o variabil hdc de tip HDC. Aceasta ne permite s efectum operaii grafice pe un anumit dispozitiv de ieire, care n cazul nostru este ecranul. Un handle reprezint un numr pe care l folosete sistemul Windows pentru a se referi la un obiect. DC reprezint o structur de date asociat unui dispozitiv de ieire (ex: imprimant, plac video- n acest caz este asociat unei ferestre de pe ecran, plotter). Mediul de operare grafic utilizeaz valorile din structura DC (atributele contextului aferent dispozitivului de ieire) pentru a determina diferite elemente (cum ar fi: culoare, culoare de fundal, font, pensul, coordonate etc.) Cnd un program vrea s deseneze un obiect, trebuie mai nti s obin un hdc, iar cnd a terminat operaiile de desenare va trebui s-l elibereze. Acest lucru se poate realiza n dou moduri: 1. n cazul tratrii mesajului WM_PAINT cu perechea de funcii BeginPaint, EndPaint 2. n cazul tratrii altui mesaj, prin perechea de funcii GetDC, ReleaseDC: Exemplu:
hdc=GetDC(hwnd); // funcii de desenare ReleaseDC(hwnd,hdc);

Observaie: n cazul 1. cnd se trateaz mesajul de tip WM_PAINT se redeseneaz doar poriunea invalid din zona client, nu ntreaga zon client. Dac se dorete redesenarea ntregii zone client trebuie apelat funcia InvalidateRect(hwnd, NULL, TRUE)

(cu TRUE dac se dorete tergerea fundalului i cu FALSE dac nu se dorete tergerea fundalului) nainte de apelul funciei BeginPaint n al 2-lea caz se poate desena n toat zona client.

2.3.

Afiarea de text

Exist dou funcii pentru afiarea de text


(1) int DrawText(HDC hdc, LPCSTR lpsz, int nc, RECT FAR *lpcr, UINT format)

unde parametrul 3 (nc) conine nr. de caractere al irului ce trebuie afiat. n cazul irurilor de caractere care n C se termin cu \0, pentru ca ntreg irul s fie afiat setez nc=-1. parametrul 4 conine adresa unui dreptunghi de formatare (n funcie de acesta pot de exemplu alinia textul la dreapta, stnga, centrat etc.) parametrul 5: un ir format o serie de indicatori (legai prin | = sau pe bii) de format de exemplu: DT_TOP, DT_BOTTOM, DT_LEFT, DT_RIGHT - aliniere sus-jos, stnga-dreapta DT_CENTER, DT_VCENTER DT_SINGLELINE etc. Exemplu:
case WM_PAINT: HDC hdc; //contextul grafic PAINTSTRUCT ps; RECT rect; //Obiect dreptunghi hdc = BeginPaint(hwnd, &ps); //Obinerea contextului grafic GetClientRect(hwnd,&rect); //Obinerea suprafeei de desenare //Scrierea unui text n fereastr DrawText(hdc,"Primul program",-1,&rect,DT_CENTER|DT_VCENTER); EndPaint(hwnd, &ps); return 0;

- centrare orizontal i vertical - text pe o singur linie

(2) BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString, int cbString)

unde: hdc handle ctre contextul de afiare nXStart, nYStart coordonatele de la care se ncepe afiarea

lpszString irul de caractere care se afieaz cbString nr. de caractere care se afieaz (lungimea irului)

Exemplu:
case WM_PAINT: HDC hdc; PAINTSTRUCT ps; RECT rect; char sir[40]; short lungime=sprintf(sir, Valorile obtinute sunt %d, %d si %d,x1,x2,x3); //unde x1, x3, x3 sunt niste //variablie din program hdc = BeginPaint(hwnd, &ps); //Obinerea contextului grafic GetClientRect(hwnd,&rect); //Obinerea suprafeei de desenare //Scrierea unui text n fereastr

TextOut(hdc,50,50,sir,lungime); EndPaint(hwnd, &ps); return 0;

iruri de caractere Majoritatea funciilor WinApi care permit afiarea de text, utilizeaz tipul LPCSTR. Pot transforma un sir char* s=sir de caractere la tipul acesta n dou moduri:
TEXT(sir de caractere) Lsir de caractere

Dac vreau sa afiez un ir de caractere care conine i valorile unor variabile pot folosi afiarea cu format, n care utilizez specificatori de format, similar ca n C. Pentru aceasta utilizez clasa CString pentru care trebuie importate
#include <atlbase.h> #include <atlstr.h>

Exemplu:
CString sir; sir.format(Avem variabila a=%d si b=%lf,a,b); DrawText(hdc,sir,-1,&rect,DT_CENTER|DT_VCENTER);

2.4. Operaii grafice


(1) Culori: O culoare este un obiect de tip COLORREF. Fiecare culoare este alctuit din trei culori de baz, care sunt amestecate n diferite proporii. Cele trei culori de baz sunt rou (R = red), verde (G = green) i albastru (B = blue). Acest sistem se numete sistemul RGB. O culoare se obine prin funcia RGB(r,g,b) unde r = valoarea pentru rou, g = valoarea pentru verde, b = valoarea pentru albastru. Fiecare variabil de culoare poate avea valori ntre 0 i 255, acestea reprezentnd cantitatea de culoare din culoarea respectiv (nuana). Valoarea 0 apropie culoarea de negru, iar 255 reprezint culoarea pur. Dac am r = g = b obin diferite tonuri de gri, unde (0,0,0) este negru i (255,255,255) este alb. Dac dou dintre componente sunt egale, de exemplu g = b, obin nuane din componenta a treia, n cazul nostru de rou. Cu ct valorile g = b sunt mai mari (mai aproape de 255) obin o nuan mai deschis de roz, mai aproape de alb.

(2) Penie i pensule Se face cu penia (pen) curent iar umplerea de suprafee se face cu pensula (brush) curent. Alegerea acestora se va discuta n cele ce urmeaz: (a) Crearea unei penie:
HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF color);

unde fnPenStyle stilul care poate fi: PS_SOLID : linie continu PS_DASH : linie ntrerupt PS_DOT : linie punctat PS_DASHDOT: linie format din puncte i liniue etc.

nWidth limea liniei (n pixeli) color culoarea folosit (de tip RGB) (b) Crearea unei pensule se poate face cu 4 funcii diferite, dintre care vom prezenta dou: Pensul cu umplere uniform:

HBRUSH CreateSolidBrush(COLORREF color);

Pensul haurat:
HBRUSH CreateHatchBrush(int fnBrushStyle, COLORREF color);

unde fnBrushStyle stilul pensulei poate fi: HS_HORIZONTAL HS_VERTICAL HS_BDIAGONAL HS_FDIAGONAL HS_CROSS HS_DIAGCROSS

Aceste funcii creeaz obiectele respective (pen sau brush). Pentru a utiliza efectiv un astfel de obiect el trebuie selectat ca fiind obiectul curent cu ajutorul funciei SelectObject. Atunci cnd un obiect HPEN sau HBRUSH este selectat, el devine obiectul curent, desenarea efectundu-se cu el. Atenie: Funcia SelectObject returneaz obiectul (pen /brush/alt obiect) curent anterior, pentru ca acesta s poat fi selectat din nou, dup ce nu mai este necesar obiectul creat de noi. Atunci cnd nu mai avem nevoie de un obiect creat de noi, se recomand restaurarea obiectului anterior i distrugerea obiectului nostru. Exemplu: //n cadrul procedurii de fereastr:
HPEN pen; HPEN old_pen; HBRUSH br1, br2, old_br; switch (message) { case WM_PAINT: hdc = BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect); //crearea noii penite pen = CreatePen(PS_SOLID,2,RGB(0,0,255)); //pastrarea penitei vechi old_pen=(HPEN)SelectObject(hdc,pen); //crearea a doua pensule noi br1=CreateSolidBrush(RGB(255,33,33)); br2=CreateHatchBrush(HS_CROSS, RGB(33,255,33)); //pastrarea pensulei vechi old_br=(HBRUSH)SelectObject(hdc,br1);

//instructiuni de desenare // //restaurarea obiectelor anterioare SelectObject(hdc,old_pen); SelectObject(hdc,old_br); //stergerea obiectelor create DeleteObject(pen); DeleteObject(br1); DeleteObject(br2); EndPaint(hwnd,&ps); return 0; //celelalte optiuni din switch default: return DefWindowProc(hwnd,message,wParam,lParam); }

(3) Desenarea de puncte (pixeli):


SetPixel(HDC hdc, int x, int y, COLORREF color);

Exemplu:
case WM_PAINT: hdc=BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect); //Desenarea unei sinusoide coef=(rect.bottom-rect.top)/2; for(x=rect.left;x<=rect.right;x++) { y=coef*(sin(3.14*x/180)+1); SetPixel(hdc,x,y,RGB(0,0,0)); } EndPaint(hwnd,&ps); return 0;

(4) Desenarea liniilor:


MoveToEx(HDC hdc, int x, int y, LPPOINT pt); LineTo(HDC hdc, int x, int y);

Funcia MoveToEx() permite poziionarea ntr-un anumit punct al ferestrei, dat prin coordonatele (x,y). Acest punct va fi punctul de start pentru linia care se va trasa. Funcia LineTo() permite trasarea unei linii de la punctul curent (la care ne-am deplasat de exemplu cu funcia MoveToEx() sau cu alt instruciune de desenare) la punctul determinat de coordonatele (x,y) date de parametrii funciei. Observaie: Ultimului parametru n cazul funciei MoveToEx i se va da valoarea NULL.

Exemplu:
case WM_PAINT: hdc=BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect); //Desenarea unei sinusoide coef=(rect.bottom-rect.top)/2; MoveToEx(hdc,0,coef,NULL); for(x=rect.left+1;x<=rect.right;x++) { y=coef*(sin(3.14*x/180)+1); LineTo(hdc,x,y); } EndPaint(hwnd,&ps); return 0;

(5) Desenarea dreptunghiurilor:


Rectangle(HDC hdc, int x1, int y1, int x2, int y2);

unde: (x1,y1),(x2,y2) definesc coordonatele colurilor stnga-sus i dreapta-jos ale dreptunghiul. (6) Desenarea elipselor (cercurilor):
Ellipse(HDC hdc, int x1, int y1, int x2, int y2);

unde: (x1,y1),(x2,y2) definesc dreptunghiul circumscris elipsei. (x1,y1) sunt coordonatele colului stnga sus (sau dreapta jos) al dreptunghiului circumscris, iar (x2,y2) sunt coordonatele colului diagonal opus lui (x1,y1). Pentru a desena un cerc este suficient ca: |x1-x2|=|y1-y2|, adic dreptunghiul circumscris s fie ptrat. Observaie: contururile formelor vor fi desenate cu penia curent iar umplerea se va face cu pensula curent. n mod predefinit penia curent este linie continu, neagr de grosime 1 iar pensula curent are culoarea fundalului (n general alb);

3. Operaii cu Mouse-ul
Vom considera mouse-uri cu 2 butoane (butonul stng i butonul drept). Exist urmtoarele aciuni care pot avea loc n cazul unui mouse: click: - apsare i eliberare a unui buton de mouse double-click: - apsare i eliberare de dou ori n interval foarte scurt de timp a unui buton de mouse move: - deplasarea mouse-ului drag: - deplasarea mouse-ului n timp ce se ine apsat una dintre taste

Pentru butoane se utilizeaz urmtoarele prescurtri: LBUTTON butonul stng RBUTTON - butonul drept. n cazul aciunii mouse-ului, fereastra noastr primete mesaje corespunztoare, n funcie de aciune i de locaia la care se afla mouse-ul. Sunt prezentate n continuare numai acelea dintre mesajele generate de mouse care pot prezenta interes. Procedura de fereastr primete mesaje de la mouse i atunci cnd mouse-ul este poziionat n zona client a ferestrei, dar i atunci cnd este poziionat n afara zonei client. Sunt prezentate doar mesajele primite atunci cnd ne aflm n zona client.

List de mesaje: Mesaj WM_LBUTTONDOWN WM_RBUTTONDOWN WM_LBUTTONUP WM_RBUTTONUP WM_LBUTTONDBLCLK WM_RBUTTONDBLCLK WM_MOUSEMOVE Descriere butonul stng este apsat butonul drept este apsat butonul stng este eliberat butonul drept este eliberat a doua apsare a butonului stng a doua apsare a butonului drept mouse-ul este deplasat

Atunci cnd procedura de fereastr primete un mesaj de la mouse, parametrul lParam conine coordonatele poziiei mouse-ului la momentul generrii mesajului. Parametrul

lParam este mprit n dou secvene a cte 16 bii: partea low (inferioar) conine coordonata orizontal x - i parte high (superioar) conine coordonata vertical y. Acestea se obin cu ajutorul macrourilor LOWORD() i HIGHWORD(). x = LOWORD(lParam); y = HIWORD(lParam); Exemplu: Scriem doar procedura de fereastr, restul este similar ca la primul exemplu:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { POINT p1; static POINT p2; HDC hdc; RECT rect; switch (message) { case WM_LBUTTONDOWN: p1.x=LOWORD(lParam); p1.y=HIWORD(lParam); hdc=GetDC(hwnd); //Obtinerea contextului grafic Ellipse(hdc,p2.x-5,p2.y-5,p2.x+5,p2.y+5); MoveToEx(hdc,p2.x,p2.y,NULL); LineTo(hdc,p1.x,p1.y); p2=p1; ReleaseDC(hwnd,hdc); //Eliberarea contextului grafic return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: } return 0; return DefWindowProc(hwnd, message, wParam, lParam);

} Parametrul wParam conine informaii referitoare la apsarea anumitor taste (SHIFT sau CTRL) i la apsarea butoanelor de mouse. Acest parametru poate fi o combinaie (sau pe bii) ntre valorile: MK_CONTROL MK_SHIFT - tasta control este apsat - tasta shift este apsat

MK_LBUTTON MK_RBUTTON Obs:

- butonul stng al mouse-ului este apsat - butonul drept al mouse-ului este apsat.

- dac (MK_CONTROL & wParam) are valoarea true, nseamn c tasta CTRL este apsat - dac (MK_SHIFT & wParam) are valoarea true, nseamn c tasta SHIFT este apsat etc. Deci pentru a stabili dac una dintre taste este apsat (sau mai multe) este suficient s testm cu un if( ) valoarea i-ului pe bii dintre parametrul wParam i valoarea care ne intereseaz. Exemplu:
static POINT p1, p2; switch (message) { case WM_LBUTTONDOWN: p1.x=LOWORD(lParam); p1.y=HIWORD(lParam); return 0; case WM_MOUSEMOVE: if(wParam & MK_LBUTTON) { hdc=GetDC(hwnd); p2.x=LOWORD(lParam); p2.y=HIWORD(lParam); if (wParam & MK_SHIFT) Ellipse(hdc,p2.x,p2.y,p3.x,p3.y); else Rectangle(hdc,p2.x,p2.y,p3.x,p3.y); ReleaseDC(hwnd,hdc); } return 0; default: return DefWindowProc(hwnd, message, wParam, lParam); }

Observaii: 1. Privind mesajul WM_MOUSEMOVE: Atunci cnd mouse-ul este deplasat se genereaz la un interval foarte mic o multitudine de mesaje WM_MOUSEMOVE. Sistemul nu le poate prelucra cu aceeai vitez cu care sunt generate. Pentru a evita suprancrcarea cozii de mesaje, atunci cnd la primirea unui mesaj WM_MOUSEMOVE n coada de mesaje se mai afl un

astfel de mesaj, acesta dinainte este ters. Astfel nct numrul de mesaje de acest tip care sunt prelucrate efectiv este mai mic dect numrul de mesaje generate n total la deplasarea cursorului. 2. Privind double-click: Un mesaj WM_LBUTTONDBLCLK (respectiv WM_RBUTTONDBLCLK) va fi generat numai dac durata dintre dou apsri succesive a butonului este suficient de mic i dac n clasa ferestrei stilul a fost definit ca CS_DBLCLKS: Exemplu:
wcmain.style=CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

n acest caz apsarea de dou ori la interval scurt a butonului stng va genera urmtoarea secven de mesaje: WM_LBUTTONDOWN WM_LBUTTONUP - la prima apsare a butonului - la eliberarea butonului

WM_LBUTTONDBLCLK - la a doua apsare a butonului WM_LBUTTONUP Structura POINT Structura POINT reprezint un obiect de tip punct, cu dou coordonate, x i y. Structura are deci dou cmpuri x i y i este definit n fiierul windows.h.

- la eliberarea butonului

5. Casete de dialog
5.1. Crearea unei casete de dialog Se alege opiunea de menu Insert-Resource-Dialog (sau n Resource-View cu click-dreapta). Apare un Wizzard pentru crearea unui dialog. Cu ajutorul acestuia se pot aduga diferite controale, precum butoane, casete de validare, butoane radio, casete text etc. Fiecare control are un numr de identificare (ID). De asemenea caseta de dialog primeste un ID. 5.2. Apelarea unei casete de dialog se realizeaz cu ajutorul funciei
BOOL CALLBACK DialogBoxParam(HI NSTANCE hInstance, LPCSTR nume_box, HWND parent, DLGPROC ProcDialog, LPARAM dwInitParam);

sau
BOOL CALLBACK DialogBoxParam(HI NSTANCE hInstance, LPCSTR nume_box, HWND parent, DLGPROC ProcDialog);

unde: hInstance instana programului nume_box numele casetei de dialog, care n general se obien cu MAKEINTRESOURCE(IDD_DIALOG) (IDD_DIALOG ID-ul casetei de dialog) parent fereastra de care aparine caseta de dialog ProcDialog procedura de ferastr asociat casetei de dialog dwInitParam primete valoarea NULL Funcia returneaz true sau false, n funcie de al doilea parametru al funciei EndDialog(), care nchide dialogul. Acest fapt permite de exemplu returnarea valorii true cnd se apas butonul OK (dac exist) i a valori false cnd se apas butonul CANCEL (dac exist). 5.3. Procedura de ferastr Se aseamn cu procedura de ferastr pentru fereastra principal. n mesajul WM_COMMAND pot fi tratate mesajele generate de ctre diferitele controale din caseta de dialog.

Exemplu: Binarizare. Se citesc valorile pragurilot T1 i T2 cu ajutorul unei casete de dialog, iar apoi se utilizeaz n cadrul funciei de binarizare (care NU este prezentat n exemplu).

Caseta de dialog arat astfel:

Fiierul care conine procedura de fereastr pentru caseta de dialog i funcia BinaryImage
#include <windows.h> #include "definitions.h" #include "resource1.h" int T1,T2; //Cele dou praguri citite cu ajutorul casetei de dialog

extern HINSTANCE myinstance; //Instanta programului declarat global n //programul principal extern HWND hwndmain; //handle-ul ctre fereastra principal //extern MyGImage prelImage; BYTE *BinaryImage(BYTE *buffer) { //Apelul casetei de dialog cu ID-ul IDD_BINAR if(DialogBoxParam(myinstance, MAKEINTRESOURCE(IDD_BINAR), hwndmain, (DLGPROC)WndBINARDialogProc, NULL)==TRUE) if(T2>T1) return binary(image,T1,T2); else return binary(image,T2,T1); else return NULL; //Dac s-a apsat butonul Cancel } ... ... ... ... //Procedura de fereastr a casetei de dialog BOOL CALLBACK WndBINARDialogProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { int bState; static int ok_cancel=TRUE; //stabileste dac s-a nchis cu OK sau //Cancel switch (message) { case WM_DESTROY: EndDialog(hdlg,ok_cancel); return TRUE; case WM_COMMAND:

switch (LOWORD(wParam)) { case IDOK: //S-a apsat OK //Functie care citeste un ntreg dintr-o caset //de text T1 =(int)GetDlgItemInt(hdlg,IDC_T1,&bState,true); if(T1>255) T1=255; if(T1<0) T1=0; T2 =(int)GetDlgItemInt(hdlg,IDC_T2,&bState,true); if(T2>255) T2=255; if(T2<0) T2=0; ok_cancel=TRUE; //Functia care duce la ncheierea dialogului EndDialog(hdlg, true); break; case IDCANCEL: //S-a apsat Cancel ok_cancel=FALSE; EndDialog(hdlg, false); break;

return TRUE; } return FALSE; }

5.4. Controale La caseta de dialog pot fi adugate diferite controale: (1) Butoane: Cnd este apsat un buton se generaz un mesaj de tip WM_COMMAND, iar parametrul wParam transmis ctre procedura de fereastr a dialogului are ca valoatre ID-ul butonului. (2) Butoane radio: Cnd se selecteaz un buton radio se generaz un mesaj WM_COMMAND, iar parametrul wParam transmis ctre procedura de fereastr a dialogului are ca valoatre ID-ul Pentru a creea un grup de butoane radio care se exclud reciproc, trebuie mai nti creat o group-box, iar apoi se introduc pe rnd butoanele radio n aceasta. (3) ExitBox: control de editare Pentru citirea de valori ntregi ntr-un control de editatare pot fi utilizate urmtoarele funcii: (int)GetDlgItemInt(hDlg,IDC_Text,NULL,true); (int)GetDlgItemInt(hDlg,IDC_Text,&nr,true); Ultimul parametru este true atunci cnd se dorete i citirea de numere negative. Altfel este false.

Pentru citirea unui text (ir de caractere) utilizm funcia:


GetWindowText(GetDlgItem(hDlg,IDC_ControlText),sir_caractere,lu ngime_sir); GetDlgItemText()?

Handle-ul unui control se obine cu ajutorul funciei:


HWND GetDlgItem(HWND hDlg, LPCSTR ID_Control);

S-ar putea să vă placă și