Documente Academic
Documente Profesional
Documente Cultură
utilizatori i pentru programatori, deoarece sarcina dezvoltatorilor unui program este s ofere
utilizatorilor lucruri de care acetia au nevoie.
CONCEPTELE I FUNDAMENTELE GUI
La nceput, ecranul era folosit numai pentru afiarea informaiilor pe care utilizatorul le
introducea de la tastatur. ntr-o interfa grafic, ecranul devine chiar o surs pentru celelalte
intrri ale utilizatorului. Pe ecran sunt afiate diferite obiecte grafice sub forma pictogramelor i
a unor dispozitive de intrare, precum butoanele i barele de derulare. Folosind tastatura (sau, mai
direct, un dispozitiv de indicare precum mouse-ul) utilizatorul poate s manipuleze direct aceste
obiecte de pe ecran. Obiectele grafice pot fi deplasate, butoanele pot fi apsate i barele de
derulare pot fi derulate.
Interaciunea dintre program i utilizator devine mult mai direct. n locul unui ciclu
unidirectional al informaiilor de la tastatur la program i de la program la ecran, utilizatorul
interacioneaz direct cu obiectele de pe ecran.
Apelurile de funcii
Windows 95 asigur suportul pentru mai mult de o mie de apeluri de funcii pe care le pot
folosi aplicaiile.
Fiecare funcie Windows are un nume sugestiv, scris att cu majuscule, ct i cu minuscule,
cum ar fi CreateWindow. Aceast funcie, aa cum probabil v-ai dat seama, creeaz o fereastr.
Un alt exemplu: funcia IsClipboardFormatAvailable determin dac n memoria temporar
(clipboard) sunt stocate date ntr-un anumit format.
Toate funciile Windows importante sunt declarate n fiiere antet. Principalul fiier antet se
numete WINDOWS.H i include multe alte fiiere antet. Aceste fiiere antet sunt furnizate de
orice mediu de programare pentru Windows 95, aa cum este, de pild, C. Fiierele antet sunt o
parte important a documentaiei Windows. Putei s tiprii o copie a fiierelor antet sau s
folosii un browser pentru o cutare rapid.
n programele pentru Windows folosii apelurile de funcii la fel cum folosii funciile de
bibiotec C, cum ar fi strlen. Principala diferen este faptul c n cazul funciilor C codul
funciilor este legat direct de codul programului, pe cnd codul funciilor Windows este stocat n
fiiere din afara programului, numite biblioteci cu legturi dinamice (DLL - dynamic link
libraries).
Arhitectura bazat pe mesaje
n Windows, atunci cnd utilizatorul redimensioneaz o fereastr, sistemul de operare trimite
programului un mesaj prin care i comunic noile dimensiuni ale ferestrei. Programul poate apoi
s modifice coninutul ferestrei, astfel nct acesta s se adapteze la noile dimensiuni.
Windows apeleaz o funcie din program. Parametrii acestei funcii descriu mesajul respectiv.
Aceast funcie din programul Windows este cunoscut sub numele de procedur de fereastr"
(window procedure").
Procedura de fereastr
Orice fereastr creat de un program are asociat o procedur de fereastr. Procedura de
fereastr este e funcie care se poate afla chiar n program sau ntr-o bibliotec cu legturi
dinamice (DLL). Windows trimite un mesaj ctre o fereastr prin apelarea procedurii de
fereastr. Procedura de fereastr prelucreaz anumite informaii pe baza mesajului primit, apoi
returneaz controlul sistemului de operare.
Mai precis, o fereastr este creat ntotdeauna pe baza unei clase de fereastr". Clasa
specific procedura de fereastr care prelucreaz mesajele trimise ctre fereastr. Folosirea unei
clase de fereastr permite ca pe baza aceleiai clase s se creeze mai multe ferestre care, ca
urmare, folosesc aceeai procedur de fereastr. De exemplu, toate butoanele din toate
programele pentru Windows sunt create pe baza aceleiai clase de fereastr. Aceast clas are o
3
procedur de fereastr (aflat ntr-una dintre bibliotecile cu legturi dinamice ale sistemului de
operare) care prelucreaz mesajele trimise ctre ferestrele butoanelor.
O procedur de fereastr prelucreaz mesajele trimise ferestrei respective. Deseori, aceste
mesaje informeaz fereastra cu privire la aciunile executate de utilizator cu ajutorul mouse-ului
sau al tastaturii. Aceasta este calea prin care o fereastr afl", de exemplu, c un buton a fost
apsat. Alte mesaje comunic ferestrei c a fost redimensionat sau c trebuie s fie refcut.
Atunci cnd un program este lansat n execuie, Windows creeaz o coad de mesaje"
(message queue") pentru programul respectiv, n aceast coad de mesaje sunt pstrate mesajele
trimise ctre toate ferestrele pe care le creeaz programul. Programul conine o mic secven de
cod numit ciclu de mesaje" (message loop") care preia mesajele din coada de ateptare i le
distribuie procedurilor de fereastr corespunztoare. Alte mesaje sunt trimise direct procedurii de
fereastr, fr s mai fie plasate n coada de mesaje.
WinMain si WinProc
Fiierul conine numai dou funcii: WinMain i WndProc. Funcia WinMain reprezint
punctul de intrare n program. Aceasta este echivalentul funciei main din programele scrise n
limbajul C. Orice program pentru Windows trebuie s aib o funcie WinMain.
WndProc este procedura de fereastr" a ferestrei create de programu. Orice fereastr indiferent dac este fereastra principal a aplicaiei sau fereastra unui mic buton de apsare - are
o procedur de fereastr. Procedura de fereastr este un mod de ncapsulare a codului care
rspunde intrrilor (n general de la tastatur i de la mouse) i afieaz elementele grafice pe
ecran. Aa cum vei vedea, procedura de fereastr face acest lucru prin prelucrarea mesajelor"
trimise ctre fereastr
Nici o instruciune din fiierul HELLOWIN.C nu apeleaz direct funcia WndProc: WndProc
este apelat de sistemul de operare Windows. Totui, n funcia WinMain apare o referire la
funcia WndProc, acesta fiind motivul pentru care WndProc este declarat n partea de nceput a
programului, nainte de WinMain
1.
n mod normal, Windows creeaz un nou context de dispozitiv cu valori prestabilite atunci
cnd apelai una dintre funciile GetDC sau BeginPaint. Toate modificrile fcute n atributele
contextului de dispozitiv se pierd atunci cnd contextul de dispozitiv este ters din memorie prin
apelarea funciei ReleaseDC sau a funciei EndPaint. Dac programul trebuie s foloseasc un
atribut cu o valoarea diferit de cea prestabilit va trebui s iniializai contextul de dispozitiv de
fiecare dat cnd obinei o variabil handle:
caseWM_Paint:
hd = BeginPaint (hwnd, &ps);
[iniializeaz atributele contextului de dispozitiv] [deseneaz zona client a ferestrei]
EndPaint (hwnd, &ps);
return 0;
);
Functia Rectangle deseneaza un dreptunghi cu penula selectata si il umple cu culoare cu periuta selectata
Rectangle(hdc, 25, 30, 100, 50)
Cronometrul Windows este un dispozitiv de intrare, ce comunic periodic unei aplicaii trecerea unui
anumit interval de timp. Programul specific sistemului de operare acest interval de timp, spunndu-i
ceva de genul: F-mi un semn la fiecare 10 secunde". Windows trimite periodic programului, mesaje
WM_TIMER prin care i semnaleaz trecerea intervalului de timp respectiv.
Iat cteva alte utilizri sub Windows ale cronometrului, dei s-ar putea ca unele s nu fie att de
evidente:
Multitaskingul - Dei Windows 95 este un mediu cu multitasking controlat, uneori este mult mai
eficient ca un program s returneze controlul sistemului de operare, imediat ce este posibil.
Dac programul trebuie s execute o operaie de durat, o poate mpri n operaii mai mici, pe
care s le prelucreze la primirea unui mesaj WM_TIMER.
6
3.
Actualizarea unui raport de stare - Un program poate s utilizeze cronometrul pentru afiarea
n timp real" a unor informaii care se schimb continuu, n funcie de resursele sistemului sau
de evoluia unei anumite operaii.
nchiderea versiunilor demonstrative ale unui program - Unele versiuni demonstrative ale
programelor sunt proiectate astfel nct s-i ncheie execuia, de exemplu, dup trecerea a 30 de
minute de la lansare. Cronometrul poate s semnaleze unei astfel de aplicaii terminarea timpului
permis de rulare.
Deplasri succesive - Obiectele grafice dintr-un joc sau imaginile afiate succesiv de un
program de instruire asistat de calculator trebuie s fie prelucrate la anumite intervale de
timp. Folosirea cronometrului elimin inconsecvenele care pot aprea datorit diferenelor
dintre viteza de lucru a microprocesoarelor.
Care este punctul de intrare ntr-un program Windows? W?
Funcia WinMain reprezint punctul de intrare n program. Aceasta este echivalentul funciei
main din programele scrise n limbajul C. Orice program pentru Windows trebuie s aib o
funcie WinMain.
Totui, n funcia WinMain apare o referire la funcia WndProc, acesta fiind motivul pentru
care WndProc este declarat n partea de nceput a programului, nainte de WinMain.
Funcia WinMain este de tipul WINAPI. Punctul de intrare ntr-un program Windows este
o funcie numit WinMain. Funcia WinMain este ntotdeauna definit astfel:
int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
4.
c
by
n
i
x, y
cx, cy
b sau f
w
l
dw
fn
s
sz
h
p
6.
char
BYTE (unsigned char)
short
int
int (folosit pentru coordonate)
int (folosit pentru dimensiuni pe axele x si y, c vine de la contor")
BOOL (int); f vine de la flag" (indicator)
WORD (unsigned short)
LONG (long)
DWORD (unsigned long)
funcie
ir de caractere
sir de caractere terminat cu zero
variabil handle
pointer
7.
Programarea orientat eveniment este o paradigm a programrii calculatoarelor. Spre deosebire de programele
tradiionale, care-i urmeaz propria execuie, schimbndu-i cteodata doar cursul n puncte
de ramificaie (instruciuni test, etc), cursul execuiei unui program orientat eveniment este condus n mare parte de
evenimente externe.
Programele orientate eveniment sunt formate de obicei dintr-un numr de programe mici numite handlere de
eveniment, care sunt apelate ca rspuns la evenimente externe i dintr-un coordonator (dispatcher), care apeleaz
handlerele de evenimente, folosind de obicei o coad a evenimentelor, care s rein evenimentele care nu au fost
procesate.
n multe cazuri, handlerele de evenimente pot declana ele nsele evenimente, ducnd la o cascad de evenimente.
Programarea orientat eveniment accentueaz ca virtui flexibilitatea i asincronicitatea.
Programele cu interfee grafice sunt de obicei programate ntr-o modalitate gestionat de evenimente. Sistemele de
operare sunt un alt exemplu clasic de programe dirijate de evenimente pe cel puin dou nivele. La cel mai de jos
nivel, handlerele de ntreruperi se comport ca handlere de evenimente hardware, cu procesorul n rol de
coordonator (dispatcher). Sistemele de operare, de asemenea se comport ca i coordonatori pentru procese,
transmind datele i ntreruperile soft ctre procese user, care de multe ori sunt programate ca i handlere de
eveniment.
8.
Contextul de dispozitiv (prescurtat DC - device context) este o structur de date ntreinut intern de interfaa GDI.
Fiecare context de dispozitiv este asociat unui anumit dispozitiv de afiare, cum ar fi imprimanta, plotterul sau
monitorul video. n cazul monitoarelor video, un context de dispozitiv este de obicei asociat unei anumite ferestre de
pe ecran
9.
Programele trebuie s cedeze voluntar controlul, astfel nct alte programe s-i poat
continua execuia. n Windows 95 multitaskingul este controlat i programele se pot mpri n
mai multe fire de execuie, care par s ruleze n acelai timp.
10.
Secvena de cod din exemplul urmtor afieaz o caset de mesaje atunci cnd funcia SetTimer nu
poate aloca programului un cronometru:
fereastr. Procedura de fereastr prelucreaz anumite informaii pe baza mesajului primit, apoi
returneaz controlul sistemului de operare.
Mai precis, o fereastr este creat ntotdeauna pe baza unei clase de fereastr". Clasa
specific procedura de fereastr care prelucreaz mesajele trimise ctre fereastr. Folosirea unei
clase de fereastr permite ca pe baza aceleiai clase s se creeze mai multe ferestre care, ca
urmare, folosesc aceeai procedur de fereastr. De exemplu, toate butoanele din toate
programele pentru Windows sunt create pe baza aceleiai clase de fereastr. Aceast clas are o
procedur de fereastr (aflat ntr-una dintre bibliotecile cu legturi dinamice ale sistemului de
operare) care prelucreaz mesajele trimise ctre ferestrele butoanelor.
12.
Clasa butoanelor.
13.
Coduri virtuale de taste. Starea tastelor de modificare. Utilizarea mesajelor de acionare a tastelor.
. -.
.
Identificator
WINDOWS.H
1
2
3
4
8
9
12
01
02
03
04
08
09
0C
VK_BUTTON
13
16
17
18
0D
10
11
12
VK_RETURN
VK_SHIFT
VK_CONTROL
VK_MENU
VK_RBUTTON
VK_CANCEL
VK_MBUTTON
VK_BACK
VK_TAB
VK_CLEAR
Necesar
Tastatur IBM
Ctrl-Break
Backspace
Tab
Tasta numeric 5 cu
tasta
Num Lock inactiv
Enter
Shift
Ctrl
Alt
returneaz o valoare negativ (adic un numr n care primul bit are valoarea 1) dac tasta Shift
este apsat. Valoarea returnat de apelul:
GetKeyState (VK_CAPITAL) ;
are un 1 n bitul cel mai puin semnificativ dac tasta Caps Lock este activ. De asemenea, putei
s obinei starea butoanelor mouse-ului folosind codurile virtuale VK_LBUTTON,
VK_MBUTTON i VK_RBUTTON. Totui, majoritatea programelor pentru Windows care
trebuie s monitorizeze combinaiile ntre taste i butoanele mouse-ului utilizeaz calea invers verificnd starea tastelor atunci cnd primesc un mesaj de la mouse. De fapt, starea tastelor de
10
modificare este inclus n mesajele primite de la mouse (aa cum vei vedea n capitolul
urmtor).
Utilizarea mesajelor de acionare a tastelor
n general, programele pentru Windows folosesc mesajele WM_KEYDOWN pentru tastele
care nu genereaz caractere. Dei s-ar putea s v vin ideea s folosii mesajele pentru acionri
de taste n combinaie cu informaiile despre tastele de modificare (furnizate de funcia
GetKeyState) ca s transformai mesajele pentru acionri de taste n mesaje pentru caractere, nu
facei acest lucru. Vei avea probleme datorit diferenelor ntre tastaturile internaionale. De
exemplu, dac primii un mesaj WM_KEYDOWN pentru care parametrul wParam are valoarea
33H, tii c utilizatorul a apsat tasta 3. Pn aici totul este bine. Dac apelai funcia
GetKeyState vei afla c tasta Shift este apsat i s-ar putea s presupunei c utilizatorul a
introdus un caracter diez (#), lucru care poate s nu fie adevrat. Un utilizator britanic ar fi
introdus caracterul . Mesajele WM_KEYDOWN sunt utile pentru tastele de deplasare, tastele
funcionale i tastele speciale, precum Insert, Delete. Uneori tastele Insert, Delete si tastele
funcionale sunt folosite ca acceleratori pentru comenzi de meniu. Deoarece Windows
transform acceleratorii n comenzi de meniu, nu este nevoie s prelucrai n program mesajele
pentru acionarea tastelor de accelerare. Unele programe non-Windows folosesc foarte des tastele
funcionale n combinaie cu tastele Alt, Ctrl i Shift. Putei face acest lucru i n programele
pentru Windows, dar nu este recomandat. Dac vrei s folosii tastele funcionale, acestea
trebuie s dubleze comenzi din meniuri. Unul dintre obiectivele sistemului de operare Windows
este s nu oblige utilizatorii s memoreze sau s foloseasc liste complicate de comenzi.
14.
Programul BTNLOOK definete o structur numit button care conine stilurile de fereastr ale
butoanelor i iruri de caractere descriptive pentru fiecare dintre cele 10 tipuri de butoane. Stilurile de
fereastr ale butoanelor ncep cu literele BS_ care sunt o prescurtare de la button style".
Cele 10 ferestre descendent sunt create ntr-un ciclu for n cadrul procedurii WndProc, n timpul
prelucrrii mesajului WM_CREATE. Apelul funciei CreateWindow folosete urmtorii parametri:
Class name (numele clasei)
"button"
Window text (textul ferestrei)
button[i].text
Window style (stilul ferestrei)
WS_CHILD|WS_VISIBLE|button[i].style
x position (poziia x)
cxChar
y position (poziia y)
cyChar * (1 + 2 * i)
Width (lime)
20 * cxChar
Height (nlime)
7*cyChar/4
Parent window (fereastra printe)
hwnd
Child window ID (identificatorul ferestrei descendent)
(HMENU) i
Instance handle (variabila handle a instanei)
((LPCREATESTRUCT) lParam) -> hlnstance
Extra parameters (ali parametri)
NULL
Parametrul care reprezint numele clasei este numele predefinit. Pentru stilul ferestrei sunt
folosite valorile WS_CHILD, WS_VISIBLE sau unul dintre cele zece stiluri de butoane
(BS_PUSHBUTTON, BS_DEFPUSHBUTTON i aa mai departe), definite n structura button. Textul
ferestrei (care pentru o fereastr normal apare n bara de titlu) este textul care va fi afiat pe fiecare
buton. n acest exemplu am folosit textul care identific stilul butonului.
Parametrii x i y indic poziia colului din stnga-sus al ferestrei descendent, raportat la colul
din stnga-sus al zonei client a ferestrei printe. Parametrii width i height specific limea i nlimea
fiecrei ferestre descendent.
Identificatorul ferestrei descendent (ID) trebuie s fie unic pentru fiecare fereastr descendent.
Acest identificator permite procedurii ferestrei printe s identifice fereastra descendent atunci cnd
11
16.
O curb Bezier este definit prin patru puncte - dou capete i dou puncte de control.
Capetele curbei sunt ancorate n cele dou puncte finale. Punctele de control acioneaz ca
nite magnei" care deformeaz linia dreapt dintre cele dou puncte finale
Funcia PolyBezierTo folosete poziia curent ca punct de nceput pentru prima curb
Bezier. Fiecare curb desenat are nevoie doar de trei puncte. La returnarea funciei,
poziia curent este punctul final al ultimei curbe desenate
17.
Cursorul de editare (CARET). Funcii pentru cursorul de editare. Soluia Unicode pentru Windows.
(CARET). . Unicode
Windows.
18.
Cele apte funcii Windows pentru desenarea figurilor sunt prezentate n tabelul urmtor:
Funcie
Figura
Rectangle
Ellipse
RoundRect
Chord
Pie
Polygon
PolyPolygon
fondului, culoarea fondului i modul de desenare, ca i n cazul desenrii unei linii simple. Tot
ceea ce ai nvat despre linii se aplic i n cazul contururilor.
Figurile sunt umplute folosind pensula selectat n contextul de dispozitiv. n mod prestabilit,
aceasta este pensula de stoc WHITE_BRUSH, ceea ce nseamn c interiorul figurilor va fi
umplut cu alb. Windows definete ase pensule de stoc: WHITE-_BRUSH, LTGRAY_BRUSH,
GRAY_BRUSH,
DKGRAY_BRUSH,
BLACK_BRUSH
i
NULL_BRUSH
(sau
HOLLOW_BRUSH).
Putei s selectai una dintre aceste pensule n contextul de dispozitiv la fel cum selectai o
peni de stoc. Windows definete tipul HBRUSH ca variabil handle a unei pensule, aa c
putei s definii mai nti o variabil de acest tip:
HBRUSH hBrush ;
Parametrul pt este un pointer la o matrice de structuri POINT, iar iCount reprezint numrul
de puncte din matrice. Dac ultimul punct din matrice este diferit de primul punct, Windows mai
deseneaz o linie care conecteaz ultimul i primul punct. (Acest lucru nu se ntmpl i n cazul
funciei Polyline.)
Suprafaa nchis de poligon este colorat folosind pensula curent n dou moduri, n funcie
de modul de umplere a poligoanelor, definit n contextul de dispozitiv. Modul prestabilit de
umplere a poligoanelor este ALTERNATE, ceea ce nseamn c Windows coloreaz numai
suprafeele nchise la care se poate ajunge din exteriorul poligonului prin traversarea unui numr
impar de laturi (1, 3, 5 i aa mai departe). Celelalte suprafee interioare nu sunt umplute. Dac
selectai WINDING ca mod de umplere, Windows coloreaz toate suprafeele nchise de poligon.
Putei s selectai modul de umplere cu ajutorul funciei SetPolyFillMode:
SetPolyFillMode (hdc, iMode) ;
Cele dou moduri de umplere a poligoanelor sunt ilustrate cel mai bine pe modelul unei stele
cu cinci coluri. n Figura 4-17 steaua din partea stng a fost desenat cu modul de umplere
ALTERNATE, iar steaua din partea dreapt a fost desenat cu modul de umplere WINDING.
13
Figura 4-17. Figuri desenate cu cele dou moduri de umplere a poligoanelor ALTERNATE
(stng) i WINDING
Umplerea suprafeelor interioare
Interiorul figurilor Rectangle, RoundRect, Ellipse, Chord, Pie, Polygon i PollyPolygon este
umplut cu pensula - numit uneori i model" (pattern") - selectat n contextul de dispozitiv. O
pensul este de fapt o imagine bitmap 8x8 repetat pe vertical i pe orizontal, pentru umplerea
unei suprafee.
19.
14
Figura 3-3. Cele cinci valori care definesc dimensiunea verticala a unui caracter.
Acestea sunt uor de neles. Valoarea tmInternalLeading se refer la spaiul pstrat deasupra
unui caracter pentru semnele de accentuare. Dac aceast valoare este zero, literele mari cu
accent sunt afiate ceva mai mici, astfel nct accentul s ncap n partea de sus a caracterului.
Valoarea tmExternalLeading se refer la spaiul recomandat de ctre proiectantul fontului a fi
lsat ntre rndurile de text. Putei s acceptai sau nu aceast recomandare atunci cnd stabilii
distana dintre rndurile de text.
Structura TEXTMETRIC conine dou cmpuri care descriu limea unui caracter:
tmAveCharWidth (limea medie a literelor mici) i tmMaxCharWidth (limea celui mai
mare caracter al fontului). Pentru fonturile cu dimensiune fix cele dou valori sunt egale.
Este important s reinei faptul c dimensiunile fontului sistem depind de rezoluia ecranului
pe care ruleaz sistemul de operare Windows. Windows furnizeaz o interfa grafic
independent de dispozitiv, dar este nevoie de un mic efort i din partea dumneavoastr. Nu
scriei programe Windows care se bazeaz pe ghicirea dimensiunilor unui caracter. Nu
introducei n cod valori fixe. Folosii funcia GetTextMetrics ca s obinei valorile de care avei
nevoie.
20.
15
Aflarea dimensiunilor zonei client a ferestrei este primul pas pentru furnizarea unei metode
de deplasare a textului n zona client atunci cnd aceasta nu este suficient de mare pentru a
cuprinde tot textul afiat.
Barele de derulare
Barele de derulare se numr printre cele mai reuite componente ale unei interfee grafice
pentru mouse; sunt uor de folosit i determin o reacie vizual foarte rapid. Putei s folosii
bare de derulare oriunde afiai ceva - text, imagini, foi de calcul tabelar, nregistrri din baze de
date - pentru care avei nevoie de mai mult spaiu dect este disponibil n zona client a ferestrei.
Barele de derulare sunt poziionale vertical (pentru deplasri n sus i n jos) sau orizontal
(pentru deplasri la stnga i la dreapta). Putei s executai clic pe sgeile de Ia capetele barei
de derulare sau pe zona dintre acestea. Bara de derulare este parcurs longitudinal de o caset
de derulare" care indic poziia aproximativ a prii afiate pe ecran fa de ntregul document.
De asemenea, putei s tragei caseta de derulare cu ajutorul mouse-ului, ca s o mutai ntr-o
anumit poziie. Figura 3-7 prezint modul recomandat de folosire a unei bare de derulare
verticale pentru text.
Programatorii au uneori probleme cu terminologia legat de barele de derulare, deoarece perspectiva lor este
diferit de cea a utilizatorilor: un utilizator care deruleaz un document n jos vrea s aduc pe ecran o parte a
documentului aflat mai jos; pentru aceasta, programul mut de fapt documentul mai sus n raport cu fereastra de pe
ecran. Documentaia Windows i identificatorii definii n fiierele antet se bazeaz, ns, pe perspectiva
utilizatorului: derularea n sus nseamn parcurgerea documentului ctre nceput; derularea n jos nseamn
parcurgerea documentului ctre sfrit.
Este foarte uor s includei n fereastra aplicaiei o bar de derulare orizontal sau vertical.
Tot ce trebuie s facei este s includei identificatorul WS_VSCROLL (derulare vertical) i/sau
WS_HSCROLL (derulare orizontal) n stilul de fereastr din apelul funciei CreateWindow.
Barele de derulare sunt plasate ntotdeauna la marginea de jos sau la cea din dreapta a ferestrei i
se ntind pe toat limea, respectiv nlimea zonei client. Zona client nu include spaiul ocupat
de barele de derulare. Limea unei bare de derulare verticale i nlimea uneia orizontale sunt
constante pentru un driver de afiare dat. Dac avei nevoie de aceste valori, putei s le obinei
(aa cum ai vzut) prin apelarea funciei GetSystemMetrics.
Domeniul i poziia unei bare de derulare
Fiecare bar de derulare are asociate un domeniu" (definit printr-o pereche de numere ntregi care reprezint
valorile maxim i minim) i o poziie" (punctul n care se afl caseta de derulare n domeniul asociat barei de
derulare). Atunci cnd caseta de derulare se afl la captul de sus (sau la captul din partea stng) al barei de
derulare, poziia corespunde valorii minime. Captul de jos (sau captul din partea dreapt) al barei de derulare
reprezint valoarea maxim.
21.
Elemente de baz despre mouse. Funcia GetSystemMetrics (SM_MOUSEPRESENT); cButtons =
GetSystemMetrics (SM_CMOUSEBUTTONS). Parametrul SM_SWAPBUTTON. Zona senzitiv a
indicatorului. . GetSystemMetrics (SM_MOUSEPRESENT);
16
Vizualizai urmtoarea linie n sus
executnd clic aici (coninutul ferestrei se
deplaseaz n jos)
Windows 95 permite folosirea mouse-ului cu un buton, cu dou butoane sau cu trei butoane,
precum i folosirea unui joystick sau a unui creion optic, pentru simularea unui mouse cu un
buton. Deoarece mouse-ul cu un singur buton reprezint un numitor comun, muli programatori
Windows au evitat mult vreme s foloseasc celelalte butoane ale mouse-ului. Totui, mouse-ul
cu trei butoane a devenit un standard de facto, aa c reticena tradiional privind folosirea celui
de-al doilea buton nu mai este justificat. Al doilea buton al mouse-ului este recomandat pentru
apelarea meniurilor de context" - meniuri care apar n fereastr n afara barei de meniu - sau
pentru operaii speciale de tragere (despre care vom discuta n curnd). Putei s determinai dac
mouse-ul este prezent folosind funcia GetSystemMetrics:
fMouse = GetSystemMetrics (SM_MOUSEPRESENT) ;
Variabila fMouse va avea valoarea TRUE (diferit de zero) dac mouse-ul este instalat.
Pentru determinarea numrului de butoane ale mouse-ului instalat, folosii tot funcia
GetSystemMetrics:
cButtons = GetSystemMetrics (SM_CMOUSEBUTTONS) ;
22.
Culorile de sistem
Windows pstreaz 25 de culori de sistem pentru afiarea diferitelor pri ale ecra nului. Putei s
obinei i s stabilii aceste culori cu ajutorul funciilor GetSysColor i SetSysColors. Identificatorii
definii n fiierele antet din Windows specific culorile de sistem. Stabilirea unei culori de sistem cu
ajutorul funciei SetSysColors afecteaz culoarea respectiv numai pe durata sesiunii Windows curente.
Putei s schimbai o parte dintre culorile de sistem folosind seciunea Display a Panoului de control
din Windows (Control Panel) sau modificnd seciunea [colors] din fiierul WIN.INI. Seciunea
[colors] folosete pentru cele 25 de culori de sistem cuvinte cheie (altele dect identificatorii folosii de
funciile GetSysColor i SetSysColors) urmai de valori pentru culorile rou, verde i albastru. Aceste
valori sunt cuprinse n intervalul 0 - 255. Tabelul urmtor prezint modul n care sunt identificate cele 25
de culori de sistem, cu ajutorul identificatorilor folosii de funciile GetSysColor i SetSysColors i al
cuvintelor cheie folosite n fiierul WIN.INI. Tabelul este ordonat cresctor, n funcie de valoarea
constantelor COLOR_ (de la 0 la 24):
17
GetSysColor i SetSysColors
WIN.INI
COLOR_SCROLLBAR
COLOR_BACKGROUND
COLOR_ACTIVECAPTION
COLOR_NACTIVECAPTION
COLOR_MENU
COLOR_WINDOW
COLOR_WINDOWFRAME
COLOR_MENUTEXT
COLOR_WINDOWTEXT
COLOR_CAPTIONTEXT
COLOR_ACTIVEBORDER
COLOR_NACTIVEBORDER
COLOR_APPWORKSPACE
COLOR_HIGHLIGHT
COLOR_HIGHLIGHTTEXT
COLOR_BTNFACE
COLOR_BTNSHADOW
COLOR_GRAYTEXT
COLOR_BTNTEXT
COLOR_NACTIVECAPTIONTEXT
COLOR_BTNHIGHLIGHT
COLOR_3DDKSHADOW
COLOR_3DLIGHT
COLOR_NFOTEXT
COLOR_INFOBK
Scrollbar
Background
ActiveTitle
InactiveTitle
Menu
Window
WindowFrame
MenuText
WindowText
TitleText
ActiveBorder
InactiveBorder
AppWorkspace
Hilight
HilightText
ButtonFace
ButtonShadow
GrayText
ButtonText
InactiveTitleText
ButtonHilight
ButtonDkShadow
ButtonLight
InfoText
InfoWindow
Valorile prestabilite pentru aceste culori sunt furnizate de driverul de afiare. Sistemul de operare
Windows folosete valorile prestabilite, dac acestea nu sunt suprascrise de valorile din seciunea
[colors] a fiierului WIN.INI, care poate fi modificat din Panoul de control.
23.
Executarea unui clic pe aceste butoane determin generarea mesajelor WM_COM-MAND. Pentru
prelucrarea mesajului WM_COMMAND, OWNERDRW apeleaz funcia GetWindcrwRect ca s
stocheze poziia i dimensiunea ntregii ferestre (nu numai a zonei client) ntr-o structur de tip RECT
(dreptunghi). Aceast poziie este definit fa de ecran. OWNERDRW modific apoi cmpurile structurii
n funcie de butonul pe care s-a executat clic. Programul repoziioneaz i redimensioneaz fereas tra prin
apelarea funciei MoveWindow. Aceasta genereaz un nou mesaj WM_SIZE i butoanele sunt
repoziionate n centrul zonei client.
Dac nu ar mai face nimic altceva, programul ar fi complet funcional, dar butoanele nu ar fi vizibile.
Un buton creat cu stilul BS_OWNERDRAW trimite ferestrei printe un mesaj WM_DRAWITEM de
fiecare dat cnd butonul trebuie s fie redesenat. Aceasta se ntmpl la crearea butonului, de fiecare dat
cnd este apsat sau eliberat, cnd obine sau pierde cursorul de intrare i n orice alt situaie cnd trebuie
s fie redesenat.
n mesajul WM_DRAWITEM, parametrul IParam este un pointer ctre o structur de tip
DRAWITEMSTRUCT. Programul OWNERDRW stocheaz acest pointer ntr-o variabil numit pdis.
Aceast structur conine informaiile necesare programului pentru redesenarea butonului. (Aceeai
structur este folosit i pentru casetele list i articolele de meniu desenate de proprietar.) Cmpurile din
structur importante pentru lucrul cu butoane sunt hDC (contextul de dispozitiv al butonului), rcltem (o
structur RECT n care este stocat dimensiunea butonului), CtllD (identificatorul ferestrei controlului) i
UemState (care indic dac butonul este apsat sau dac deine cursorul de intrare).
Programul OWNERDRW ncepe prelucrarea mesajului WM_DRAWITEM prin apelarea funciei
FillRect, pentru a terge suprafaa butonului cu o pensul de culoare alb. Apoi este apelat funcia
FrameRed, care traseaz un chenar negru n jurul butonului. n continuare, OWNERDRW deseneaz cele
patru triunghiuri negre pe buton, prin apelarea funciei Potygon. Aceasta este situaia normal.
Dac butonul este apsat, unul dintre biii cmpului UemState din structura DRAWITEMSTRUCT are
valoarea 1. Putei s testai acest bit folosind constanta ODS_SELECTED. Dac bitul are valoarea 1,
OWNERDRW inverseaz culorile butonului, apelnd funcia InvertRect. Dac butonul deine cursorul
18
de intrare, atunci bitul ODS_FOCUS din cmpul UemState are valoarea 1. n acest caz, programul
OWNERDRW deseneaz o linie punctat n jurul textului afiat de buton, apelnd funcia
DrawFocusRect.
Un avertisment legat de folosirea butoanelor desenate de proprietar: Windows obine contextul de
dispozitiv i l include n structura DRAWITEMSTRUCT. Lsai contextul de dispozitiv n aceeai
stare n care l-ai gsit. Orice obiect GDI selectat n contextul de dispozitiv trebuie s fie deselectat. De
asemenea, avei grij s nu desenai n afara dreptunghiului care definete limitele butonului.
24.
n aceast secven de cod, atunci cnd fereastra printe este avertizat c urmeaz s piard cursorul
de intrare n favoarea uneia dintre ferestrele descendent, apeleaz funcia SetFocus ca s rectige
cursorul de intrare.
Iat o cale mai simpl (dar mai puin evident) de a face acelai lucru:
case WM_KILLFOCUS ;
~ if (hwnd == GetParent ((HW ND) wParam))
SetFocus (hwnd) ;
return 0 ;
25.
Dac nu includei parametrul WS_VISIBLE n clasa ferestrei la crearea ferestrei descendent, aceasta
nu va fi afiat pn cnd nu apelai funcia ShowWindow:
ShowWindow (hwndChild, SW_SHOWNORMAL) ;
Dac includei parametrul WS_VISIBLE n clasa ferestrei, nu este nevoie s apelai funcia
ShowWindow. Totui, prin apelarea funciei ShowWindow putei s mascai o fereastr descendent
afiat:
ShowWindow (hwndChild, SW_HIDE) ;
Pentru controalele de tip buton, aceast aciune are ca efect afiarea cu gri a textului din buton. Butonul
nu mai rspunde la intrrile de la mouse sau de la tastatur. Aceasta este cea mai bun metod de a
indica faptul c opiunea reprezentat de un anumit buton nu este disponibil.
Putei s reactivai o fereastr descendent prin urmtorul apel:
EnableWindow (hwndChild, TRUE) ;
Putei s determinai dac o fereastr descendent este activ sau nu prin urmtorul apel:
IsWindowEnabled (hwndChild) ;
26.
Casetele de validare sunt dreptunghiuri etichetate cu un text; de obicei, textul apare n partea dreapt a
casetei de validare. (Dac la crearea butonului folosii stilul BS_LEFTTEXT, textul apare n stnga
casetei de validare.) De obicei, casetele de validare sunt incluse n aplicaii pentru a permite
utilizatorilor s selecteze diferite opiuni. Casetele de validare funcioneaz ca un comutator: executarea
unui clic ntr-o caset de validare determin apariia unui marcaj de validare; un al doilea clic face ca
marcajul de validare s dispar.
Cele mai cunoscute stiluri de casete de validare sunt BS_CHECKBOX i BS_AUTOCHECKBOX.
Atunci cnd folosii stilul BS_CHECKBOX, v revine dumneavoastr sarcina de aplicare a marcajului
de validare, prin trimiterea unui mesaj BS_SETCHECK. Parametrul wParam trebuie s aib valoarea 1
pentru afiarea marcajului de validare i valoarea 0 pentru tergerea acestuia. Putei s folosii urmtoarea
secven de cod pentru inversarea marcajului de validare la prelucrarea mesajului WM_COMMAND
primit de la control:
SendMessage ((HWND) 1Param, BM_SETCHECK, (WPARAM) SendMessage ((HWND) lParam, BM_GETCHECK, 0, 0), 0) ;
Remarcai folosirea operatorului .' naintea celui de-al doilea apel al funciei SendMessage. Valoarea
lParam este variabila handle a ferestrei descendent, transmis ctre procedura ferestrei prin mesajul
WM_COMMAND. Dac ulterior dorii s aflai starea butonului, trimitei un nou mesaj
BM_GETCHECK. Sau putei s stocai starea curent a casetei de validare ntr-o variabil static din
procedura ferestrei.
Putei s iniializai o caset de validare de tip BS_CHECKBOX cu un X, trimind mesajul
BM_SETCHECK:
SendMessage (hwndButton, BM_SETCHECK, 1, 0) ;
n cazul folosirii stilului BS_AUTOCHECKBOX, controlul este cel care actualizeaz afiarea
marcajului de validare. Procedura ferestrei printe poate s ignore mesajele WM_COMMAND.
Atunci cnd vrei s aflai starea butonului, trimitei ctre acesta mesajul BM_GETCHECK:
iCheck = (int) SendMessage (hwndButton, BM_GETCHECK, 0, 0) ;
iCheck are valoarea TRUE (sau o valoare diferit de 0) dac butonul este validat i valoarea FALSE
(sau 0) n caz contrar.
20
Celelalte dou stiluri de casete de validare sunt BS_3STATE i BS_AUTO3STATE. Aa cum indic i
numele lor, aceste stiluri permit afiarea unei stri tere - culoarea gri din caseta de validare - n cazul
n care trimitei ctre control un mesaj WM_SETCHECK cu parametrul wParam egal cu 2. Culoarea
gri indic utilizatorului c opiunea respectiv este nedeterminat sau irelevant. n acest caz, caseta nu
poate fi validat - cu alte cuvinte, este dezactivat. Totui, caseta de validare continu s trimit
mesaje ctre fereastra printe atunci cnd se execut clic. Vom descrie puin mai trziu metode mai
bune de dezactivare a unei casete de validare.
Caseta de validare este aliniat la partea stng a dreptunghiului i este centrat ntre marginile de
sus i de jos ale acestuia, conform dimensiunilor specificate la apelarea funciei CreateWindow.
Executarea unui clic oriunde n cadrul dreptunghiului determin trimiterea unui mesaj
WM_COMMAND ctre fereastra printe, nlimea minim a casetei de validare este egal cu nlimea
unui caracter. Limea minim este egal cu numrul de caractere din text, plus dou.
27.
Spre deosebire de butoane ,barele de derulare nu trimit mesaje WM_COMMAND ctre fereastra
printe, n schimb, trimit mesaje WM_VSCROLL i WM_HSCROLL, ca i barele de derulare ale
ferestrelor. Atunci cnd prelucrai mesajele primite de la barele de derulare, putei s facei diferena
ntre barele de control ale ferestrelor i controalele de tip bare de derulare cu ajutorul parametrului
IParatn. Acesta va fi 0 pentru barele de derulare ale ferestrelor sau o variabil handle n cazul
controalelor de tip bar de derulare. Cele dou cuvinte care formeaz parametrul wParam au aceeai
semnificaie att pentru barele de derulare ale ferestrelor, ct i pentru controalele de tip bar de
derulare.
Dei barele de derulare ale ferestrelor au lime fix, n cazul controalelor de tip bare de derulare
Windows folosete dimensiunile dreptunghiului specificate la apelarea funciei CreateWindow sau a
funciei MoveWindow. Putei s creai bare de derulare lungi i subiri sau bare de derulare scurte i
late.
Dac vrei s creai controale de tip bare de derulare cu aceleai dimensiuni ca i barele de derulare
ale ferestrelor, putei s folosii funcia GetSystemMetrics ca s obinei nlimea unei bare de
derulare orizontale:
GetSystemMetrics (SH_CYHSCROLL) ;
Diferena const n faptul c barele de derulare ale ferestrelor folosesc o variabil ctre fereastra
principal ca prim parametru i SB_VERT sau SB_HORZ ca al doilea parametru.
Destul de surprinztor, culoarea de sistem COLOR_SCROLLBAR nu mai este folosit pentru
controalele de tip bar de derulare. Butoanele de la captul barei i caseta de derulare de pe bar
folosesc culorile COLOR_BTNFACE, COLOR_BTN-HIGHUGHT, COLOR_BTNSHADOW,
COLOR_BTNTEXT (pentru sgei) i COLOR J3TNLIGHT. Spaiul mai mare dintre cele' dou
butoane de la capete este o combinaie a culorilor COLOR_BTNFACE i COLOR_BTNHIGHLIGHT.
Dac interceptai mesajul WM_CTLCOLORSCROLLBAR, putei s returnai o pensul pentru
suprascrierea culorilor folosite pentru aceast zon. Haidei s facem acest lucru.
28.
21
Clasa de editare este, din unele puncte de vedere, cea mai simpla clasa de fereastra predefinita, iar
din alte puncte de vedere este cea mai complicate. Atunci cand creati o fereastra descendent folosind
numele de clasa ,,edit", definiti un dreptunghi pe baza coordonatelor x si y si a parametrilorinaltime si
latime - specificati la apelarea functiei CreateWindow. Acest dreptunghi contine text care poate fi editat.
Atunci cand fereastra descendent detine cursorul de intrare, puteti sa introduced text de la tastatura,
sa deplasati cursorul, sa selectati portiuni din text cu ajutorul mouse-ului sau al tastei Shift si al
tastelor de deplasare, sa stergeti textul selectat si sa 11 pastrati in memoria temporara (Clipboard) apasand
tastele Ctrl+X, sa il copiati cu ajutorul tastelor Ctrl+C sau sa inserati in controlul de editare textul din
memoria temporara apasand tastele Ctrl+V.
Unul dintre cele mai simple moduri de folosire a controalelor de editare este crearea rubricilor de
intrare cu o singura linie. Dar controalele de editare nu sunt limitate la o singura .
29.
Putei s creai un control static de tip fereastr descendent folosind clasa static" n
funcia CreateWindow. Aceste ferestre sunt un tip destul de inofensiv" - nu accept
intrri de la mouse sau de la tastatur i nu trimit mesaje WM_COMMAND ctre
fereastra printe. (Atunci cnd executai clic pe o fereastr descendent static, aceasta
intercepteaz mesajul WM_NCHITTEST i returneaz o valoare HTTRANSPARENT
ctre Windows. Ca rezultat, Windows trimite acelai mesaj WM_NCHITTEST ctre
fereastra aflat dedesubt, care de obicei este fereastra printe. n general, fereastra
printe transmite mesajul primit ctre procedura DefWindowProc, unde acesta este
convertit ntr-un mesaj de mouse din zona client.)
Primele ase stiluri de ferestre descendent statice nu fac dect s deseneze un
dreptunghi sau un cadru n zona client a ferestrei descendent. n tabelul urmtor
stilurile statice RECT" (coloana din stnga) sunt dreptunghiuri pline, iar cele trei
stiluri FRAME" (coloana din dreapta) sunt chenare dreptunghiulare necolorate:
SS_BLACKRECT SS_BLACKFRAME SS_GRAYRECT SS_GRAYFRAME
SS_WHITERECT SS_WHITEFRAME
BLACK", GRAY" i WHITE" nu sunt, de fapt, culorile dreptunghiurilor res pective. Culorile reale folosite se bazeaz pe culori de sistem, aa cum se poate vedea n
tabelul urmtor:
Control static
Culoare de sistem
BLACK
COLOR_3DDKSHADOW
GRAY
COLOR_BTNSHADOW
WHITE
COLOR_BTNHIGHLIGHT
Parametrul pentru textul ferestrei din apelul funciei CreateWindow este ignorat n
cazul acestor stiluri de fereastr. Colul din stnga-sus al dreptunghiului ncepe la
poziia indicat de parametrii x i y, relativ la fereastra printe. (Putei s folosii i
stilurile SS_ETCHEDHORZ, SS_BTCHEDVERT sau SS_ETCHEDFRAME ca s creai
chenare umbrite cu culorile gray" i white".)
Clasele statice includ i trei stiluri de text: SS_LEFT, SS_RIGHT i SS_CENTER.
Acestea creeaz rubrici de text aliniate la stnga, la dreapta sau centrate. Textul este
furnizat ca parametru al funciei CreateWindow i poate fi modificat prin apelarea
funciei SetWindowText. Atunci cnd procedura ferestrei pentru controalele statice
afieaz acest text, folosete funcia DrawText cu parametrii DT_WORDBREAK,
DT_NOCLIP i DT_EXPANDTABS. Textul este ncadrat n dreptunghiul ferestrei
descendent.
Fondul ferestrelor descendent de tip text este, n mod normal, COLOR_BTNFACE,
iar textul este scris cu culoarea dat de COLOR_WINDOWTEXT. Putei s
interceptai mesajele WM_CTLCOLORSTATIC dac dorii s modificai culoarea
22
textului prin apelarea funciei SetTextColor sau a fondului prin apelarea funciei
SetBkColor i prin returnarea unei variabile handle a pensulei pentru fond. Acest lucru
va fi ilustrat n programul COLORS1, prezentat puin mai jos.
In sfrit, clasa static" include stilurile de fereastr SS_CON i SS_USERITEM. Acestea nu au ns
nici o semnificaie atunci cnd sunt folosite pe post de controale de tip fereastr descendent. Le vom
prezenta pe larg atunci cnd vom discuta despre casetele de dialog.
30.
In programul COLORS1, interiorul celor trei bare de derulare si textul din cele sase rubrici de text
sunt colorate cu rosu, verde si albastru. Colorarea barelor de derulare se realizeaza prin prelucrarea
mesajelor WM_CTLCOLORSCROLLBAR.
In procedura WndProc definim o matrice statica ce contine trei variabile handle ale pensulelor:
unde matricea crPrim contine valorile RGB pentru cele trei culori primare. In timpul prelucrarii
mesajului WMlCTLCOLORSCROLLBAR, procedura ferestrei returneaza una dintre cele trei pensule:
case WM_CHX0LORSCR0LLBAR : i = GetWindowLong ((HWND) lParam, GWWJD) ; return (LR ESULT) hBrush[i] ;
Textul din rubricile de text static este colorat mtr-un mod similar prin prelucrarea mesajului
WM_CTLCOLORSTATIC si prin apelarea functiei SetTextColor. Fondul textului este stabilit cu ajutorul
functiei SetBkColor, folosind culoarea de sistem COLOR_BTNHIGHLIGHT. In acest fel fondul
textului are aceeasi culoare ca si dreptunghiul static din spatele barelor de derulare si al textului. In
cazul controalelor de tip text static, culoarea de fond se aplica numai pentru dreptunghiul din spatele
caracterelor care formeaza textul, nu pentru tot spatiul ocupat de fereastra controlului. Pentru aceasta,
procedura ferestrei trebuie sa returneze o variabila handle la o pensula de culoarea
COLOR_BTNHIGHLIGHT. Aceasta pensula se numeste hBrushStatic, este creata in timpul prelucrarii
mesajului WM_CREATE si este distrusa in timpul prelucrarii mesajului WM_DESTROY.
Prin crearea unei pensule bazate pe culoarea COLOR_BTNHIGHLIGHT In timpul prelucrarii
mesajului WM_CREATE si folosirea acesteia pe toata durata programului, ne-am expus la aparitia unei
mici probleme. Daca in timpul rularii programului culoarea COLOR_BTNHIGHLIGHT este
modificata, culoarea dreptunghiului static se va modifica, la fel si culoarea de fond a textului, dar culoarea
de fond a controalelor de tip text va ramane tot vechea culoare COLOR_BTNHIGHLIGHT.
32.
Atunci cand defineste clasa de fereastra, programul COLORS1 stabileste pentru fondul zonei client o
pensula neagra plina:
wndclass.hbrBackground CreateSolidBrush (OL) ;
Atunci cand modificati valorile barelor de derulare, programul trebuie sa creeze o noua pensula si sa
puna variabila handle a acesteia in structura de clasa a ferestrei. Asa cum avem posibilitatea sa
obtinem si sa stabilim procedura barelor de derulare cu ajutorul funcfiilor GetWindowLong si
SetWindowLong, putem sa obtinem si sa stabilim si variabila handle a acestei pensule cu ajutorul
functiilor GetClassWord si SetClassWord.
Puteti sa aveti o noua pensula, sa inserati variabila handle a acesteia in structura de clasa a ferestrei,
apoi sa stergeti vechea pensula:
DeleteObject ((HBRUSH)
SetClassLong (hwnd, GCL HBRBACKGROUND, (LONG)
CreateSolidBrush TRGB (color[0], color[l], color[2])))) ;
La urmatoarea recolorare a fondului ferestrei, Windows va folosi noua pensula. Pentru a forja
stergerea fondului, invalidam partea dreapta a zonei client:
InvalidateRect (hwnd, ircColor, TRUE) ;
Valoarea TRUE (diferita de 0) folosita ca eel de-al treilea parametru indica faptul ca dorim ca fondul
sa fie sters Inainte de a fi redesenat.
Functia InvalidateRect forteaza sistemul de operare Windows sa puna un mesaj WM_PAINT in
coada de mesaje a ferestrei. Deoarece are prioritate scazuta, mesajul WMJPAINT nu va fi prelucrat
imediat daca inch mai miscati caseta de pe bara de derulare cu ajutorul mouse-ului sau al tastaturii.
Daca vreti ca fereastra sa fie actualizata imediat dupa modificarea culorii, puteti sa adaugati
instructiunea:
UpdateWindow (hwnd) ;
dupa apelarea functiei InvalidateRect. Dar aceasta instructiune va incetini prelucrarea mesajelor de la
mouse sau de la tastatura.
Functia WndProc din programul COLORS1 nu prelucreaza mesajele WM_PAINT, ci le trimite
functiei DefWindowProc. Codul prestabilit de prelucrare a mesajului WM_PAINT consta numai in
apelarea functiilor BeginPaint si EndPaint pentru validarea ferestrei. Deoarece am specificat in apelul
functiei InvalidateRect ca fondul ferestrei trebuie sters, functia BeginPaint forfeaza sistemul de
operare Windows sS genereze mesajul WM_ERASEBKGND (stergere fond). Functia WndProc ignora
acest mesaj. Mesajul este prelucrat de Windows, care sterge fondul zonei client, folosind pensula
specificata in clasa ferestrei.
Intotdeauna este bine sa faceti curatenie inainte de terminarea programului, asa c in timpul
prelucrarii mesajului WM_DESTROY este apelata din nou funcia DeleteObject:
DeleteObject ((HBRUSH)
SetClassLong (hwnd, GCL_HBRBACKGROUND,
(LONG) GetStockObject (WHITE_BRUSH))) ;
33.
Windows pstreaz 25 de culori de sistem pentru afiarea diferitelor pri ale ecra nului. Putei s
obinei i s stabilii aceste culori cu ajutorul funciilor GetSysColor i SetSysColors. Identificatorii
definii n fiierele antet din Windows specific culorile de sistem. Stabilirea unei culori de sistem cu
ajutorul funciei SetSysColors afecteaz culoarea respectiv numai pe durata sesiunii Windows curente.
Putei s schimbai o parte dintre culorile de sistem folosind seciunea Display a Panoului de control
din Windows (Control Panel) sau modificnd seciunea [colors] din fiierul WIN.INI. Seciunea
[colors] folosete pentru cele 25 de culori de sistem cuvinte cheie (altele dect identificatorii folosii de
funciile GetSysColor i SetSysColors) urmai de valori pentru culorile rou, verde i albastru. Aceste
valori sunt cuprinse n intervalul 0 - 255. Tabelul urmtor prezint modul n care sunt identificate cele 25
de culori de sistem, cu ajutorul identificatorilor folosii de funciile GetSysColor i SetSysColors i al
cuvintelor cheie folosite n fiierul WIN.INI. Tabelul este ordonat cresctor, n funcie de valoarea
constantelor COLOR_ (de la 0 la 24):
24
GetSysColor i SetSysColors
WIN.INI
COLOR_SCROLLBAR
COLOR_BACKGROUND
COLOR_ACTIVECAPTION
COLOR_NACTIVECAPTION
COLOR_MENU
COLOR_WINDOW
COLOR_WINDOWFRAME
COLOR_MENUTEXT
COLOR_WINDOWTEXT
COLOR_CAPTIONTEXT
COLOR_ACTIVEBORDER
COLOR_NACTIVEBORDER
COLOR_APPWORKSPACE
COLOR_HIGHLIGHT
COLOR_HIGHLIGHTTEXT
COLOR_BTNFACE
COLOR_BTNSHADOW
COLOR_GRAYTEXT
COLOR_BTNTEXT
COLOR_NACTIVECAPTIONTEXT
COLOR_BTNHIGHLIGHT
COLOR_3DDKSHADOW
COLOR_3DLIGHT
COLOR_NFOTEXT
COLOR_INFOBK
Scrollbar
Background
ActiveTitle
InactiveTitle
Menu
Window
WindowFrame
MenuText
WindowText
TitleText
ActiveBorder
InactiveBorder
AppWorkspace
Hilight
HilightText
ButtonFace
ButtonShadow
GrayText
ButtonText
InactiveTitleText
ButtonHilight
ButtonDkShadow
ButtonLight
InfoText
InfoWindow
Valorile prestabilite pentru aceste culori sunt furnizate de driverul de afiare. Sistemul de operare
Windows folosete valorile prestabilite, dac acestea nu sunt suprascrise de valorile din seciunea
[colors] a fiierului WIN.INI, care poate fi modificat din Panoul de control.
34.
Tasta de
deplasare
Valoarea
wParam din
mesajul barei
de derulare
25
Home
,
SB_TOP
End
SB_BOTTOM
Page Up
SB_PAGEUP
Page Down
SB_PAGEDOWN
Left sau Up
SB_LINEUP
Right sau Down
SB_LINEDOWN
De fapt, mesajele SB_TOP i SB_BOTTOM nu pot fi generate dect prin folosirea tastaturii. Dac dorii ca un
control de tip bar de derulare s obin cursorul de intrare atunci cnd se execut clic pe aceasta, trebuie s
includei identificatorul WS_TAB-STOP n parametrul de stil al ferestrei la apelarea funciei CreateWindow.
Atunci cnd o bar de derulare deine cursorul de intrare, pe caseta de derulare de pe ea este afiat un bloc gri care
clipete.
Totui, pentru a furniza barelor de derulare o interfa complet cu tastatura, este necesar ceva mai mult
munc. Mai nti, procedura WndProc trebuie s acorde explicit barei de derulare cursorul de intrare. Acest
lucru se face prin prelucrarea mesajului WM_SETFOCUS, pe care fereastra printe l primete atunci cnd
primete cursorul de intrare. WndProc cedeaz pur i simplu cursorul de intrare uneia dintre barele de derulare:
SetFocus (hwndScrol[iFocus]) ;
35.
Dei putei s creai propriile controale de tip fereastr descendent, putei s beneficiai i de avantajele
oferite de un set de clase de fereastr (i proceduri specifice) predefinite, clase pe care programele pot s le foloseasc
pentru crearea unor controale de tip fereastr descendent standard, pe care cu siguran le-ai mai vzut i n alte
programe pentru Windows. Aceste controale apar sub forma butoanelor, casetelor de validare, casetelor de
editare, casetelor list, casetelor combinate, a irurilor de caractere i a barelor de derulare. De exemplu, dac
dorii s punei un buton cu eticheta Recalculare" ntr-un col al unui program de calcul tabelar, putei s l creai
printr-un simplu apel al procedurii CreateWindow. Nu trebuie s v facei griji n privina logicii de interpretare
a clicurilor de mouse, a redesenrii butonului sau a modului n care butonul se mic atunci cnd este apsat. Tot
ce trebuie s facei este s interceptai mesajul WM_COMMAND - acesta este modul n care butonul
informeaz procedura ferestrei despre declanarea unui eveniment.
36.
O abordare mai potrivit (din nou, teoretic) este prelucrarea mesajului WM_CTLCOLORBTN. Acesta
este un mesaj pe care controalele de tip buton l trimit ctre procedura ferestrei printe atunci cnd fereastra
descendent este pe cale de a executa o redesenare. Fereastra printe poate s foloseasc aceast ocazie ca s
modifice culorile pe care procedura ferestrei descendent urmeaz s le foloseasc pentru desenare. (In
versiunile pe 16 bii ale sistemului de operare Windows, un mesaj numit WM_CTLCOLOR era folosit pentru
toate controalele. Acesta a fost nlocuit cu mesaje separate pentru fiecare tip standard de control.)
Atunci cnd procedura printe recepioneaz mesajul WM_CTLCOLORBTN, parametrul wParam conine
variabila handle a contextului de dispozitiv al butonului, iar IParatn este variabila handle a ferestrei butonului.
Atunci cnd fereastra printe primete acest mesaj, controlul de tip buton a obinut deja contextul de
dispozitiv. n timpul prelucrrii mesajului WM_CTLCOLORBTN:
Stabilii (opional) o culoare de text cu ajutorul funciei SetTextColor.
Stabilii (opional) o culoare de fond cu ajutorul funciei SetBkColor.
Returnai ctre fereastra descendent o variabil de manipulare a pensulei
cu care se va desena.
Teoretic, fereastra descendent folosete pensula respectiv pentru colorarea fondului. Este sarcina
dumneavoastr s distrugei pensula atunci cnd aceasta nu mai este necesar.
Totui, n legtur cu mesajul WM_CTLCOLORBTN este o problem: acesta nu este trimis dect de
butoanele de apsare i de butoanele desenate de proprietar; de asemenea, numai butoanele desenate de
proprietar rspund la prelucrarea fcut mesajului de ctre fereastra printe, folosind pensula trimis pentru
colorarea fondului. Oricum, acest lucru este inutil, deoarece fereastra printe este rspunztoare de desenarea
acestor butoane.
37.
Pentru toate celelalte butoane radio din acelai grup putei s tergei marcajul de validare trimindu-le
mesajul BM_SETCHECK cu parametrul wParam egal cu 0:
SendMessage (hwndButton, BM_SETCHECK, 0, 0) ;
38.
Pentru controalele de editare pe o singura linie, inalfimea controlului trebuie sa corespunda inalfimii unui
caracter. In cazul in care controlul de editare are un chenar
(si majoritatea au), folosifi ca dimensiune de 1,5 ori inalfimea unui caracter (indusiv spatiul extern).
39.
40.
O abordare mai potrivit (din nou, teoretic) este prelucrarea mesajului WM_CTLCOLORBTN. Acesta
este un mesaj pe care controalele de tip buton l trimit ctre procedura ferestrei printe atunci cnd fereastra
descendent este pe cale de a executa o redesenare. Fereastra printe poate s foloseasc aceast ocazie ca s
modifice culorile pe care procedura ferestrei descendent urmeaz s le foloseasc pentru desenare. (In
versiunile pe 16 bii ale sistemului de operare Windows, un mesaj numit WM_CTLCOLOR era folosit pentru
toate controalele. Acesta a fost nlocuit cu mesaje separate pentru fiecare tip standard de control.)
Atunci cnd procedura printe recepioneaz mesajul WM_CTLCOLORBTN, parametrul wParam conine
variabila handle a contextului de dispozitiv al butonului, iar IParatn este variabila handle a ferestrei butonului.
Atunci cnd fereastra printe primete acest mesaj, controlul de tip buton a obinut deja contextul de
dispozitiv. n timpul prelucrrii mesajului WM_CTLCOLORBTN:
Stabilii (opional) o culoare de text cu ajutorul funciei SetTextColor.
Stabilii (opional) o culoare de fond cu ajutorul funciei SetBkColor.
Returnai ctre fereastra descendent o variabil de manipulare a pensulei
cu care se va desena.
41.
42.
Dei folosirea penielor definite ca obiecte de stoc este foarte convenabil, avei la dispoziie doar
un numr limitat de opiuni: o peni neagr, pentru linie continu, una alb pentru linie continu sau
una care nu deseneaz nimic. Dac dorii ceva diferit, trebuie s creai propriile dumneavoastr penie.
Iat procedura general: creai mai nti o peni logic" (logical pen) care este doar o descriere a unei
penie, folosind funciile CreatePen sau CreatePenIndirect. (De asemenea, putei s folosii i funcia
ExtCreatePen, despre care vom discuta atunci cnd vom ajunge la cile GDI.) Aceste funcii
returneaz o variabil handle a peniei logice. Selectai penia n contextul de dispozitiv apelnd funcia
SelectObject. Apoi putei s desenai linii cu penia selectat. La un moment dat nu poate fi selectat,
ntr-un context de dispozitiv, dect o peni. Dup ce tergei contextul de dispozitiv (sau dup ce
selectai o alt peni n contextul de dispozitiv) putei s tergei penia logic pe care ai creat-o
apelnd funcia DeleteObject. Dup ce facei acest lucru, variabila handle a peniei nu mai este valid.
O peni logic este un obiect GDI". Dumneavoastr creai i folosii penia, dar aceasta nu
aparine programului, ci modulului GDI. Penia este unul dintre cele ase obiecte GDI pe care putei s
le creai. Celelalte cinci sunt pensulele, imaginile bitmap, regiunile, fonturile i paletele. Exceptnd
paletele, toate celelalte obiecte pot fi selectate n contextul de dispozitiv folosind funcia SelectObject.
Pentru folosirea obiectelor GDI trebuie s respectai urmtoarele reguli:
La sfritul programului tergei toate obiectele GDI pe care le-ai creat.
Nu tergei obiectele GDI n timp ce sunt selectate ntr-un context de dispozitiv valid.
Nu tergei obiectele de stoc.
Chiar dac sunt nite reguli rezonabile, neplcerile pot exista. Voi prezenta cteva exemple ca s
nelegei cum funcioneaz aceste reguli i pentru a putea evita eventuale probleme.
+Putei s creai o peni i cu ajutorul unei structuri de tip LOGPEN (logical pen"), apelnd
funcia CreatePenIndirect. Dac programul folosete un numr mai mare de penie diferite pe care Ie
iniializai n codul surs, aceast metod este mai eficient. Mai nti definii o variabil de tip
LOGPEN, cum ar fi logpen:
LOGPEN logpen ;
Aceast structur are trei membri: lopnStyle (UINT) este stilul peniei, lopn Width (POINT) este
grosimea peniei n uniti logice, iar lopnColor (COLORREF) este culoarea peniei. Membrul lopn
Width este o structur de tip POINT, dar Windows folosete numai membrul lopnWidth.x al acestei
structuri i ignor membrul lopnWidth.y. Apoi creai penia, transmind funciei CreatePenIndirect
adresa structurii logpen:
hPen = CreatePenIndirect (&logpen) ;
De asemenea, putei s obinei informaii despre o peni logic existent. Dac avei deja o
variabil handle a unei penie putei s copiai datele care definesc penia logic ntr-o structur de tip
LOGPEN folosind funcia GetObject:
GetObject (hPen, sizeof (LOGPEN), (LPVOID) &logpen) ;
n timpul prelucrrii mesajului WM_PAINT (sau n orice alt moment n care avei o variabil
handle valid a contextului de dispozitiv) putei s selectai oricare dintre aceste penie n contextul de
dispozitiv i s desenai:
SelectObject (hdc, hPen2) ;
[funcii de desenare a liniilor]
SelectObject (hdc, hPen1) ;
[alte funcii de desenare a liniilor]
n timpul prelucrrii mesajului WM_DESTROY putei s tergei cele trei penie create:
DeleteObject (hPen1) ;
DeleteObject (hPen2) ;
DeleteObject (hPen3) ;
Aceasta este metoda cea mai direct pentru crearea, selectarea i tergerea penielor, dar are
dezavantajul c peniele create ocup spaiu n memorie pe toat durata rulrii programului. O alt
soluie este s creai peniele necesare n timpul prelucrrii fiecrui mesaj WM_PAINT i s le tergei
dup apelarea funciei EndPaint. (Putei s le tergei i nainte de apelarea funciei EndPaint, dar
trebuie s avei grij s nu tergei penia curent selectat n contextul de dispozitiv.)
De asemenea, putei s creai peniele atunci cnd sunt necesare, combinnd funciile CreatePen i
SelectObject n aceeai instruciune:
SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0))) ;
Din acest moment, vei folosi o peni pentru linii ntrerupte de culoare roie. Dup ce terminai de
fcut desenele cu acest tip de linie, putei s tergei penia. Hopa! Cum putei s tergei penia dac
nu ai salvat variabila handle a acesteia? V amintii c funcia SelectObject returneaz variabila
handle a peniei selectate anterior n contextul de dispozitiv. Aa c putei s tergei penia selectnd n
contextul de dispozitiv penia de stoc BLACK_PEN i tergnd variabila handle returnat de funcia
SelectObject:
DeleteObject (SelectObject (hdc, GetStockObject (BLACK PEN))) ;
Exist i o alt metod. Atunci cnd selectai n contextul de dispozitiv o peni nou creat, salvai
variabila handle returnat de funcia SelectObject;
hPen = SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0))) ;
Ce este hPen? Dac aceasta este prima apelare a funciei SelectObject de la obinerea contextului
de dispozitiv, atunci hPen este variabila handle a obiectului de stoc BLACK_PEN. Putei acum s
selectai penia BLACK_PEN n contextul de dispozitiv i s o tergei pe cea creat (variabila handle
returnat la a doua apelare a funciei SelectObject) printr-o singur instruciune:
DeleteObject (SelectObject (hdc, hPen)) ;
43.
Parametrul iPenStyle precizeaz dac se deseneaz o linie continu, o linie punctat sau una
ntrerupt. Parametrul iPenStyle poate fi unul dintre identificatorii definii n fiierele antet din
Windows. Figura 4-16 prezint stilul de linie produs de fiecare identificator.
Fomatarea textului
Deoarece dimensiunile fontului sistem nu se modific n timpul unei sesiuni Windows, trebuie s
apelai funcia GetTextMetrics o singur dat dup lansarea n execuie a programului. Un loc potrivit
pentru acest apel este codul de prelucrare a mesajului WM_CREATE din procedura de fereastr.
Mesajul WM_CREATE este primul mesaj pe care l primete procedura de fereastr. Windows trimite
un mesaj WM_CREATE procedurii de fereastr atunci cnd apelai funcia CreateWindow din funcia
WinMain.
S presupunem c scriei un program Windows care afieaz mai multe linii de text una sub alta, n
zona client a ferestrei. Trebuie s obinei valorile pentru nlimea i limea caracterelor. n procedura
de fereastr putei s definii dou variabile n care s salvai limea medie (cxChar) i nlimea total
a caracterelor (cyChar):
static int cxChar, cyChar ;
Prefixul c adugat la numele variabilelor provine de la contor" i n combinaie cu x sau y se
refer la dimensiunea pe orizontal sau pe vertical a caracterelor. Aceste variabile sunt declarate ca
statice deoarece trebuie s fie valide atunci cnd procedura de fereastr prelucreaz alte mesaje (cum
ar fi WM_PAINT). Dac variabilele sunt declarate ca globale n alte funcii nu mai este necesar s fie
declarate statice. Iat codul de prelucrare a mesajului WM_CREATE:
case WH_CREATE:
hdc = GetDC (hwnd);
GetTextMetrics (hdc, &tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC (hwnd, hdc);
return 0;
Dac nu vrei s folosii spaiul suplimentar extern pentru spaierea liniilor de text, putei s
utilizai instruciunea:
cyChar = tm.tmHeight;
Pentru afiarea mai multor linii de text aliniate la stnga, folosii valoarea cxChar pentru
parametrul care reprezint coordonata pe axa x n apelul funciei TextOut. Valoarea coordonatei pe axa
y la apelarea funciei TextOut este:
cyChar * (1 + i);
unde i reprezint numrul liniei, ncepnd de la 0.
Deseori este necesar s afiai att numere formatate, cat i iruri simple de caractere. Dac ai scris
programe DOS folosind funciile standard C de bibliotec, probabil ai folosit pentru formatarea
numerelor funcia printf. n Windows nu putei s folosii funcia printf, deoarece ea determin afiarea
la dispozitivul standard de ieire, acesta fiind un concept care n Windows nu are nici un sens.
n schimb, putei s folosii funcia sprintf. Funcia sprintf lucreaz la fel ca i funcia printf, cu
excepia faptului c irul de caractere formatat este stocat ntr-o matrice de caractere. Apoi putei
utiliza funcia TextOut pentru a scrie irul ce trebuie afiat. Funcia sprintf returneaz lungimea irului
de caractere, ceea ce este foarte convenabil - putei s transmitei valoarea returnat n locul
parametrului iLength din apelul funciei TextOut. Secvena de cod de mai jos prezint o combinaie
tipic a funciilor TextOut i sprintf:
int iLenght;
char szBuffer [40];
[alte Iinii de program]
iLenght = sprintf (szBuffer, "The sum of %d and %d is %d"), nA, nB, nA + nB);
TextOut (hdc, x, y, szBuffer, iLength);
Pentru operaiile simple de afiare precum cea de mai sus putei s renunai la definirea variabilei
iLength i s combinai cele dou instruciuni rmase ntr-una singur:
TextOut (hdc, x, y, szBuffer, sprintf (szBuffer, "The sum of %d and %d is %d", nA, nB,
nA + nB));
Nu arat prea frumos, dar funcioneaz.
Dac nu trebuie s afiai numere n virgul mobil, putei folosi funcia wsprintf n locul funciei
sprintf. Funcia wsprintf are aceeai sintax ca i funcia sprintf, dar este inclus n Windows, aa c nu
va mri dimensiunea fiierului executabil.
45.
Parametrul iIndex este unul dintre cei 28 de identificatori definii n fiierele antet din Windows.
De exemplu, dac iIndex are valoarea HORZRES funcia GetDeviceCaps returneaz limea
dispozitivului n pixeli; VERTRES returneaz nlimea dispozitivului n pixeli. Dac hdc este o
variabil handle a contextului de dispozitiv pentru un monitor video, informaiile obinute sunt aceleai
cu cele returnate de funcia GetSystemMetrics. Dac hdc este o variabil handle a contextului de
dispozitiv pentru o imprimant, funcia GetDeviceCaps returneaz nlimea i limea zonei pe care
imprimant o poate tipri.
Putei s folosii funcia GetDeviceCaps i ca s obinei informaii despre posibilitile unui
dispozitiv de prelucrare a anumitor tipuri de elemente grafice. Aceast posibilitate nu este important
pentru ecran, dar poate fi folosit n cazul imprimantelor. De exemplu, majoritatea plotterelor nu pot
tipri imagini bitmap - iar funcia GetDeviceCaps v poate comunica acest lucru.
46.
Funcia TextOut. Contextul de dispozitiv. Obinerea unei variabile handle a contextului de dispozitiv:
TextOut. . handle DC:
Contextul de dispozitiv (prescurtat DC - device context) este o structur de date ntreinut intern
de interfaa GDI. Fiecare context de dispozitiv este asociat unui anumit dispozitiv de afiare, cum ar fi
imprimanta, plotterul sau monitorul video. n cazul monitoarelor video, un context de dispozitiv este
de obicei asociat unei anumite ferestre de pe ecran.
O parte dintre valorile din contextul de dispozitiv sunt atribute grafice. Aceste atribute definesc
unele particulariti privind modul de lucru al unor funcii de desenare din interfaa GDI. n cazul
funciei TextOut, de exemplu, atributele contextului de dispozitiv determin culoarea textului, culoarea
fondului, modul de mapare a coordonatelor x i y n zona client a ferestrei i fontul folosit de Windows
pentru afiarea textului.
Atunci cnd vrea s deseneze, programul trebuie s obin mai nti o variabil handle a unui
context de dispozitiv. Dup terminarea operaiilor de desenare, programul ar trebui s elibereze
variabila. Dup eliberarea variabilei handle, aceasta nu mai este valid i, deci, nu mai poate fi folosit.
Programul trebuie s obin i s elibereze variabila handle n timpul prelucrrii unui singur mesaj. Cu
excepia contextelor de dispozitiv create cu funcia CreateDC (despre care nu vom discuta n acest
capitol) este recomandat s nu pstrai variabilele handle ale contextelor de dispozitiv de la un mesaj la
altul.
n general, aplicaiile Windows folosesc dou metode pentru obinerea variabilelor handle ale
contextelor de dispozitiv, atunci cnd se pregtesc pentru desenarea ecranului.
Windows plaseaz un mesaj WM_PAINT n coada de ateptare, deoarece o parte a zonei client este
invalid. Dac nu apelai funciile BeginPaint i EndPaint (sau ValidateRect) Windows nu valideaz
zona de fereastr respectiv, ci v trimite n continuare mesaje WM_PAINT.
47.
Funciile SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw), SetScrollPos (hwnd, iBar, iPos, bRedraw).
Pozii
a
Pozii
a
Pozii
a
Pozii
a
Poziia
4
Poziia 0 Poziia 1 Poziia 2 Poziia 3 Poziia
4
Figura
3-8. Bare de derulare cu cinci poziii ale casetei de derulare.
Parametrul iPos reprezint noua poziie, care trebuie s fie cuprins n domeniul delimitat de iMin
i iMax. Windows conine funcii asemntoare (GetScrollRange i GefScrollPos) pentru obinerea
domeniului i a poziiei unei bare de derulare.
Atunci cnd folosii bare de derulare ntr-un program Windows, rspunderea pentru ntreinerea i
actualizarea acestora este mprit ntre dumneavoastr i sistemul de operare. Sistemul de operare
Windows are urmtoarele sarcini:
Trateaz operaiile executate cu mouse-ul asupra barei de derulare. .Afieaz n video invers
zona pe care utilizatorul execut clic.
Mut caseta de derulare atunci cnd utilizatorul o trage cu ajutorul mouse-ului.
Trimite mesaje din partea barei de derulare ctre procedura de fereastr care o conine.
Funciile programului n aceast privin sunt:
Iniializarea domeniului barei de derulare.
Prelucrarea mesajului primit de la bara de derulare.
48.
Dei tastatura este principala surs de intrri de la utilizatori a unui program pentru Windows,
programele nu trebuie s reacioneze la toate mesajele pe care le primete de la tastatur. Multe funcii
ale tastaturii sunt tratate chiar de Windows. De exemplu, putei s ignorai apsrile de taste legate de
funcii sistem. Acestea sunt, n general, combinaii cu tasta Alt.
Programul nu este obligat s monitorizeze aceste taste, deoarece Windows i comunic efectul
acestora. (Totui, dac este nevoie, programul poate face i acest lucru.) De exemplu, dac utilizatorul
selecteaz un articol dintr-un meniu cu ajutorul tastaturii. Windows trimite programului un mesaj prin
care i comunic articolul de meniu selectat, indiferent dac utilizatorul a folosit mouse-ul sau
tastatura.
Unele programe pentru Windows folosesc acceleratori" (sau taste de accelerare") pentru
opiunile de meniu folosite mai frecvent. Acceleratorii sunt, de obicei, combinaii de taste funcionale sau alte taste corespunztoare unor caractere - cu tasta Ctrl. Tastele de accelerare sunt definite n
fiierul de resurse al programului.
Casetele de dialog au i ele o interfa cu tastatura, dar programele, n general, nu trebuie s
monitorizeze tastatura ct timp este activ o caset de dialog. Interfaa cu tastatura este manipulat de
Windows i acesta trimite programului mesaje prin care i comunic efectele tastelor apsate. Casetele
de dialog pot conine controale de editare pentru introducerea textului. Acestea sunt mici casete, n care
utilizatorul poate s scrie un ir de caractere. Windows asigur logica de funcionare a controlului de
editare i furnizeaz programului coninutul final al controlului, dup ce utilizatorul a terminat.
Cursorul, cursorul, cine a luat cursorul de intrare?
Tastatura trebuie s fie partajat de toate aplicaiile rulate simultan sub Windows. Unele aplicaii
pot avea mai multe ferestre, iar tastatura trebuie s fie partajat de toate ferestrele din cadrul aceleiai
aplicaii. Atunci cnd este apsat o tast, o singur fereastr trebuie s primeasc mesajul privind
apsarea tastei respective. Fereastra care primete acest mesaj este fereastra care deine cursorul de
intrare" (input focus").
Conceptul cursorului de intrare este strns legat de conceptul de fereastr activ". Fereastra care
deine cursorul de intrare este fie fereastra activ, fie o fereastr descendent a ferestrei active. De
obicei, fereastra activ este uor de identificat. Dac fereastra activ are o bar de titlu, Windows
evideniaz bara de titlu a acesteia. Dac fereastra activ are un cadru de dialog (o form des ntlnit
n casetele de dialog) n locul unei bare de titlu, Windows evideniaz acest cadru. Dac fereastra
activ a fost redus la o pictogram (minimizat), Windows evideniaz textul afiat sub pictogram.
Ferestrele descendent mai des ntlnite sunt controale, precum butoanele de apsare, butoanele
radio, casetele de validare, barele de derulare, casetele de editare i casetele list, care, de obicei, apar
n casete de dialog. Ferestrele descendent nu sunt niciodat ferestre active. Dac o fereastr descendent
deine cursorul de intrare, atunci fereastra activ este fereastra printe. Controalele de tip fereastr
descendent indic faptul c dein cursorul de intrare prin afiarea unui cursor care clipete sau a unui
cursor de editare.
Dac fereastra activ a fost redus la o pictogram, atunci nici o fereastr nu deine cursorul de
intrare. Windows continu s trimit programului mesaje de la tastatur, dar acestea sunt trimise ntr-o
alt form dect mesajele trimise unei ferestre active normale.
O procedur de fereastr poate s afle cnd are cursorul de intrare prin interceptarea mesajelor
WM_SETFOCUS i WM_KILLFOCUS. Mesajul WM_SETFOCUS indic faptul c fereastra
primete cursorul de intrare (input focus), iar mesajul WM_KILLFOCUS indic faptul c fereastra
pierde cursorul de intrare.
caractere afiabile. Tasta A poate s genereze mai multe caractere, n funcie de starea tastelor Ctrl,
Shift i Caps Lock. n mod normal, caracterul generat este a. Dac tasta Shift este apsat, sau tasta
Caps Lock este activ, caracterul generat este A. Dac tasta Ctrl este apsat, caracterul generat este
Ctrl+A. Dac se folosete un driver de tastatur pentru o limb strin, apsarea tastei A poate s fie
precedat de un caracter mort" (dead-character key") sau de tastele Shift, Ctrl sau Alt n diferite
combinaii. Combinaiile pot s genereze un caracter a sau A cu un accent.
Pentru acionrile de taste care genereaz caractere afiabile, Windows trimite programului att
mesaje pentru acionarea de taste, ct i mesaje pentru caractere. Unele taste nu genereaz caractere.
Astfel de taste sunt Shift, tastele funcionale, tastele de deplasare i tastele speciale, precum Insert i
Delete. n cazul acestor taste, Windows genereaz numai mesaje pentru acionari de taste.
49.
dialog. Toate meniurile au aceeai interfa cu tastatura i cu mouse-ul deoarece aceste operaii sunt
manipulate mai degrab de Windows, dect de programul respectiv.
51.
Interfaa pentru dispozitive grafice. Filozofia GDI. Structura interfeei GDI. Tipuri de apeluri de funcii.
Primitive GDI. . GDI. GDI.
. GDI.
Filozofia GDI
n versiunile pe 32 de bii ale sistemului de operare Windows elementele grafice sunt manipulate,
n principal, prin funcii exportate din biblioteca cu legturi dinamice GDI32.DLL, care, la rndul ei,
folosete biblioteca cu legturi dinamice pe 16 bii GDI.EXE. (n versiunile Windows anterioare,
bibliotecile cu legturi dinamice erau fiiere cu extensia .EXE, nu .DLL.) Aceste module apeleaz
proceduri din diferite fiiere driver pentru afiare - un fiier .DRV pentru afiarea pe ecran i, probabil,
unul sau mai multe fiiere .DRV care controleaz imprimantele i plotterele. Driverele execut
operaiile de acces la componentele hardware ale monitorului video sau convertesc comenzile GDI n
coduri sau comenzi pe care le pot interpreta diferite tipuri de imprimante. Pentru diferite tipuri de plci
video sau de imprimante este nevoie, desigur, de diferite fiiere driver.
Deoarece la calculatoarele compatibile PC pot fi ataate diferite dispozitive de afiare, unul dintre
scopurile principale ale interfeei GDI este s permit manipularea elementelor grafice independent de
dispozitiv. Programele scrise pentru Windows ar trebui s ruleze fr probleme, indiferent de
dispozitivul grafic de afiare folosit, dac acesta este acceptat de sistemul de operare. Interfaa GDI
realizeaz acest lucru prin furnizarea unor componente care izoleaz programele de caracteristicile
particulare ale diferitelor dispozitive de ieire.
Lumea dispozitivelor grafice de ieire este mprit n dou categorii: dispozitive rastru i
dispozitive vectoriale. Majoritatea dispozitivelor de ieire pentru PC sunt dispozitive rastru, ceea ce
nseamn c reprezentarea imaginilor se face prin matrice de puncte. Aceast categorie include plcile
video, imprimantele matriceale i imprimantele laser. Dispozitivele vectoriale, care deseneaz
imaginile prin linii, sunt, n general, limitate la plottere.
Majoritatea limbajelor de programare cu posibiliti grafice tradiionale se bazeaz n exclusivitate
pe vectori. Aceasta nseamn c un program care folosete unul dintre aceste limbaje grafice este
desprit de componentele hardware printr-un nivel de abstractizare. Dispozitivul de ieire folosete
pixeli pentru reprezentarea elementelor grafice, dar programul nu comunic deloc cu interfaa n
limbajul pixelilor. Dei putei s folosii interfaa Windows GDI ca sistem de desenare vectorial la
nivel nalt, putei s folosii aceeai interfaa i pentru manipularea la nivel sczut a pixelilor.
Din acest punct de vedere, interfaa Windows GDI este pentru limbajele grafice de interfaa
tradiionale ceea ce este C pentru alte limbaje de programare. Limbajul C e bine cunoscut pentru
gradul nalt de portabilitate ntre diferite medii i sisteme de operare. Dar, n acelai timp, limbajul C e
cunoscut i pentru faptul c permite efectuarea unor operaii de nivel sczut, care n alte limbaje de
nivel nalt sunt, deseori, imposibile. Aa cum C este numit uneori limbaj de asamblare de nivel nalt",
putei s considerai c GDI este o interfa de nivel nalt ctre componentele hardware ale
dispozitivelor grafice.
Aa cum ai vzut, n mod prestabilit. Windows folosete un sistem de coordonate bazat pe pixeli.
Majoritatea limbajelor grafice tradiionale folosesc un sistem de coordonate virtual", cu o ax
vertical i una orizontal care merg, de exemplu, de la 0 la 32.767. Dei unele limbaje grafice nu v
permit s folosii coordonate n pixeli, interfa GDI v las s lucrai n oricare dintre cele dou
sisteme de coordonate (i chiar ntr-un alt sistem, bazat pe dimensiunile fizice). Putei s folosii un
sistem de coordonate virtual i s izolai astfel programul de componentele hardware, sau s folosii
sistemul de coordonate al dispozitivului i s scriei programul direct pentru componentele hardware
utilizate.
De asemenea, trebuie s tii c interfa Windows GDI i are limitele ei. Cel puin n acest
moment, interfa GDI nu poate s fac tot ce v-ai putea dori de la o interfa grafic. Dei putei s
mutai pe ecran obiecte grafice, GDI este, n general, un sistem de afiare static, ce permite numai
animaii limitate. Aa cum este implementat n Windows 95, interfa GDI nu asigur un suport direct
pentru afiarea tridimensional sau pentru rotirea obiectelor. De exemplu, atunci cnd desenai o
elips, axele acesteia trebuie s fie paralele cu axele sistemului de coordonate. Dei unele limbaje
grafice folosesc numere n virgul mobil pentru coordonatele virtuale. Windows 95 - din motive
legate de performan - folosete numai numere ntregi pe 16 bii aceasta este una dintre deficienele
sistemului de operare Windows 95. Windows NT permite folosirea coordonatelor pe 32 de bii.
Funcii care obin (sau creeaz) i elibereaz (sau distrug) un context de dispozitiv. Aa cum am
vzut n Capitolul 3, pentru a desena avei nevoie de un context de dispozitiv. Funciile GetDC i
ReleaseDC v permit s facei aceste lucruri n timpul prelucrrii altor mesaje dect WM_PAINT,
pe cnd funciile BeginPaint i EndPaint (dei din punct de vedere tehnic fac parte din subsistemul
USER din Windows) sunt folosite n timpul prelucrrii mesajului WM_PAINT. Vom discuta n
curnd despre alte funcii legate de contextul de dispozitiv.
Funcii care obin informaii despre contextul de dispozitiv. n programele SYSMETS, cu care ai
fcut cunotin n Capitolul 3, am folosit funcia GetTextMetrics ca s obinem informaii despre
dimensiunile fontului selectat n contextul de dispozitiv. Mai trziu n acest capitol vom prezenta
programul DEVCAPS1, pentru a obine informaii generale despre contextul de dispozitiv.
Funcii care deseneaz ceva. Evident, dup rezolvarea problemelor preliminare, acestea sunt
funciile cu adevrat importante. n Capitolul 3 am folosit funcia TextOut pentru afiarea textului
n zona client a ferestrei. Aa cum vom vedea, alte funcii GDI sunt folosite pentru desenarea
liniilor, a zonelor colorate i a imaginilor de tip bitmap.
Funcii care stabilesc sau obin atribute ale contextului de dispozitiv. Un atribut" al contextului de
dispozitiv specific modul de lucru al funciilor de desenare. De exemplu, folosii funcia
SetTextColor ca s precizai culoarea textului afiat cu funcia TextOut (sau cu o alt funcie de
afiare a textului). n programele SYSMETS din Capitolul 3 am folosit funcia SetTextAlign ca s
artm interfeei GDI faptul c poziia de nceput a irului de caractere este n partea dreapt a
irului de caractere, nu n partea stng, aa cum se ntmpl de obicei. Toate atributele contextului
de dispozitiv au valori prestabilite, care devin active la obinerea contextului de dispozitiv. Pentru
fiecare funcie de tip Set exist i o funcie Get corespondent, folosit pentru obinerea valorilor
curente ale atributelor contextului de dispozitiv.
Funcii care lucreaz cu obiecte GDI. Aici este punctul n care lucrurile se ncurc puin n
interfaa GDI. Mai nti vom da un exemplu: n mod prestabilit, toate liniile pe care le desenai
folosind interfaa GDI sunt continue i au o grosime standard. Ce se ntmpl, ns, dac dorii s
desenai o linie mai groas sau o linie punctat ori ntrerupt? Grosimea i stilul liniei nu sunt
atribute ale contextului de dispozitiv. Acestea sunt caracteristici ale peniei logice" (logical pen").
Putei s indicai o peni logic prin specificarea acestor caracteristici n funciile CreatePen,
CreatePenIndirect i ExtCreatePen. Funciile de mai sus returneaz o variabil handle a peniei
logice create. (Dei se consider c aceste funcii fac parte din interfaa GDI, spre deosebire de
majoritatea celorlalte funcii acestea nu au nevoie, ca parametru, de o variabil handle a contextului
de dispozitiv.) Pentru folosirea peniei selectai variabila handle a acesteia n contextul de
dispozitiv. Din acest moment, orice linie va fi desenat eu penia selectat. Ulterior, deselectai
obiectul peni din contextul de dispozitiv i distrugei-l. n afara penielor, putei s folosii obiecte
GDI pentru crearea pensulelor care coloreaz o suprafa nchis, pentru fonturi, pentru imagini
bitmap i pentru alte aspecte ale interfeei GDI, despre care vom discuta n acest capitol.
Primitive GDI
Elementele grafice pe care le afiai pe ecran sau le tiprii la imprimant pot fi mprite n mai
multe categorii, numite primitive". Iat care sunt aceste categorii:
Linii i curbe. Liniile reprezint baza oricrui sistem de desenare vectorial. GDI permite folosirea
liniilor drepte, a dreptunghiurilor, a elipselor (inclusiv subsetul de elipse cunoscute sub numele de
cercuri), a arcelor - care sunt curbe reprezentnd poriuni din circumferina unei elipse sau a
curbelor Bezier. Despre toate aceste clemente vom mai discuta n capitolul de fa. Orice curb mai
complex poate n desenat ea o linie poligonal, adic o serie de linii foarte scurte care definesc o
curb. Liniile sunt desenate folosind penia curent selectat n contextul de dispozitiv.
Suprafee pline. Dac o serie de linii sau de curbe nchid o suprafa, aceasta poate fi umplut"
folosind pensula GDI curent. Aceast pensul poate fi o culoare compact, un model (hauri
orizontale, verticale sau pe diagonal) sau o imagine bitmap repetat pe vertical sau pe orizontal.
Imagini bitmap. Imaginile bitmap sunt matrice dreptunghiulare de bii, care corespund pixelilor
unui dispozitiv de afiare. Imaginile bitmap sunt instrumente de baz pentru sistemele grafice de
tip rastru. n general, acestea sunt folosite pentru afiarea imaginilor complexe (deseori preluate
din lumea real) pe ecran sau pentru tiprirea acestora la imprimant. De asemenea, imaginile
bitmap sunt folosite pentru afiarea unor mici imagini (cum ar fi pictograme, indicatoare de mouse
i butoane de pe barele cu instrumente de lucru ale aplicaiilor) care trebuie afiate foarte rapid.
Interfaa GDI accept dou tipuri de imagini bitmap: un tip mai vechi (dar util) de imagini bitmap
dependente de dispozitiv i un tip mai nou (precum cele din Windows 3.0) de imagini bitmap
independente de dispozitiv (DIB - Device Independent Bitmap) care pot fi stocate n fiiere.
53.
Text. Textul este mai puin matematic" dect alte aspecte ale graficii pe calculator. Textul, aa cum
l tim, este legat de sute de ani de tipografia tradiional, apreciat adesea ca adevrat art. Din
acest motiv, textul este de multe ori nu doar cea mai complex parte a sistemului grafic, ci i cea
mai important. Structurile create pentru definirea fonturilor i pentru obinerea informaiilor
despre fonturi sunt printre cele mai mari din Windows. ncepnd cu versiunea Windows 3.1,
interfaa GDI accept fonturile TrueType, bazate pe contururi umplute, care pot fi manipulate de
alte funcii GDI. Windows 95 accept n continuare i fonturile mai vechi, de tip bitmap (cum este
fontul sistem prestabilit) pentru compatibilitate i pentru economisirea spaiului de memorie.
Mesaje CARACTER. Mesajul WM_CHAR. Mesaje pentru caractere moarte". .
WM_CHAR. .
Mesajul WM_CHAR
Atunci cnd trebuie s prelucreze caracterele introduse de la tastatur (de exemplu, ntr-un
procesor de texte sau ntr-un program de comunicaii) programul prelucreaz mesajele WM_CHAR.
Probabil dorii s prelucrati ntr-un mod mai special tastele Backspace, Tab i Enter (eventual si tasta
de salt la linie nou) dar toate celelalte caractere sunt tratate la fel:
case WH_CHAR :
switch (wParam)
{
case '\b' :
case '\f' :
case '\n' :
case '\r' :
default :
// backspace
[alte linii de program]
break ;
// tab
[alte linii de program]
break ;
// salt la linie nou
[alte linii de program]
break ;
// retur de car
[alte linii de program]
break ;
// cod de caractere
[alte linii de program]
break ;
}
return 0 ;
Acest fragment de program este asemntor cu secvenele de cod pentru tratarea caracterelor dintrun program MS-DOS obinuit.
i de tratarea erorilor: dac tasta moart este urmat de o liter care nu poate avea semnul diacritic
respectiv (cum ar fi litera s"), procedura de fereastr primete dou mesaje WM_CHAR - pentru
primul parametrul wParam conine codul ASCII al semnului diacritic, iar pentru al doilea parametrul
wParam conine codul ASCII al literei s".
54.
55.
Mesaje generate de mouse n afara zonei client. Mesajul de testare a poziiei. Mesajele genereaz mesaje.
. .
.
Apsat
Eliberat
WM_NCLBUTTON
UP
WM_NCMBUTTON
UP
WM_NCRBUTTON
UP
Totui, parametrii wParam i lParam pentru mesajele generate de mouse din afara zonei client sunt
diferite de cele generate din zona client. Parametrul wParam indic zona non-client din care a fost
generat mesajul. Parametrul wParam poate conine unul dintre identificatorii cu prefixul HT (hit
test") definii n fiierele antet din Windows.
Variabila lParam conine coordonata pe axa x n cuvntul mai puin semnificativ i coordonata pe
axa y n cuvntul mai semnificativ. Totui, aceste coordonate sunt relative la ecran, nu la zona client.
Pentru coordonatele de ecran, punctul de origine (0,0) este colul din stnga-sus al zonei de afiare a
ecranului. Valorile coordonatei x cresc ctre dreapta, iar valorile coordonatei y cresc n jos (vezi Figura
6.3).
Parametrul pPoint este un pointer la o structur de tip POINT. Aceste funcii transform valorile
stocate n structura transmis ca parametru fr s pstreze vechile valori. Remarcai faptul c dac un
punct se afl deasupra zonei client a unei ferestre, n urma transformrii coordonatelor de ecran n
coordonate ale zonei client, valoarea coordonatei pe axa y va fi negativ. Similar, dac un punct se afl
n stnga zonei client a unei ferestre, n urma transformrii coordonatelor de ecran n coordonate ale
zonei client, valoarea coordonatei pe axa x va fi negativ.
Dac v amintii cum am dezactivat toate funciile de sistem activate de la tastatur, prin
interceptarea mesajului WM_SYSKEYDOWN, probabil v ntrebai dac putei s facei ceva
asemntor i prin interceptarea mesajelor generate de mouse. Desigur, putei face acest lucru
incluznd n procedura de fereastr liniile:
case WM_NCHITTEST
return (LRESULT) HTNOWHERE ;
Vei dezactiva toate mesajele de mouse trimise procedurii de fereastr pentru zona client i pentru
poriunile din afara zonei client. Butoanele mouse-ului nu vor mai funciona ct timp indicatorul
mouse-ului se afl n fereastra dumneavoastr, inclusiv deasupra pictogramei meniului sistem, a
butoanelor de redimensionare i a butonului pentru nchiderea ferestrei.
56.
Apsat
Eliberat
WM_LBUTTONDOWN
WM_MBUTTONDOWN
WM_LBUTTONUP
WM_MBUTTONUP
WM_LBUTTONDBLCLK
WM_MBUTTONDBLCLK
Dreapta
WM_RBUTTONDOWN
WM_RBUTTONUP
WM_RBUTTONDBLCLK
Atunci cnd deplasai indicatorul mouse-ului peste zona client a unei ferestre nu se genereaz un
mesaj WM_MOUSEMOVE pentru fiecare pixel peste care trece indicatorul. Numrul mesajelor
WM_MOUSEMOVE depinde de componentele hardware ale mouse-ului i de viteza cu care
procedura de fereastr poate s prelucreze aceste mesaje
57.
Atunci cnd rulai programul BTNLOOK n partea stng a zonei client, sunt afiate diferite tipuri de butoane.
Aa cum am menionat anterior, atunci cnd executai clic pe un buton, controlul de tip fereastr descendent
trimite mesajul WM_COMMAND ctre fereastra printe. Programul BTNLOOK intercepteaz mesajul
WM_COMMAND i afieaz valorile lParam i wParam. Iat ce semnificaie au acestea:
LOWORD (wParam)
Identificatorul ferestrei descendent
HIWORD (wParam)
Codul de ntiinare
lParam
Variabila handle a ferestrei descendent
Dac facei conversia unor programe scrise pentru versiunile pe 16 bii ale sis temului de operare
Windows, reinei c aceti parametri au fost modificai n vederea adaptrii la dimensiunea pointerilor pe 32
de bii.
Identificatorul ferestrei descendent este valoarea transmis funciei CreateWindow la crearea ferestrei
descendent. n programul BTNLOOK, aceti identificatori au valori de la 0 la 9, corespunztoare celor 10
butoane afiate n zona client. Variabila handle a ferestrei descendent este valoarea returnat de funcia
CreateWindow.
Codul de ntiinare este un cod de submesaj pe care fereastra descendent l folosete pentru a transmite
ferestrei printe mai multe informaii despre semnificaia mesajului. Valorile pe care le pot avea aceste coduri
sunt definite n fiierele antet definite n Windows:
Identificatorul codului de ntiinare al butonului
Valoare
BN_CLICKED
0
BN_PAINT
1
BN_HILITE
2
BN_UNHILITE
3
BN_DISABLE
4
BN_DOUBLECLICKED
5
Codurile de ntiinare de la 1 la 5 sunt pstrate pentru compatibilitatea cu un stil nvechit de butoane,
numit BS_SERBUTTON, aa c nu vei ntlni dect codul BN_CLICKED.
58.
Mesajele de la timer. ( e)
60.
Mesajele privind tastatura: acionri de taste i caractere". Taste obinuite i taste de sistem.
WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP. Variabila lParam.
: .
. WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP.
lParam.
Mesajele WM_CREATE, WM_PAINT i WM_DESTROY. WM_CREATE, WM_PAINT
WM_DESTROY.
Procedura de fereastr WndProc din fiierul SYSMETS1.C trateaz trei mesaje: WM_CREATE,
WM_PAINT i WM_DESTROY. Mesajul WM_DESTROY indic faptul c sistemul de operare
desfoar un proces de distrugere a ferestrei pe baza unei comenzi de la utilizator. Mesajul este trimis
atunci cnd utilizatorul execut clic pe butonul Close, selecteaz opiunea Close din meniul sistem sau
apas fastele Alt+F4.
WM_CREATE este primul mesaj pe care l primete procedura de fereastr. Acest mesaj este
generat de Windows atunci cnd funcia Create Window creeaz fereastra. n timpul prelucrrii
mesajului WM_CREATE, se obine un context de dispozitiv pentru fereastr, apelnd funcia GetDC,
i dimensiunile fontului sistem prestabilit, apelnd funcia GetTextMetrics. SYSMETS1 salveaz
limea medie a caracterelor n variabila cxChar i nlimea total (inclusiv spaiul suplimentar
extern) a caracterelor n variabila cyChar.
61.
Mesajul WM_PAINT
Majoritatea programelor Windows apeleaz funcia UpdateWindow n timpul procesului de
iniializare din procedura WinMain, puin dup intrarea n ciclul de tratare a mesajelor. Windows
profit de aceast ocazie ca s trimit ctre procedura ferestrei primul mesaj WM_PAINT. Acest mesaj
informeaz procedura ferestrei c zona client este pregtit pentru desen. Din acest moment, procedura
ferestrei ar trebui s fie pregtit s prelucreze orice mesaj WM_PAINT n urmtoarele situaii:
O zon anterior acoperit a ferestrei este adus la suprafa atunci cnd utilizatorul mut o
fereastr.
Utilizatorul redimensioneaz fereastra (dac stilul clasei ferestrei include seturile de bii
CS_HREDRAW si CS_VREDRAW).
Programul folosete funciile ScrollWindow sau ScrollDC ca s deruleze o parte din zona client a
ferestrei.
Programul folosete funciile InvalidateRect sau InvalidateRgn pentru a genera n mod explicit un
mesaj WM_PAINT.
n anumite cazuri, cnd zona client este acoperit parial cu text, Windows ncearc s salveze o
zon a ecranului, pe care o va restaura mai trziu. Aceast metod, ns, nu d ntotdeauna rezultate
bune. Windows poate trimite, de aceea, un mesaj WM_PAINT, n situaiile n care:
Windows a ters o caset de dialog sau caset de mesaje care acoperea o parte a ferestrei.
Un meniu este tras n jos i apoi eliberat.
Windows salveaz zona de ecran pe care a scris i apoi o restaureaz, n cazurile n care:
Indicatorul mouse-ului este micat n zona client.
O pictogram este tras n zona client.
Tratarea mesajelor WM_PAINT implic revizuirea modului de scriere pe ecran. Programul trebuie
structurat astfel nct s acumuleze toate informaiile necesare pentru redesenarea zonei client, dar s
fac aceast operaie numai la cerere" - atunci cnd Windows i trimite un mesaj WM_PAINT. Dac
programul trebuie s actualizeze zona client, poate fora sistemul de operare s i trimit un mesaj
WM_PAINT. Dei aceast metod de afiare pare ocolitoare, ea contribuie la structurarea programului.
unde hwnd este variabila handle a ferestrei al crei text urmeaz s fie nlocuit, iar pszString este un pointer la
un ir de caractere terminat cu caracterul nul. Pentru o fereastr normal, acesta este textul care va fi afiat n
bara de titlu. Pentru un buton, acesta este textul afiat pe buton.
De asemenea, putei s obinei textul ferestrei curente:
iLength = GetWindowText (hwnd, pszBuffer, iMaxLength) ;
Parametrul iMaxLength specific numrul maxim de caractere care va fi copiat n bufferul adresat de
pointerul pszBuffer. Funcia returneaz lungimea irului de caractere copiat. Putei s pregtii programul
pentru un text de o anumit lungime apelnd mai nti funcia GetWindowTextLength:
iLength = GetWindowTextLength (hwnd) ;
63.
Moduri de desenare. Operaii rastru (ROP - raster operation). Funciile SetROP2, iDrawMode, GetROP2.
. .
Atunci cnd folosete o peni pentru desenarea unei linii, Windows face de fapt o operaie
boolean ntre pixelii peniei i pixelii de pe suprafaa destinaie. Efectuarea operaiei booleene ntre
pixeli se numete operaie rastru" (ROP - raster operation).
Deoarece desenarea unei linii implic numai dou modele de pixeli (penia i destinaia), operaia
boolean se numete operaie rastru binar" sau ROP2. Windows definete 16 coduri ROP2 care
specific modul de combinare ntre pixelii peniei i pixelii suprafeei, n contextul de dispozitiv
prestabilit, modul de desenare definit este R2_COPYPEN, ceea ce nseamn c Windows copiaz
pixelii peniei pe suprafaa destinaie - adic modul normal n care suntem obinuii s funcioneze o
peni. Exist alte 15 coduri ROP2.
Care este originea celor 16 coduri ROP2 diferite? Pentru exemplificare, s presupunem c avem un
sistem monocrom. Culoarea destinaiei (culoarea zonei client a ferestrei) poate fi negru (reprezentat
prin valorea 0) sau alb (1). La fel, culoarea peniei poate fi alb sau negru. Exist patru combinaii
posibile n cazul folosirii unei penie alb/negru pe o suprafa alb/negru: alb pe alb, alb pe negru, negru
pe alb i negru pe negru.
Ce se ntmpl cu destinaia dup ce desenai cu penia? O posibilitate este ca linia s fie desenat
ntotdeauna cu negru, indiferent de culoarea peniei i a destinaiei: acest mod de desenare este indicat
de codul R2_BLACK. O alt posibilitate este ca linia s fie desenat cu negru, exceptnd situaia n
care att penia ct i destinaia sunt negre, caz n care linia este desenat cu alb. Dei pare puin
ciudat, Windows are un nume pentru acest mod de desenare: R2_NOTMERGEPEN. Windows face o
operaie orientat pe bii de tip SAU ntre pixelii destinaie i pixelii peniei, i inverseaz rezultatul.
Tabelul de mai jos prezint toate cele 16 moduri de desenare ROP2. Tabelul indic modul n care
sunt combinate culoarea peniei (P) i culoarea destinaiei (D) pentru obinerea culorii afiate. n
coloana Operaia boolean" sunt folosite notaiile C pentru indicarea modului n care sunt combinai
pixelii peniei cu pixelii destinaiei.
Peni (P):
Destinaie (D):
Rezultate:
1
1
0
1
0
0
0
1
Operaia
boolean
Mod de desenare
0
0
0
R2_BLACK
0
0
0
0
0
0
0
1
1
1
1
1
0
0
0
1
1
1
1
0
0
0
0
1
0
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
0
1
0
~(P | D)
~P & D
~P
P & ~D
~D
P^D
~(P & D)
P&D
~(P ^ D)
D
~P | D
P
R2_NOTMERGEPEN
R2_MASKNOTPEN
R2_NOTCOPYPEN
R2_MASKPENNOT
R2_NOT
R2_XORPEN
R2_NOTMASKPEN
R2_MASKPEN
R2_NOTXORPEN
R2_NOP
R2_MERGENOTPEN
R2_COPYPEN
(prestabilit)
1
1
0
1
P | ~D
R2_MERGEPENNOT
1
1
1
0
P|D
R2_MERGEPEN
1
1
1
1
1
R2_WHITE
Putei s selectai un nou mod de desenare n contextul de dispozitiv astfel:
SetROP2 (hdc, iDrawMode) ;
unde parametrul iDrawMode este una dintre valorile din coloana Mod de desenare" a tabelului de mai
sus. Putei s obinei modul curent de desenare astfel:
iDrawMode = GetROP2 (hdc) ;
Modurile de mapare metrice". Moduri de mapare proprii. Modul de mapare MM_ISOTROPIC. Modul de
mapare MM_ANISOTROPIC sau ajustarea imaginii. .
. MM_ISOTROPIC. MM_ANISOTROPIC:
Windows include dou moduri de mapare n care coordonatele logice sunt exprimate n uniti
fizice. Deoarece coordonatele logice pe axele x i y sunt mapate la uniti fizice identice, aceste moduri
de mapare v ajut s desenai cercuri mai rotunde" i ptrate mai ptrate".
Cele cinci moduri de mapare metrice" sunt prezentate mai jos n ordinea cresctoare a preciziei.
Cele dou coloane din partea dreapt prezint dimensiunile unitilor logice n inci (in.) i n milimetri
(mm) pentru comparare:
Mod de mapare
MM_LOENGLISH
MM_LOMETRIC
MM_HIENGLISH
MM_TWIPS*
MM_HIMETRIC
Uniti logice
0,01 in.
0,1 mm
0,001 in.
1/1440 in.
0,01 mm
Inci
0,001
0,00394
Milimetri
0,254
0,1
0,001
0,0254
0,000694
0,000394
0,0176
0,01
* Un twip este 1/20 dintr-un punct (care este 1/72 dintr-un inci), deci 1 /1440 dintr-un inci.
Ca s putei face o comparaie ntre modul de mapare MM_TEXT i aceste rezoluii, trebuie s v
amintesc faptul c, pe un monitor VGA standard, fiecare pixel este un ptrat cu latura de 0,325 mm,
ceea ce nseamn c coordonatele unui dispozitiv VGA sunt mult mai grosiere dect oricare dintre
modurile de mapare metrice.
Pentru o imprimant laser cu rezoluia de 300 dpi (puncte pe inci) fiecare pixel are 0,0033 inci - o
rezoluie mai mare dect cea a modurilor de mapare MM_LOENGLISH si MM_LOMETRIC, dar mai
mic dect cea a modurilor de mapare MM_HIENGLISH, MM_TWIPS i MM_HIMETRIC.
Originile i extensiile prestabilite sunt urmtoarele:
Originea ferestrei:
Originea vizorului:
Extensia ferestrei:
Extensia vizorului:
(0,0)
(0,0)
(?, ?)
(?, ?)
Poate fi modificat
Poate fi modificat
Nu poate fi modificat
Nu poate fi modificjat
Modul de mapare MM_ISOTROPIC este ideal pentru folosirea unor axe arbitrare, cu uniti logice
egale pe cele dou axe. Dreptunghiurile cu limi i nlimi logice egale sunt afiate ca ptrate.
Elipsele cu limi i nlimi logice egale sunt afiate ca cercuri.
Atunci cnd selectai pentru prima dat modul de mapare MM_ISOTROPIC, Windows folosete
aceleai extensii pentru fereastr i pentru vizor, ca i pentru modul de mapare MM_LOMETRIC.
(Totui, nu v bazai pe acest fapt.) Diferena este c acum putei s schimbai extensiile dup cum
dopi, apelnd funciile SetWindowExtEx i SetViewportExtEx. Windows va ajusta apoi aceste extensii
astfel nct unitile logice de pe ambele axe s reprezinte distane fizice egale.
n general, vei folosi ca parametri ai funciei SetWindowExtEx dimensiunile dorite pentru fereastra
logic, iar ca parametri ai funciei SetViewportExtEx dimensiunile reale ale zonei client. Atunci cnd
ajusteaz aceste extensii, Windows trebuie s ncadreze fereastra logic n vizorul fizic, ceea ce
nseamn c o parte a zonei client poate s rmn n afara ferestrei logice. Pentru folosirea mai
eficient a spaiului din zona client trebuie s apelai funcia SetWindowExtEx nainte de apelarea
funciei SetViewportExtEx.
De exemplu, s presupunem c vrei s folosii un sistem de coordonate virtual, tradiional", cu un
singur cadran n care punctul (0, 0) este colul din stnga-jos al zonei client, iar limea i nlimea au
valori de la 0 la 32.767. Dac dorii ca unitile logice x i y s aib aceleai dimensiuni, iat ce trebuie
s facei:
SetMapMode (hdc, HH_ISOTROPIC) ;
SetWindowExtEx (hdc, 32767, 32767, NULL) ;
SetViewportExtEx (hdc, cxClient, -cyClient, NULL) ;
SetViewportOrgEx (hdc, 0, cyClient, NULL) ;
Dac apoi obinei extensiile ferestrei i ale vizorului apelnd funciile GetWindowExtEx i
GetViewportExtEx vei vedea c acestea au alte valori dect cele specificate. Windows ajusteaz
extensiile n funcie de raportul de afiare (aspect ratio) al dispozitivului, astfel nct unitile logice de
pe cele dou axe s reprezinte aceleai dimensiuni fizice.
Dac zona client este mai mult lat dect nalt (n dimensiuni fizice), Windows ajusteaz extensia
x astfel nct fereastra logic s fie mai mic dect vizorul zonei client. Fereastra logic va fi
poziionat n partea stng a zonei client:
Nu putei s afiai nimic n partea dreapt a zonei client dincolo de captul axei x, deoarece pentru
aceasta ar trebui s folosii o coordonat logic x mai mare de 32.767. Dac zona client este mai mult
nalt dect lat (n dimensiuni fizice), Windows ajusteaz extensia y. Fereastra logic va fi poziionat
n partea de jos a zonei client:
Nu putei s afiai nimic n partea de sus a zonei client dincolo de captul axei y, deoarece pentru
aceasta ar trebui s folosii o coordonat logic y mai mare de 32.767. Dac preferai ca fereastra
logic s fie poziionat ntotdeauna n partea stng i n partea de sus a zonei client, putei s
modificai astfel codul precedent:
SetMapMode (hdc, HH_ISOTROPIC) ;
SetWindowExtEx (hdc, 32767, 32767, NULL) ;
SetViewportExtEx (hdc, cxClient, -cyClient, NULL) ;
SetWindowOrgEx (hdc, 0, 32767, NULL) ;
n acest fel, prin apelul funciei SetWihdowOrgEx precizm c dorim ca punctul logic (0,32767) s
fie mapat la punctul de dispozitiv (0,0). Dac zona client este mai mult nalt dect lat, sistemul de
coordonate este poziionat astfel:
Pentru imaginile de genul celei folosite de programul ANACLOCK putei s folosii un sistem de
coordonate cartezian cu patru cadrane avnd axe arbitrar scalate n cele patru direcii i cu punctul
de coordonate (0, 0) n centrul zonei client. Dac, de exemplu, vrei ca fiecare ax s ia valori de la
0 la 1000, folosii codul urmtor:
SetMapMode (hdc, MM_ISOTROPIC) ;
SetWindowExtEx (hdc, 1000, 1000, NULL);
SetViewportExtEx (hdc, cxClient/2, -cyClient/2, NULL) ;
SetViewportOrgEx (hdc, cxClient/2, cyCllent/2, NULL) ;
Dac zona client este mai mult lat dect nalt, sistemul logic de coordonate arat astfel:
Sistemul logic de coordonate este centrat i atunci cnd zona client este mai mult nalt dect lat:
Reinei faptul c extensiile ferestrei i ale vizorului nu implic nici o operaie de decupare. La
apelarea funciilor GDI putei s folosii pentru coordonatele x i y valori mai mici de -1000 sau mai
mari de +1000. n funcie de forma zonei client, aceste puncte pot s fie sau s nu fie vizibile.
Folosind modul de mapare MM_ISOTROPIC putei s facei ca unitile logice s fie mai mari
dect pixelii. De exemplu, s presupunem c dorii s creai un sistem de coordonate n care punctul de
coordonate (0, 0) se afl n colul din stnga-sus al ecranului i valorile de pe axa y cresc de sus n jos
(ca n modul de mapare MM_TEXT) dar cu coordonate logice msurate n uniti de 1/16 dintr-un inci.
Acest mod de mapare v-ar permite s desenai o rigl avnd un capt n colul din stnga-sus al zonei
client, cu diviziuni de aisprezecimi de inci:
SetMapMode (hdc, MM_ISOTROPIC) ;
SetWindowExtEx(hdc, 160*GetDeviceCaps (hdc, HORZSIZE)/254,160*GetDeviceCaps(hdc, VERTSIZE)/254, NULL);
SetViewportExtEx(hdc, GetDeviceCaps(hdc, HORZRES),GetDeviceCaps(hdc, VERTRES), NULL);
n aceast secven de cod extensiile vizorului sunt stabilite la dimensiunile n pixeli ale ntregului
ecran. Extensiile ferestrei trebuie s fie stabilite la dimensiunile ntregului ecran n uniti de
aisprezecimi de inci. Indicii HORZSIZE i VERTSIZE ai funciei GetDeviceCaps returneaz
dimensiunile dispozitivului n milimetri. Dac lucrai cu numere n virgul mobil, trebuie s
transformai milimetrii n inci mprind valorile obinute la 2,54, i apoi s transformai incii n
aisprezecimi de inci nmulind rezultatul operaiei anterioare cu 16. Deoarece aici lucrm cu numere
ntregi, am nmulit rezultatul cu 160 i l-am mprit la 254.
Pentru majoritatea dispozitivelor, acest cod face ca unitile logice s fie mult mai mari dect
unitile fizice. Tot ce desenai pe dispozitiv va avea pentru coordonate valori mapate la multipli de
1/16 inci. Nu putei s desenai dou linii orizontale aflate la distana de 1/32 de inci, deoarece pentru
aceasta ai avea nevoie de o coordonat logic fracionar.
Modul de mapare MM_ANISOTROPIC sau ajustarea imaginii
Atunci cnd stabilii extensiile ferestrei i pe ale vizorului n modul de mapare MM_ISOTROPIC,
Windows ajusteaz valorile astfel nct unitile logice de pe cele dou axe s aib aceleai dimensiuni.
n modul de mapare MM_ANISOTROPIC, Windows nu face nici o ajustare a valorilor pe care le
stabilii. Aceasta nseamn c n modul de mapare MM_ANISOTROPIC nu este obligatorie pstrarea
raportului corect de afiare.
Pentru a folosi modul de mapare MM_ANISOTROPIC, stabilii un sistem arbitrar de coordonate
pentru zona client, ca i pentru modul de mapare MM_ISOTROPIC. Codul de mai jos stabilete
punctul de coordonate (0, 0) n colul din stnga-jos al zonei client, iar axele de coordonate x i y pot
lua valori de la 0 la 32.767:
SetMapMode (hdc, MM_ANISOTROPIC) ;
SetWindowExtEx (hdc, 32767, 32767, NULL) ;
SetViewportExtEx (hdc, cxClient, -cyClient, NULL) ;
SetViewportOrgEx (hdc, 0, cyClient, NULL) ;
65.
Modurile de mapare
Pn acum am presupus c toate desenele se fac ntr-un sistem de coordonate raportate la colul,
din stnga-sus al zonei client i folosind ca unitate de msur pixelul. Acesta este modul de lucru
prestabilit, dar nu este singurul mod de lucru.
Un atribut al contextului de dispozitiv care afecteaz aproape toate operaiile de desenare din zona
client este modul de mapare" (mapping mode"). Alte patru atribute ale contextului de dispozitiv originea ferestrei, originea vizorului (viewport), extensia ferestrei i extensia vizorului - sunt strns
legate de modul de mapare.
Majoritatea funciilor GDI primesc coordonate sau dimensiuni ca parametri. Iat, ca exemplu,
funcia TextOut:
TextOut (hdc, x, y, szBuffer, iLength) ;
Parametrii x i y indic poziia n care ncepe textul. Parametrul x reprezint poziia pe axa
orizontal, iar parametrul y reprezint poziia pe axa vertical. Deseori, pentru indicarea acestui punct
este folosit notaia (x, y).
n funcia TextOut i, de fapt, n toate funciile GDI, coordonatele sunt furnizate n uniti logice".
Windows trebuie s transforme unitile logice" n uniti de dispozitiv", adic n pixeli. Aceast
transformare este guvernat de modul de mapare, de originile ferestrei, ale vizorului i de extensiile
ferestrei i ale vizorului. De asemenea, modul de mapare stabilete i orientarea axelor x i y, adic
determin sensul n care cresc valorile coordonatelor x i y.
Windows definete opt moduri de mapare. Acestea sunt prezentate n tabelul urmtor, folosind
identificatorii definii n fiierele antet din Windows:
Mod de mapare
MM_TEXT
MM_LOMETRIC
MM_HIMETRIC
MM_LOENGLISH
MM_HIENGLISH
MM_TWIPS
MM_ISOTROPIC
MM_ANISOTROPIC
Uniti logice
Pixel
0,1 mm
0,01mm
0,01 mei
0,001 inci
1/1440 inci
Arbitrar (x = y)
Arbitrar (x != y)
unde iMapMode este unul dintre cei opt identificatori definii pentru modurile de mapare. Putei s
obinei modul de mapare curent folosind funcia GefMapMode:
iMapMode = GetMapMode (hdc) ;
Twip este un cuvnt fabricat, care nseamn a douzecea parte dintr-un punct" (twentieth of a point"). Un punct - unitate de msur folosit n
tipografie - este aproximativ egal cu 1/72 dintr-un inci, dar n sistemele grafice precum GDI se consider de cele mai multe ori c este exact 1/72 dintr-un
inci. Un twip este 1/20 dintr-un punct, deci 1/1440 dintr-un inci.
Modul de mapare prestabilit este MM_TEXT. n acest mod de mapare unitile logice sunt aceleai
cu unitile fizice, ceea ce v permite (sau, privind dintr-o alt perspectiv, v foreaz) s lucrai n
pixeli. ntr-un apel al funciei TextOut care arat astfel:
TextOut (hdc, 8, 16, szBuffer, iLength) ;
textul ncepe la o distan de opt pixeli fa de marginea din stnga a zonei client i de 16 pixeli fa de
marginea de sus a acesteia.
Dac modul de mapare este MM_LOENGLISH, o unitate logic este egal cu o sutime de inci:
SetMapHode (hdc, HM_LOENGLISH) ;
Textul afiat ncepe la 0,5 inci fa de marginea din stnga i la 1 inci fa de marginea de sus a
zonei client. (Motivul folosirii unei valori negative pentru coordonata y va deveni evident ceva mai
trziu, atunci cnd vom discuta n detaliu despre modurile de mapare.) Celelalte moduri de mapare
permit programului s specifice coordonatele n milimetri, n puncte pentru imprimant sau ntr-un
sistem de coordonate arbitrar.
Dac vi se pare convenabil folosirea pixelilor ca unitate de msur, putei s folosii numai modul
de mapare MM_TEXT. Dac trebuie s afiai o imagine la dimensiunile reale n inci sau milimetri,
putei s obinei informaiile necesare cu ajutorul funciei GetDeviceCaps i s facei singur scalarea.
Celelalte moduri de mapare sunt doar metode convenabile de evitare a acestor operaii de scalare.
Indiferent de modul de mapare folosit, toate coordonatele specificate la apelarea funciilor
Windows trebuie s fie numere ntregi cu semn avnd valori de la -32 768 la 32 767. n plus, unele
funcii care folosesc coordonate pentru punctele de nceput i de sfrit ale unui dreptunghi cer ca
limea i nlimea dreptunghiului s nu depeasc 32 767.
Coordonate de dispozitiv i coordonate logice
S-ar putea s v punei urmtoarea ntrebare: Dac folosesc modul de mapare MM_LOENGLISH
voi primi mesajele WM_SIZE n sutimi de inci?" Bineneles c nu. Windows va folosi n continuare
coordonatele de dispozitiv pentru toate mesajele (cum ar fi WM_SIZE, WM_MOVE i
WM_MOUSEMOVE), pentru toate funciile care nu fac parte din interfaa GDI i chiar pentru unele
funcii GDI. Lucrurile se petrec n felul urmtor: modul de mapare fiind un atribut al contextului de
dispozitiv, are efect numai atunci cnd folosii funcii GDI care primesc o variabil handle a
contextului de dispozitiv ca parametru. GetSystemMetrics nu este o funcie GDI, aa c va returna n
continuare dimensiunile n uniti de dispozitiv, adic n pixeli. Dei GetDeviceCaps este o funcie
GDI care primete ca parametru o variabil handle a contextului de dispozitiv, Windows continu s
returneze uniti de dispozitiv pentru identificatorii HORZRES i VERTRES, deoarece unul dintre
scopurile acestei funcii este s furnizeze programului dimensiunea n pixeli a dispozitivului.
Totui, valorile din structura TEXTMETRIC pe care le obinei prin apelarea funciei
GetTextMetrics sunt furnizate n uniti logice. Dac modul de mapare este MM_LOENGLISH n
momentul apelrii funciei, GetTextMetrics returneaz limea i nlimea caracterelor, n sutimi de
inci. Atunci cnd apelai funcia GetTextMetrics ca s obinei nlimea i limea caracterelor, modul
de mapare trebuie s fie acelai cu cel pe care l vei folosi atunci cnd afiai textul pe baza acestor
dimensiuni. Pe msur ce voi prezenta diferite funcii GDI n acest capitol, voi preciza dac acestea
utilizeaz coordonate logice sau coordonate de dispozitiv. Toate funciile despre care am discutat pn
acum utilizeaz coordonate logice, exceptnd cele pentru stabilirea spaiilor ntre puncte sau liniue
pentru stilurile de linii i ntre liniile de haur din modele. Acestea sunt independente de modul de
mapare.
Sistemele de coordonate ale dispozitivului
Pentru afiarea culorilor este nevoie de mai muli bii. Cu ct se folosesc mai muli bii, cu att pot
fi afiate mai multe culori. Sau, mai precis, numrul culorilor care pot fi afiate simultan este egal cu 2
la o putere egal cu numrul de bii folosii. De obicei, biii sunt organizai n planuri de culori - un
plan pentru rou, un plan pentru verde, unul pentru albastru i unul pentru intensitatea culorii.
Adaptoarele video cu 8,16 sau 24 de bii pentru fiecare pixel au un singur plan de culoare, n care un
numr de bii adiaceni reprezint culoarea fiecrui pixel.
Funcia GetDeviceCaps v permite s determinai modul de organizare a memoriei n adaptoarele
video i numrul de culori care pot fi reprezentate. Apelul de mai jos returneaz numrul de planuri de
culoare:
iPlanes = GetDeviceCaps (hdc, PLANES);
Apelul urmtor returneaz numrul de bii de culoare folosii pentru fiecare pixel:
iBitsPixel = GetDeviceCaps (hdc, BITSPIXEL)
Majoritatea adaptoarelor video care pot afia culori folosesc fie mai multe planuri de culoare, fie
mai muli bii de culoare pentru fiecare pixel, dar nu pe amndou; cu alte cuvinte, unul dintre cele
dou apeluri de mai sus va returna valoarea 1. Numrul de culori care pot fi redate de o plac video se
poate calcula cu formula urmtoare:
iColors = 1<<(iPlanes * iBitsPixel);
Aceast valoare poate s nu fie identic cu numrul de culori obinut prin apelarea funciei
GetDeviceCaps cu parametrul NUMCOLORS:
iColors = GetDeviceCaps (hdc, NUMCOLORS);
De exemplu, cele dou numere vor fi diferite pentru majoritatea plotterelor. n cazul unui plotter,
PLANES i BITSPIXEL vor avea valoarea 1, dar NUMCOLORS va reprezenta numrul de penie pe
care le folosete plotterul. Pentru dispozitivele monocrome, funcia GetDeviceCaps apelat cu
parametrul NUMCOLORS returneaz valoarea 2.
107PARTEA 1 NCEPUTUL
Aceste valori pot fi diferite i n cazul adaptoarelor video care permit ncrcarea paletelor de culori.
Funcia GetDeviceCaps apelat cu parametrul NUMCOLORS returneaz numrul de culori rezervate
de Windows, adic 20. Celelalte 236 de culori pot fi stabilite de program folosind un manager de
palete.
Windows folosete pentru reprezentarea culorilor o valoare ntreag fr semn, pe 32 de bii. Tipul
de date folosit pentru culori se numete COLORREF. Ultimii trei octei ai numrului (cei mai puin
semnificativi) specific valorile pentru culorile rou, verde i albastru, de la O la 255, aa cum se poate
vedea n Figura 4-3. Rezult o palet potenial de 224 culori (aproximativ 16 milioane de culori).
Astfel, valoarea
RGB (255, 0, 255)
este de fapt 0x00FF00FF, valoarea RGB pentru magenta. Dac toate cele trei argumente au valoarea 0,
se obine negrul, iar dac au valoarea 255, se obine albul. Macroinstruciunile GetRValue, GetGValue
i GetBValue extrag valorile pentru culorile primare, sub forma unor octei fr semn, din valoarea
RGB a culorii. Aceste macroinstructiuni sunt utile atunci cnd apelai funcii Windows care returneaz
culori RGB.
Numrul de culori returnat de funcia GetDeviceCaps reprezint numrul de culori pure pe care le
poate afia dispozitivul respectiv. Windows poate s foloseasc amestecarea culorilor - aceasta implic
folosirea unui model de pixeli de diferite culori - pentru reprezentarea altor culori n afara celor pure.
Nu toate combinaiile de valori pentru rou, verde i albastru produc modele diferite de amestecare a
culorilor. De exemplu, n cazul unui monitor VGA pe care pot fi afiate 16 culori, valorile pentru rou,
verde i albastru trebuie s fie incrementate cu patru, ca s genereze un model diferit de amestecare. Ca
urmare, pentru aceste tipuri de adaptoare avei la dispoziie 218 (sau 262.144) culori amestecate.
Putei s determinai cea mai apropiat culoare pur pentru o anumit valoare apelnd funcia
GetNearestColor:
rgbPureColor = GetNearestColor (hdc, rgbColor) ;
67.
Obinerea variabilei handle a contextului de dispozitiv. Obinerea informaiilor despre contextul de dispozitiv.
Variabila ps este o structur de tip PAINTSTRUCT. Cmpul hdc al acestei structuri conine
variabila handle a contextului de dispozitiv. Structura PAINTSTRUCT conine i o structur de tip
RECT numit rcPaint, care definete dreptunghiul ce cuprinde regiunea invalid a zonei client a
ferestrei. Folosind variabila handle a contextului de dispozitiv, obinut prin apelarea funciei
BeginPaint, nu putei s desenai dect n regiunea invalid a ferestrei. Funcia BeginPaint valideaz
regiunea invalid.
Programele Windows pot s obin variabila handle a contextului de dispozitiv i n timpul
prelucrrii altor mesaje dect WM_PAINT:
hdc = GetDC (hwnd);
(alte linii de program] ReleaseDC (hwnd, hdc);
Acest context de dispozitiv se aplic zonei client a ferestrei care are variabila handle hwnd.
Principala diferen ntre apelul de mai sus i metoda folosirii funciilor BeginPaint i EndPaint este c
variabila handle returnat de funcia GetDC v permite s desenai n toat zona client a ferestrei. n
plus, funciile GetDC i ReleaseDC nu valideaz eventualele regiuni invalide ale zonei client.
Un program Windows poate s obin i o variabil handle a unui context de dispozitiv care se
aplic ntregii ferestre, nu numai zonei client a ferestrei:
hdc = GetWindowDC (hwnd);
[alte linii de program] ReleaseDC (hwnd, hdc);
Contextul de dispozitiv include, n afar de zona client, bara de titlu a ferestrei, barele de derulare
i chenarul. Funcia GetWindowDC este rareori folosit de aplicaii. Dac vrei s experimentai
folosirea acestei funcii, trebuie s interceptai mesajele WM_NCPAINT (nonclient paint"),
mpiedicnd sistemul de operare s redeseneze poriunile din fereastr care nu fac parte din zona client.
Funciile BeginPaint, GetDC i GetWindowDC obin variabila handle a contextului de dispozitiv
asociat unei anumite ferestre de pe ecran. O funcie mai general pentru obinerea variabilei handle a
unui context de dispozitiv este CreateDC:
hdc = CreateDC (pszDriver, pszDevice, pszOutput, pData);
[alte linii de program] DeleteDC (hdc);
De exemplu, putei s obinei variabila handle a contextului de dispozitiv pentru tot spaiul de
afiare, cu urmtorul apel:
hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
Scrierea n afara ferestrei proprii nu este n general recomandat, dar poate fi convenabil pentru
unele aplicaii speciale. (Dei aceast metod nu e documentat, se poate obine o variabila handle a
contextului de dispozitiv pentru ntregul ecran i prin apelarea funciei GetDC, cu parametrul NULL.)
n Capitolul 15 vom folosi funcia CreateDC pentru a obine o variabil handle a contextului de
dispozitiv pentru o imprimant.
Uneori avei nevoie de unele informaii despre un context de dispozitiv fr s desenai nimic. n
aceast situaie putei s obinei o variabila handle a contextului de informaii (information context")
folosind funcia CreateIC. Parametrii sunt aceiai ca i pentru funcia CreateDC:
hdclnfo = CreatelC ("DISPLAY", NULL, NULL, NULL);
[alte linii de program] DeleteDC (hdclnfo);
Nu putei s executai operaii de scriere la un dispozitiv folosind aceast variabil handle. Atunci
cnd lucrai cu imagini bitmap, poate fi uneori util obinerea unui context de dispozitiv n memorie":
Acesta este un concept destul de abstract. n esen, putei s selectai o imagine bitmap ntr-un
context de dispozitiv n memorie i apoi s desenai peste folosind funciile GDI. Vom discuta mai
trziu despre aceast tehnic i o vom folosi n programul GRAFMENU din Capitolul 10.
Aa cum am menionat mai devreme, un metafiier este o colecie de apeluri GDI codificate ntr-o
form binar. Putei s creai un metafiier prin obinerea unui context de dispozitiv pentru metafiiere:
hdcMeta = CreateMetaFile (pszFilename);
[alte linii de program] hmf = CloseMetaFile (hdcMeta);
Ct timp acest context este valid, nici un apel GDI pe care l facei folosind parametrul hdcMeta nu
afieaz nimic pe ecran, ci devine parte a metafiierului. Apelai apoi funcia CloseMetaFile i
contextul de dispozitiv este invalidat. Funcia returneaz o variabil handle a metafiierului (hmf).
Obinerea informaiilor despre contextul de dispozitiv
Parametrul iIndex este unul dintre cei 28 de identificatori definii n fiierele antet din Windows.
De exemplu, dac iIndex are valoarea HORZRES funcia GetDeviceCaps returneaz limea
dispozitivului n pixeli; VERTRES returneaz nlimea dispozitivului n pixeli. Dac hdc este o
variabil handle a contextului de dispozitiv pentru un monitor video, informaiile obinute sunt aceleai
cu cele returnate de funcia GetSystemMetrics. Dac hdc este o variabil handle a contextului de
dispozitiv pentru o imprimant, funcia GetDeviceCaps returneaz nlimea i limea zonei pe care
imprimant o poate tipri.
Putei s folosii funcia GetDeviceCaps i ca s obinei informaii despre posibilitile unui
dispozitiv de prelucrare a anumitor tipuri de elemente grafice. Aceast posibilitate nu este important
pentru ecran, dar poate fi folosit n cazul imprimantelor. De exemplu, majoritatea plotterelor nu pot
tipri imagini bitmap - iar funcia GetDeviceCaps v poate comunica acest lucru.
68.
69.
Funcii care stabilesc sau obin atribute ale contextului de dispozitiv. Un atribut" al contextului
de dispozitiv specific modul de lucru al funciilor de desenare. De exemplu, folosii funcia
SetTextColor ca s precizai culoarea textului afiat cu funcia TextOut (sau cu o alt funcie de
afiare a textului). n programele SYSMETS din Capitolul 3 am folosit funcia SetTextAlign ca s
artm interfeei GDI faptul c poziia de nceput a irului de caractere este n partea dreapt a
irului de caractere, nu n partea stng, aa cum se ntmpl de obicei. Toate atributele contextului
de dispozitiv au valori prestabilite, care devin active la obinerea contextului de dispozitiv. Pentru
fiecare funcie de tip Set exist i o funcie Get corespondent, folosit pentru obinerea valorilor
curente ale atributelor contextului de dispozitiv.
Pensule haurate". Stiluri de haura. Funcia CreatePatternBrush. .
. CreatePatternBrush.
Atunci cnd Windows folosete metoda amestecrii culorilor (dithering) pentru afiarea unui
numr mai mare de culori dect ar fi n mod normal disponibile pe monitorul respectiv, de fapt
folosete o pensul pentru fiecare culoare. Pe un ecran monocrom, Windows poate s afieze 64 de
tonuri de gri prin amestecarea pixelilor pentru alb cu cei pentru negru. Pentru negru toi biii din
matricea 8x8 au valoarea zero. Unul dintre cei 64 de bii are valoarea 1 (adic alb) pentru primul ton de
gri, doi bii au valoarea 1 pentru al doilea ton de gri i aa mai departe, pn cnd toi cei 64 de bii au
valoarea 1 ca s se obin albul pur. n cazul unui monitor color, culorile amestecate sunt tot imagini
bitmap, dar domeniul disponibil de culori este mult mai mare.
Windows conine patru funcii pe care putei s le folosii pentru crearea pensulelor logice.
Selectai o pensul n contextul de dispozitiv folosind funcia Select-Object. Ca i peniele logice,
pensulele logice sunt obiecte GDI. Trebuie s tergei toate pensulele pe care le-ai creat, dar nu trebuie
s le tergei ct timp sunt selectate n contextul de dispozitiv.
Iat prima funcie pentru crearea unei pensule logice:
hBrush = CreateSolidBrush (rgbColor) ;
Cuvntul Solid din numele acestei funcii nu nseamn c pensula folosete o culoare pur. Atunci
cnd selectai pensula n contextul de dispozitiv, Windows creeaz o imagine bitmap 8x8 pentru
culorile amestecate i folosete imaginea respectiv atunci cnd este necesar pensula selectat.
Putei s creai i o pensul haurat" cu linii orizontale, verticale sau oblice. Acest stil de pensule
este folosit frecvent pentru colorarea barelor din diagrame sau grafice i pentru desenele executate de
plottere. Funcia care creeaz o pensul haurat este:
hBrush = CreateHatchBrush (iHatchStyle, rgbColor) ;
Parametrul iHatchStyle precizeaz aspectul haurii i poate avea una dintre urmtoarele valori:
HS_HORIZONTAL, HS_VERTICAL, HS_FDIAGONAL, HS_BDIAGONAL, HS_CROSS i
HS_DIAGCROSS. Figura 4-18 prezint haurile produse de fiecare dintre stilurile de mai sus.
Parametrul rgbColor din funcia CreateHatchBrush reprezint culoarea liniilor cu care se face
haurarea. Atunci cnd selectai pensula n contextul de dispozitiv, Windows convertete aceast
culoare n cea mai apropiat culoare pur. Spaiul dintre liniile de haur sunt colorate n funcie de
modul de desenare a fondului i de culoarea fondului, definite n contextul de dispozitiv. Dac modul
de desenare a fondului este OPAQUE, culoarea fondului (care este convertit, la rndul ei, ntr-o
culoare pur) este folosit pentru umplerea spaiilor dintre linii, n acest caz, nici liniile de haur, nici
culoarea de umplere nu pot fi culori amestecate. Dac modul de desenare a fondului este
TRANSPARENT, Windows deseneaz liniile de haura fr s umple spaiile dintre acestea.
Vom discuta despre aceast funcie n seciunea rezervat imaginilor bitmap din capitolul de fa.
Windows conine o funcie care poate nlocui toate celelalte trei funcii de creare a pensulelor
(CreateSolidBrush, CreateHatchBrush i CreatePatternBrush):
Variabila logbrush este o structur de tip LOGBRUSH (logical brush"). Cele trei cmpuri ale
structurii sunt prezentate mai jos. Valoarea cmpului lbStyle determin modul n care Windows
interpreteaz celelalte dou cmpuri:
lbStyle (UINT)
lbColor (COLORREF) lbHatch (LONG)
BS_SOLID
Culoarea pensulei
Ignorat
BS_HOLLOW
Ignorat
Ignorat
BS_HATCHED Culoarea haurii
Stilul de haur
BS_PATTERN
Ignorat
Variabila handle a unei imagini bitmap
Am folosit mai devreme funcia SelectObject ca s selectm n contextul de dispozitiv o peni
logic, funcia DeleteObject ca s tergem o peni logic i funcia GetObject ca s obinem informaii
despre o peni logic. Putei s folosii aceleai funcii i pentru pensule. Dac avei o variabil handle
a unei pensule, putei s selectai pensula n contextul de dispozitiv folosind funcia SelectObject:
SelectObject (hdc, hBrush) ;
Totui, nu tergei pensula selectat n contextul de dispozitiv. Dac vrei s obinei informaii
despre o pensul, apelai funcia GetObject:
GetObject (hBrush, sizeof (LOGBRUSH), (LPVOID) &logbrush) ;
Redesenarea zonei client. Ciclul de mesaje. Structura de tip MSG. Funciile GetMessage, TranslateMessage,
DispatchMessage.
. . MSG.
GetMessage, TranslateMessage, DispatchMessage.
UpdateWindow (hwnd) ;
determin redesenarea zonei client. Acest lucru se face prin trimiterea ctre procedura de fereastr
(funcia WndProc din HELLOWIN.C) a unui mesaj WM_PAINT. Vom vedea imediat cum trateaz
funcia WndProc aceste mesaje.
Acest apel transmite sistemului de operare un pointer, numit msg, la o structur de tip MSG. Al
doilea, al treilea i al patrulea parametru au valoarea NULL sau 0, ceea ce indic faptul c programul
vrea s preia toate mesajele, pentru toate ferestrele create de program. Windows completeaz
cmpurile structurii de mesaje cu urm torul mesaj din coada de ateptare. Cmpurile acestei structuri
sunt:
hwnd - variabila handle a ferestrei creia i este destinat mesajul. n pro gramul HELLOWIN,
aceasta este aceeai cu valoarea hwnd returnat de funcia CreateWindow, deoarece aceasta este
singura fereastr a programului.
message - identificatorul mesajului. Acesta este un numr folosit pentru identificarea mesajului.
Pentru fiecare mesaj n fiierele antet din Windows este definit un identificator care ncepe cu
prefixul WM_ (window message"). De exemplu, dac poziionai indicatorul mouse-ului n zona
client a programului HELLOWIN i apsai butonul din stnga, Windows va insera n coada de
ateptare un mesaj pentru care cmpul message conine identificatorul WM_LBUTTONDOWN,
adic valoarea 0x0201.
LONG x ;
LONG y ;
}
POINT ;
Funcia GetMessage apelat la nceputul ciclului de mesaje preia un mesaj din coada de ateptare:
GetMessage (&msg, NULL, 0, 0)
Acest apel transmite sistemului de operare un pointer, numit msg, la o structur de tip MSG. Al
doilea, al treilea i al patrulea parametru au valoarea NULL sau 0, ceea ce indic faptul c programul
vrea s preia toate mesajele, pentru toate ferestrele create de program. Windows completeaz
cmpurile structurii de mesaje cu urm torul mesaj din coada de ateptare. Cmpurile acestei structuri
sunt:
hwnd - variabila handle a ferestrei creia i este destinat mesajul. n pro gramul HELLOWIN,
aceasta este aceeai cu valoarea hwnd returnat de funcia CreateWindow, deoarece aceasta este
singura fereastr a programului.
message - identificatorul mesajului. Acesta este un numr folosit pentru identificarea mesajului.
Pentru fiecare mesaj n fiierele antet din Windows este definit un identificator care ncepe cu
prefixul WM_ (window message"). De exemplu, dac poziionai indicatorul mouse-ului n zona
client a programului HELLOWIN i apsai butonul din stnga, Windows va insera n coada de
ateptare un mesaj pentru care cmpul message conine identificatorul WM_LBUTTONDOWN,
adic valoarea 0x0201.
wParam - un parametru pe 32 de bii a crui valoare depinde de mesajul trimis.
lParam - un alt parametru pe 32 de bii dependent de mesaj.
time - momentul inserrii mesajului n coada de mesaje.
pt - coordonatele poziiei mouse-ului n momentul inserrii mesajului n coada de mesaje.
Dac n cmpul message este transmis orice alt valoare dect WM_QUIT (egal cu 0x0012),
funcia GetMessage returneaz o valoare diferit de zero. Mesajul WM_QUIT determin ieirea din
ciclul de mesaje. Programul se ncheie, returnnd valoarea parametrului wParam al structurii msg.
Instruciunea:
TranslateMessage (&msg) ;
retransmite structura msg sistemului de operare, pentru convertirea unor mesaje de la tastatur.
Instruciunea:
DispatchMessage (&msg) ;
ca i funcia TranslateMessage, retransmite structura msg sistemului de operare. Windows trimite apoi
mesajul ctre procedura de fereastr corespunztoare, n vederea prelucrrii - cu alte cuvinte, Windows
apeleaz procedura de fereastr. n programul HELLOWIN, procedura de fereastr este WndProc.
Dup ce prelucreaz mesajul, funcia WndProc pred controlul sistemului de operare, care nc
elaboreaz rspunsul la apelul DispatchMessage. Atunci cnd Windows returneaz controlul
programului HELLOWIN, dup executarea apelului DispatchMessage, ciclul de tratare a mesajelor
continu cu urmtorul apel al funciei GetMessage.
71.
72.
(0, 0)
Poate fi modificat
Originea vizorului:
Extensia ferestrei:
Extensia vizorului:
(0, 0)
(1, 1)
(1, 1)
Poate fi modificat
Nu poate fi modificat
Nu poate fi modificat
Raportul din extensia ferestrei i extensia vizorului este 1, aa c nu este necesar nici o operaie de
scalare pentru transformarea coordonatelor logice n coordonate de dispozitiv. Formulele prezentate
anterior se reduc la acestea:
xViewport = xWindow - xWinOrg + xViewOrg
yViexport = yWindow - yWinOrg + yViewOrg
Acest mod de mapare se numete mapare de tip text", nu fiindc este cea mai potrivit pentru text,
ci datorit orientrii axelor. n general, citim textul de la stnga spre dreapta i de sus n jos, iar n
modul de mapare MM_TEXT, valorile cresc n acelai sens:
Valorile logice ale axei x sunt cuprinse n intervalul de la -cxClient/2 la +cxClient/2 iar valorile
logice ale axei y sunt cuprinse n intervalul de la -cyClient/2 la +cyClient/2. Colul din dreapta-jos al
zonei client are coordonatele (cxClient/2, cyClient/2). Dac vrei s afiai text ncepnd din colul din
stnga-sus al zonei client, care are coordonatele de dispozitiv (0, 0), trebuie s folosii coordonate
logice negative:
TextOut (hdc, -cxClient/2, -cyClient/2, "Hello", 5) ;
Aceasta nseamn c punctul logic (-cxClient/2, -cyClient/2) este mapat la punctul de dispozitiv
(cxClient/2, cyClient/2), rezultnd urmtorul sistem de coordonate:
unde pt este o structur de tip POINT. Valorile returnate de funcia GetViewportOrgEx sunt n
coordonate de dispozitiv, iar valorile returnate de funcia GetWindowOrgEx sunt n coordonate logice.
Uneori este de dorit s modificai originea ferestrei sau a vizorului ca s deplasai imaginea afiat
pe ecran - de exemplu, ca rspuns la acionarea barei de derulare de ctre utilizator. Modificarea
originii nu determin deplasarea imediat a imaginii afiate. Mai nti modificai originea, apoi
redesenai ecranul. De exemplu, n programul SYSMETS2 din Capitolul 2 am folosit valoarea
iVscrollPos (poziia curent a casetei de derulare de pe bara de derulare vertical) ca s ajustm
coordonatele de afiare pe axa y:
case WM_PAINT :
BeginPaint (hwnd, &ps) ;
for 0 = 0; i<NUMLINES ; i++)
{
y = cyChar * (1 - iVscrollPos + 1) ;
[afieaz textul]
}
EndPaint (hwnd, &ps) ;
return 0 ;
y = cyChar * (1 + i) ;
[afieaz textul]
}
EndPaint (hwnd, &ps) ;
return 0 ;
Acum nu mai este nevoie s fie folosit valoarea iVscrollPos pentru calcularea coordonatei y
pentru funcia TextOut. Aceasta nseamn c putei s apelai funciile de afiare a textului dintr-o
subrutin, fr s transmitei subrutinei valoarea iVscrollPos, deoarece ajustarea poziiei de afiare a
textului s-a fcut prin modificarea originii ferestrei.
Dac ai mai lucrat cu sistemele de coordonate rectangulare (carteziene), probabil deplasarea
punctului logic de coordonate (0, 0) n centrul zonei client vi se pare o operaie logic. Totui, modul
de mapare MM_TEXT prezint o mic problem: de obicei, ntr-un sistem de coordonate cartezian,
valorile de pe axa y cresc n sus, pe cnd n modul de mapare MM_TEXT acestea cresc n jos. In acest
sens, modul de mapare MM_TEXT este un caz izolat, aceast problem fiind corectat de celelalte
cinci moduri de mapare.
Modul de mapare prestabilit este MM_TEXT. n acest mod de mapare unitile logice sunt aceleai
cu unitile fizice, ceea ce v permite (sau, privind dintr-o alt perspectiv, v foreaz) s lucrai n
pixeli. ntr-un apel al funciei TextOut care arat astfel:
TextOut (hdc, 8, 16, szBuffer, iLength) ;
73.
Umplerea golurilor
Folosirea penielor pentru linii punctate sau pentru linii ntrerupte ridic o ntrebare interesant: ce
se ntmpl cu pauzele dintre puncte sau dintre liniue? Culoarea acestor spaii depinde de atributele
pentru culoarea fondului i de modul de desenare a fondului, definite n contextul de dispozitiv.
Modul prestabilit de desenare a fondului este OPAQUE, ceea ce nseamn c Windows umple
spaiile cu culoarea fondului, care n mod prestabilit este alb. Rezultatele sunt aceleai n cazul
pensulei WHITE_BRUSH, folosit de majoritatea programelor n clasa ferestrei pentru tergerea
fondului.
Putei s schimbai culoarea fondului pentru completarea spaiilor goale dintre linii, prin apelarea
funciei SetBkColor:
SetBkColor (hdc, rgbColor) ;
Ca i n cazul valorii rgbColor folosit pentru culoarea peniei, Windows convertete valoarea
specificat ntr-o culoare pur. Putei s obinei culoarea defint n contextul de dispozitiv prin
apelarea funciei GetBkColor.
De asemenea, putei s mpiedicai colorarea spaiilor stabilind modul TRANSPARENT de
desenare a fondului:
SetBkMode (hdc, TRANSPARENT) ;
Windows va ignora culoarea fondului i nu va mai colora spaiile goale. Modul de desenare a
fondului (TRANSPARENT sau OPAQUE) poate fi obinut cu ajutorul funciei GetBkMode.
74.
Un program de afiare a ceasului este cea mai evident aplicaie pentru un cronometru, aa c vom
prezenta un ceas digital i un ceas analogic. Programul DIGCLOCK, prezentat n Figura 7-5, creeaz o
fereastr popup, care se poziioneaz n colul din dreapta-sus al ecranului. Programul afieaz ziua, data i ora,
aa cum se poate vedea n Figura 7-6.
Toate programele prezentate pn acum au folosit pentru cel de-al treilea parametru al funciei
CreateWindow stilul de fereastr WS_OVERLAPPEDWINDOW. n programul DIGCLOCK este folosit
stilul de fereastr:
Prima metod
Prima metod (i cea mai simpl) determin sistemul de operare s trimit mesajele
WM_TIMER ctre procedura de fereastr normal a aplicaiei. Apelul funciei SetTimer arat astfel:
SetTimer (hwnd, 1, iMsecInterval, NULL);
Primul parametru este o variabil handle pentru fereastra a crei procedur de fereastr va primi
mesajele WM_TIMER. Al doilea parametru este identificatorul cronometrului, care trebuie s fie o valoare
diferit de zero i care n acest exemplu este n mod arbitrar 1. Al treilea parametru este o valoare ntreag fr
semn pe 32 de bii, care specific intervalul de timp n milisecunde. Dac acest parametru are valoarea
60000, programul va primi un mesaj WM_TIMER la fiecare minut. Putei s oprii generarea mesajelor
WM_TIMER n orice moment, chiar i n timpul prelucrrii unui mesaj WM_TIMER, apelnd funcia:
Al doilea parametru al funciei KillTimer este acelai identificator cu cel folosit la apelarea funciei
SetTimer. naintea terminrii programului, ca rspuns la mesajul WM_DESTROY, este recomandat s
distrugei toate cronometrele active din program.
Atunci cnd procedura de fereastr primete un mesaj WM_TIMER, parametrul wParam conine
identificatorul cronometrului (care n acest caz este 1) iar parametrul lParam este 0. Dac avei nevoie de mai
multe cronometre, folosii un identificator unic pentru fiecare. Valoarea parametrului wParam va diferenia
mesajele WM_TIMER trimise ferestrei. Pentru ca programul s fie mai uor de citit, putei s folosii
instruciuni define pentru definirea identificatorilor fiecrui cronometru:
#define TIMERSEC 1
#define TIMERMIN 2
Apoi putei s creai cele dou cronometre prin apelarea funciei SetTimer:
case WM_TIMER :
switch (wParam)
{
case TIMERSEC :
[operaii de prelucrare la fiecare secunda]
break ;
case TIMERMIN :
77.
Prima metod de folosire a cronometrelor determin trimiterea mesajelor WM _TIMER ctre procedura
normal de fereastr. A doua metod v permite s folosii un cronometru astfel nct Windows s trimit
mesajele WM_TIMER ctre o alt funcie din program.
Funcia care recepioneaz mesajele de cronometru este numit funcie cu apel invers (callback). Aceasta
este o funcie din program care poate fi apelat direct de sistemul de operare. Programul comunic
sistemului de operare adresa funciei, iar sistemul de operare Windows apeleaz ulterior funcia. Acest mod
de lucru ar trebui s vi se par cunoscut, deoarece procedura de fereastr a unui program este tot o funcie
cu apel invers. Atunci cnd nregistrai clasa de fereastr i comunicai sistemului de operare adresa procedurii de
fereastr i Windows apeleaz apoi procedura de fereastr atunci cnd trimite mesaje ctre program.
SetTimer nu este singura funcie Windows care folosete funcii cu apel invers. Funciile CreateDialog i
DialogBox (despre care vom discuta n Capitolul 14) folosesc funcii cu apel invers pentru prelucrare mesajelor
trimise ctre casetele de dialog; mai multe funcii Windows (cum ar fi EnumChildWindows, EnumFonts,
EnumObjects, EnumProps i EnumWindows) transmit informaii de tip enumerare unor funcii cu apel
invers; i alte funcii mai puin folosite, cum ar fi GrayString, LineDDA si SetWindowsHookEx) impun
folosirea unor funcii cu apel invers.
Ca i procedurile de fereastr, funciile cu apel invers trebuie s fie definite de tipul CALLBACK, deoarece
sunt apelate de Windows din afara spaiului de cod al programului. Parametrii transmii funciilor cu apel
invers i valoarea returnat de acestea depind de scopul funciei. n cazul unei funcii cu apel invers
asociate unui cronometru, parametrii de intrare sunt aceiai cu parametrii de intrare ai unei proceduri de
fereastr. Funciile cu apel invers folosite pentru cronometre nu returneaz nici o valoare ctre sistemul de
operare.
Presupunem c funcia cu apel invers se numete TimerProc. (Putei s dai orice nume dorii.) Aceast
funcie va prelucra numai mesajele WM_TIMER.
VOID CALLBACK TimerProc (HWND hwnd, UINT iMsg, UINT iTimerlD, DWORD
dwTime) [prelucreaz mesajele WM_TIMER]
Parametrul de intrare hwnd reprezint variabila handle a ferestrei specificate la apelarea funciei SetTimer.
Windows va trimite funciei TimerProc numai mesajele WM_TIMER, aa c parametrul iMsg va avea
ntotdeauna valoarea WM_TIMER. Parametrul iTimerlD conine identificatorul cronometrului, iar
parametrul dwTime reprezint timpul sistemului.
Aa cum am menionat anterior, prima metod de pornire a unui cronometru impune apelarea funciei
SetTimer n felul urmtor:
78.
A treia metod
A treia metod este asemntoare cu cea de-a doua, cu diferena c parametrul hwnd din apelul funciei
SetTimer are valoare NULL, iar al doilea parametru (care ar fi trebuit sa fie identificatorul cronometrului)
este ignorat. Rezultatul este faptul c funcia SetTimer returneaz un identificator al cronometrului:
Variabilele handle. Notaia ungar. Punctul de intrare n program. nregistrarea clasei de fereastr. Crearea
ferestrei. Afiarea ferestrei.
handle. . .
Arhitectura .NET Framework. Compilarea programelor. De ce am alege .NET?
2. Platforma .NET
2.1. Prezentare
.NET este un cadru (framework) de dezvoltare software unitar care permite realizarea,
distribuirea i rularea aplicaiilor-desktop Windows i aplicaiilor WEB.
Tehnologia .NET pune laolalt mai multe tehnologii (ASP, XML, OOP, SOAP, WDSL,
UDDI) i limbaje de programare (VB, C++, C#, J#) asigurnd totodat att portabilitatea
codului compilat ntre diferite calculatoare cu sistem Windows, ct i reutilizarea codului n
programe, indiferent de limbajul de programare utilizat.
.NET Framework este o component livrat npreun cu sistemul de operare Windows.
De fapt, .NET 2.0 vine cu Windows Server 2003 i Windows XP SP2 i se poate instala pe
versiunile anterioare, pn la Windows 98 inclusiv; .NET 3.0 vine instalat pe Windows Vista i
poate fi instalat pe versiunile Windows XP cu SP2 i Windows Server 2003 cu minimum SP1.
Pentru a dezvolta aplicatii pe platforma .NET este bine sa avem 3 componente eseniale:
un set de limbaje (C#, Visual Basic .NET, J#, Managed C++, Smalltalk, Perl, Fortran,
Cobol, Lisp, Pascal etc),
un set de medii de dezvoltare (Visual Studio .NET, Visio),
i o bibliotec de clase pentru crearea serviciilor Web, aplicaiilor Web i aplicaiilor
desktop Windows.
Cnd dezvoltm aplicaii .NET, putem utiliza:
Servere specializate - un set de servere Enterprise .NET (din familia SQL Server 2000,
Exchange 2000 etc), care pun la dispoziie funcii de stocare a bazelor de date, email,
aplicaii B2B (Bussiness to Bussiness comer electronic ntre partenerii unei afaceri).
Servicii Web (n special comerciale), utile n aplicaii care necesit identificarea
utilizatorilor (de exemplu, .NET Passport - un mod de autentificare folosind un singur
nume i o parol pentru toate ste-urile vizitate)
Servicii incluse pentru dispozitive non-PC (Pocket PC Phone Edition, Smartphone,
Tablet PC, Smart Display, XBox, set-top boxes, etc.)
2.2. .NET Framework
Componenta .NET Framework st la baza tehnologiei .NET, este ultima interfa ntre
aplicaiile .NET i sistemul de operare i actualmente conine:
Limbajele C#, VB.NET, C++ i J#. Pentru a fi integrate n platforma .NET toate aceste
limbaje respect nite specificaii OOP numite Common Type System (CTS). Ele au
ca elemente de baz: clase, interfee, delegri, tipuri valoare i referin, iar ca
mecanisme: motenire, polimorfism i tratarea excepiilor.
Platforma comun de executare a programelor numit Common Language Runtime
(CLR), utilizat de toate cele 4 limbaje.
Ansamblul de biblioteci necesare n realizarea aplicaiilor desktop sau Web numit
Framework Class Library (FCL).
81.
definit n clasa Console. Cum n spaiul de nume curent este definit doar clasa Program,
deducem c definiia clasei Console trebuie s se gseasc n spaiul System.
Pentru a facilita cooperarea mai multor programatori la realizarea unei aplicaii
complexe, exist posibilitatea de a segmenta aplicaia n mai multe fiiere numite
assemblies. ntr-un assembly se pot implementa mai multe spaii de nume, iar pari ale unui
aceeai spaiu de nume se pot regsi n mai multe assembly-uri. Pentru o aplicaie consol,
ca i pentru o aplicaie Windows de altfel, este obligatoriu ca una (i numai una) dintre clasele
aplicaiei s conin un punct de intrare (entry point), i anume metoda (funcia) Main.
S comentm programul de mai sus:
linia 1: este o directiv care specific faptul c se vor folosi clase incluse n spaiul de nume
System. n cazul nostru se va folosi clasa Console.
linia 3: spaiul nostru de nume
linia 5: orice program C# este alctuit din una sau mai multe clase
linia 7: metoda Main, punctul de intrare n program
linia 9: clasa Console, amintit mai sus, este folosit pentru operaiile de intrare/ieire. Aici
se apeleaz metoda WriteLine din acest clas, pentru afiarea mesajului dorit pe ecran.
3.5. Sintaxa limbajului
Ca i limbajul C++ cu care se nrudete, limbajul C# are un alfabet format din litere
mari i mici ale alfabetului englez, cifre i alte semne. Vocabularul limbajului este format din
acele simboluri27 cu semnificaii lexicale n scrierea programelor: cuvinte (nume), expresii,
separatori, delimitatori i comentarii.
Comentarii
comentariu pe un rnd prin folosirea // Tot ce urmeaz dup caracterele // sunt
considerate, din acel loc, pn la sfritul rndului drept comentariu
// Acesta este un comentariu pe un singur rand
comentariu pe mai multe rnduri prin folosirea /* i */ Orice text cuprins ntre
simbolurile menionate mai sus se consider a fi comentariu. Simbolurile /* reprezint
nceputul comentariului, iar */ sfritul respectivului comentariu.
/* Acesta este un
comentariu care se
intinde pe mai multe randuri */
Nume
Prin nume dat unei variabile, clase, metode etc. nelegem o succesiune de caractere
care ndeplinete urmtoarele reguli:
numele trebuie s nceap cu o liter sau cu unul dintre caracterele _ i @;
primul caracter poate fi urmat numai de litere, cifre sau un caracter de subliniere;
numele care reprezint cuvinte cheie nu pot fi folosite n alt scop dect acela
pentru care au fost definite
cuvintele cheie pot fi folosite n alt scop numai dac sunt precedate de @
dou nume sunt distincte dac difer prin cel puin un caracter (fie el i liter mic
ce difer de aceeai liter majuscul)
Convenii pentru nume:
n cazul numelor claselor, metodelor, a proprietilor, enumerrilor, interfeelor,
spaiilor de nume, fiecare cuvnt care compune numele ncepe cu majuscul
n cazul numelor variabilelor dac numele este compus din mai multe cuvinte,
primul ncepe cu minuscul, celelalte cu majuscul
Cuvinte cheie n C#
83.
variabilelor; complicaiile apar atunci cnd la program sunt asignai doi sau mai muli
programatori care nu pot lucra simultan pe un acelai fiier ce conine codul surs.
Programarea modular (gruparea subprogramelor cu
funcionaliti similare n module, implementate i depanate
separat); se obin avantaje privind independena i
ncapsularea (prin separarea zonei de implementare,
pstrnd vizibilitatea numai asupra zonei de interfa a
modulului) i se aplic tehnici de asociere a procedurilor cu
datele pe care le manevreaz, stabilind i diferite reguli de
acces la date i la subprograme.
Se observ c modulele sunt centrate pe proceduri,
acestea gestionnd i setul de date pe care le prelucreaz
(date+date1 din figur). Daca, de exemplu, dorim s avem mai multe seturi diferite de date,
toate nzestrate comportamental cu procedurile din modulul module1, aceast arhitectur de
aplicaie nu este avantajoas.
Programarea orientat obiect (programe cu noi tipuri ce
integreaz att datele, ct i metodele asociate crerii,
prelucrrii i distrugerii acestor date); se obin avantaje prin
abstractizarea programrii (programul nu mai este o succesiune
de prelucrri, ci un ansamblu de obiecte care prind via, au
diverse proprieti, sunt capabile de aciuni specifice i care
interacioneaz n cadrul programului); intervin tehnici noi privind
instanierea, derivarea i polimorfismul tipurilor obiectuale.
1.2. Tipuri de date obiectuale. ncapsulare
Un tip de date abstract (ADT) este o entitate caracterizat printr-o structur de date i
un ansamblu de operaii aplicabile acestor date. Considernd, n rezolvarea unei probleme
de gestiune a accesului utilizatorilor la un anumit site, tipul abstract USER, vom obseva c
sunt multe date ce caracterizeaz un utilizator Internet. Totui se va ine cont doar de datele
semnificative pentru problema dat. Astfel, culoarea ochilor este irelevant n acest caz, n
timp ce data naterii poate fi important. n aceeai idee, operaii specifice ca se
nregistreaz, comand on-line pot fi relevante, n timp ce operaia mannc nu este, n
cazul nostru. Evident, nici nu se pun n discuie date sau operaii nespecifice (numrul de
laturi sau aciunea zboar).
Operaiile care sunt accesibile din afara entitii formeaz interfaa acesteia. Astfel,
operaii interne cum ar fi conversia datei de natere la un numr standard calculat de la
01.01.1900 nu fac parte din interfaa tipului de date abstract, n timp ce operaia plaseaz o
comand on-line face parte, deoarece permite interaciunea cu alte obiecte (SITE, STOC etc.)
O instan a unui tip de date abstract este o concretizare a tipului respectiv, format
din valori efective ale datelor.
Un tip de date obiectual este un tip de date care implementeaz un tip de date abstract.
Vom numi operaiile implementate n cadrul tipului de date abstract metode. Spunem c
datele i metodele sunt membrii unui tip de date obiectual. Folosirea unui astfel de tip
presupune: existena definiiei acestuia, apelul metodelor i accesul la date.
Un exemplu de-acum clasic de tip de date abstract este STIVA. Ea poate avea ca date:
numerele naturale din stiv, capacitatea stivei, vrful etc. Iar operaiile specifice pot fi:
introducerea n stiv (push) i extragerea din stiv (pop). La implementarea tipului STIVA,
vom defini o structura de date care s rein valorile memorate n stiv i cmpuri de date
simple pentru: capacitate, numr de elemente etc. Vom mai defini metode (subprograme)
capabile s creeze o stiv vid, care s introduc o valoare n stiv, s extrag valoarea din
vrful stivei, s testeze dac stiva este vid sau dac stiva este plin etc.
Crearea unei instane noi a unui tip obiectual, presupune operaii specifice de
construire a noului obiect, metoda corespunztoare purtnd numele de constructor. Analog,
la desfiinarea unei instane i eliberarea spaiului de memorie aferent datelor sale, se aplic
o metod specific numit destructor1
.
O aplicaie ce utilizeaz tipul obiectual STIVA, va putea construi dou sau mai multe
stive (de cri de joc, de exemplu), le va umple cu valori distincte, va muta valori dintr-o stiv
n alta dup o anumit regul desfiinnd orice stiv golit, pn ce rmne o singur stiv.
De observat c toate aceste prelucrri recurg la datele, constructorul, destructorul i la
metodele din interfaa tipului STIVA descris mai sus.
Principalul tip obiectual ntlnit n majoritatea mediilor de dezvoltare (Viisual Basic,
Delphi, C++, Java, C#) poart numele de clas (class). Exist i alte tipuri obiectuale (struct,
object). O instan a unui tip obiectual poart numele de obiect.
clas abstract trebuie obligatoriu derivat, deoarece direct din ea nu se pot obine obiecte
prin operaia de instaniere, n timp ce o clas sigilat (sealed) nu mai poate fi derivat (e un
fel de terminal n ierarhia claselor). O metod abstract este o metod pentru care nu este
definit o implementare, aceasta urmnd a fi realizat n clasele derivate din clasa curent4
.
O metod sigilat nu mai poate fi redefinit n clasele derivate din clasa curent.
1.5. Polimorfism. Metode virtuale
Folosind o extensie a sensului etimologic, un obiect polimorfic este cel capabil s ia
diferite forme, s se afle n diferite stri, s aib comportamente diferite. Polimorfismul
obiectual5
se manifest n lucrul cu obiecte din clase aparinnd unei ierarhii de clase, unde,
prin redefinirea unor date sau metode, se obin membri diferii avnd ns acelai nume.
Astfel, n cazul unei referiri obiectuale, se pune problema stabilirii datei sau metodei referite.
Comportamentul polimorfic este un element de flexibilitate care permite stabilirea
contextual, n mod dinamic6
, a membrului referit.
De exemplu, dac este definit clasa numit PIESA (de ah), cu metoda nestatic
muta(pozitie_initiala,pozitie_finala), atunci subclasele TURN i PION trebuie
s aib metoda muta definit n mod diferit (pentru a implementa maniera specific a
pionului de a captura o pies en passant7
). Atunci, pentru un obiect T, aparinnd claselor
reduce diferenele dintre operarea la nivel abstract (cu DTA) i apelul metodei ce realizeaz acest
operaie la nivel de implementare obiectual. Dei ajut la sporirea expresivitii codului, prin
suprancrcarea operatorilor i metodelor se pot crea i confuzii. 4
care trebuie s fie i ea abstract (virtual pur, conform terminologiei din C++) 5
deoarece tot aspecte polimorfice mbrac i unele tehnici din programarea clasic sau tehnica
suprancrcrcrii funciilor i operatorilor. 6
Este posibil doar n cazul limbajelor ce permit legarea ntrziat. La limbajele cu "legare
timpurie", adresa la care se face un apel al unui subprogram se stabilete la compilare. La limbajele
cu legare ntrziat, aceast adresa se stabileste doar in momentul rulrii, putndu-se calcula distinct,
n funcie de contextul n care apare apelul. 7
ntr-o alt concepie, metoda muta poate fi implementat la nivelul clasei PIESA i redefinit
la nivelul subclasei PION, pentru a particulariza acest tip de deplasare care captureaz piesa peste
care trece pionul n diagonal. 6 POO i Programare vizual (suport de curs)
derivate din PIESA, referirea la metoda muta pare nedefinit. Totui mecanismele POO
permit stabilirea, n momentul apelului, a clasei proxime creia i aparine obiectul T i
apelarea metodei corespunztore (mutare de pion sau tur sau alt pies).
Pentru a permite acest mecanism, metodele care necesit o decizie contextual (n
momentul apelului), se decalr ca metode virtuale (cu modificatorul virtual). n mod
curent, n C# modificatorului virtual al funciei din clasa de baz, i corespunde un
specificator override al funciei din clasa derivat ce redefinete funcia din clasa de baz.
O metod ne-virtual nu este polimorfic i, indiferent de clasa creia i aparine
obiectul, va fi invocat metoda din clasa de baz.
86.
STRUCTURA UNEI APLICAII ORIENTAT PE OBIECTE N C#. Clas de baz i clase derivate.
3.4. Structura unui program C#
S ncepem cu exemplul clasic Hello World adaptat la limbajul C#:
1 using System;
2
3 namespace HelloWorld
4{
5 class Program
6{
7 static void Main()
8{
9 Console.WriteLine("Hello World!");
10 }
11 }
12 }
O aplicatie C# este format din una sau mai multe clase, grupate n spaii de nume
(namespaces). Un spaiu de nume cuprinde mai multe clase cu nume diferite avnd
funcionaliti nrudite. Dou clase pot avea acelai nume cu condiia ca ele s fie definite n
spaii de nume diferite. n cadrul aceluiai spaiu de nume poate aprea definiia unui alt
spaiu de nume, caz n care avem de-a face cu spaii de nume imbricate. O clas poate fi
identificat prin numele complet (nume precedat de numele spaiului sau spaiilor de nume
din care face parte clasa respectiv, cu separatorul punct). n exemplul nostru,
HelloWorld.Program este numele cu specificaie complet al clasei Program.
O clas este format din date i metode (funcii). Apelarea unei metode n cadrul clasei
n care a fost definit aceasta presupune specificarea numelui metodei. Apelul unei metode
definite n interiorul unei clase poate fi invocat i din interiorul altei clase, caz n care este
necesar specificarea clasei i apoi a metodei separate prin punct. Dac n plus, clasa
aparine unui spaiu de nume neinclus n fiierul curent, atunci este necesar precizarea
tuturor componentelor numelui: spaiu.clas.metod sau spaiu.spaiu.clas.metod etc.
n fiierul nostru se afl dou spaii de nume: unul definit (HelloWorld) i unul extern
inclus prin directiva using (System). Console.Writeln reprezint apelul metodei Writeln
definit n clasa Console. Cum n spaiul de nume curent este definit doar clasa Program,
deducem c definiia clasei Console trebuie s se gseasc n spaiul System.
Pentru a facilita cooperarea mai multor programatori la realizarea unei aplicaii
complexe, exist posibilitatea de a segmenta aplicaia n mai multe fiiere numite
assemblies. ntr-un assembly se pot implementa mai multe spaii de nume, iar pari ale unui
aceeai spaiu de nume se pot regsi n mai multe assembly-uri. Pentru o aplicaie consol,
ca i pentru o aplicaie Windows de altfel, este obligatoriu ca una (i numai una) dintre clasele
aplicaiei s conin un punct de intrare (entry point), i anume metoda (funcia) Main.
S comentm programul de mai sus:
linia 1: este o directiv care specific faptul c se vor folosi clase incluse n spaiul de nume
System. n cazul nostru se va folosi clasa Console.
linia 3: spaiul nostru de nume
linia 5: orice program C# este alctuit din una sau mai multe clase
linia 7: metoda Main, punctul de intrare n program
linia 9: clasa Console, amintit mai sus, este folosit pentru operaiile de intrare/ieire. Aici
se apeleaz metoda WriteLine din acest clas, pentru afiarea mesajului dorit pe ecran.
87.
1.3. Suprancrcare
Dei nu este o tehnic specific programrii orientat obiect, ea creeaz un anumit
context pentru metodele ce formeaz o clas i modul n care acestea pot fi (ca orice
subprogram) apelate.
Prin suprancarcare se nelege posibilitatea de a defini n acelai domeniu de
vizibilitate2
mai multe funcii cu acelai nume, dar cu parametri diferiti ca tip i/sau ca numr.
Astfel ansamblul format din numele funciei i lista sa de parametri reprezint o modalitate
unic de identificare numit semntur sau amprent. Suprancrcarea permite obinerea
unor efecte diferite ale apelului n contexte diferite3
.
1
Datorit tehnicii de suprancrcare C++, Java i C# permit existena mai multor constructori 2
Noiunile generale legate de vizibilitate se consider cunoscute din programarea procedural.
Aspectele specifice i modificatorii de acces/vizibilitate pot fi studiai din documentaiile de referin C#. 3
Capacitatea unor limbaje (este i cazul limbajului C#) de a folosi ca nume al unui
subprogram un operator, reprezint suprancrcarea operatorilor. Aceasta este o facilitate care Programarea Orientat Obiect
(POO) 5
Apelul unei funcii care beneficiaz, prin suprancrcare, de dou sau mai multe
semnturi se realizeaz prin selecia funciei a crei semntur se potrivete cel mai bine cu
lista de parametri efectivi (de la apel).
Astfel, poate fi definit metoda comand on-line cu trei semnturi diferite:
comanda_online(cod_prod) cu un parametru ntreg (desemnnd comanda unui singur
produs identificat prin cod_prod.
comanda_online(cod_prod,cantitate) cu primul parametru ntreg i celalalt real
comanda_online(cod_prod,calitate) cu primul parametru ntreg i al-II-ilea caracter.
1.8. Constructori
Sintaxa:
[atrib]o [modificatori]o [nume_clas] ([list_param_formali]o) [:iniializator]o [corp_constr]o
Modificatori: public protected internel private extern
Iniializator: base([list_param]o), this([list_param]o) ce permite invocarea unui constructor
anume12 nainte de executarea instruciunilor ce formeaz corpul constructorului curent. Dac
nu este precizat niciun iniializator, se asociaz implicit iniializatorul base().
Corpul constructorului este format din instruciuni care se execut la crearea unui nou obiect al
clasei respective (sau la crearea clasei, n cazul constructorilor cu modificatorul static).
pot exista mai muli constructori care se pot diferenia prin lista lor de parametri
constructorii nu pot fi motenii
dac o clas nu are definit niciun constructor, se va asigna automat constructorul fr
parametri al clasei de baz (clasa object, dac nu este precizat clasa de baz)
Instanierea presupune declararea unei variabile de tipul clasei respective i iniializarea
acesteia prin apelul constructorului clasei (unul dintre ei, dac sunt definii mai muli)
precedat de operatorul new. Acestea se pot realiza i simultan ntr-o instruciune de felul:
[Nume_clas] [nume_obiect]=new [Nume_clas] ([list_param]o)
Utilizarea unui constructor fr parametri i a constructorului implicit n clas derivat
public abstract class Copil
{ protected string nume;
public Copil() {nume = Console.ReadLine();} //la iniializarea obiectului se citete
//de la tastatur un ir de caractere ce va reprezenta numele copilului
}
class Fetita:Copil {}
...
Fetita f=new Fetita();
Copil c= new Copil(); //Pentru clasa Copil abstract, s-ar fi obinut eroare aici
Suprancrcarea constructorilor i definirea explicit a constructorilor n clase derivate
public class Copil
{ protected string nume; //dat acceesibil numai n interiorul clasei i claselor derivate
public Copil() {nume = Console.ReadLine();}
public Copil(string s) {nume=s;}
}
class Fetita:Copil
{ public Fetita(string s):base(s) {nume=Fetita +nume}13
public Fetita(){} //preia constructorul fr parametri din clasa de baz14
//public Fetita(string s):base() {nume=s}
}
...
Copil c1= new Copil(); //se citeste numele de la tastatur
Copil c2= new Copil(Codrina);
Fetita f1=new Fetita();Fetita f2=new Fetita("Ioana);
Exist dou motive pentru care definiia constructorului al treilea din clasa Fetita este greit
i de aceea este comentat. Care sunt aceste motive?
1.9. Destructor
Sintaxa: [atrib]o [extern]o ~[nume_clas] () [corp_destructor]o
Corpul destructorului este format din instruciuni care se execut la distrugerea unui
obiect al clasei respective. Pentru orice clas poate fi definit un singur constructor. Destructorii
12 Din clasa de baz (base) sau din clasa insi (this) 13 Preia i specializeaz constructorul al doilea din clasa de baz 14
Este echivalent cu public Fetita():base(){} 8 POO i Programare vizual (suport de curs)
nu pot fi motenii. n mod normal, destructorul nu este apelat n mod explicit, deoarece
procesul de distrugere a unui obiect este invocat i gestionat automat de Garbagge Collector.
1.10. Metode
Sintaxa:[atrib]o[modificatori]o[tip_returnat] [nume] ([list_param_formali]o) [corp_metoda]o
Modificatori: new public protected internal private static virtual abstract
sealed override extern15
Tipul rezultat poate fi un tip definit sau void. Numele poate fi un simplu identificator sau, n
cazul n care definete n mod explicit un membru al unei interfee, numele este de forma
[nume_interfata].[nume_metoda]
Lista de parametri formali este o succesiune de declarri desprite prin virgule, declararea
unui parametru avnd sintaxa: [atrib]o [modificator]o [tip] [nume]
Modificatorul unui parametru poate fi ref (parametru de intrare i ieire) sau out (parametru
care este numai de ieire). Parametrii care nu au niciun modificator sunt parametri de intrare.
Un parametru formal special este parametrul tablou cu sintaxa: [atrib]o params [tip][] [nume].
Pentru metodele abstracte i externe, corpul metodei se reduce la un semn ;
Semntura fiecrei metode este format din numele metodei, modificatorii acesteia,
numrul i tipul parametrilor16
Numele metodei trebuie s difere de numele oricrui alt membru care nu este metod.
La apelul metodei, orice parametru trebuie s aib acelai modificator ca la definire
Invocarea unei metode se realizeaz prin sintagma [nume_obiect].[nume_metoda] (pentru
metodele nestatice) i respectiv [nume_clas].[nume_metoda] (pentru metodele statice).
Definirea datelor i metodelor statice corespunztoare unei clase
public class Copil
{ public const int nr_max = 5; //constant
public static int nr_copii=0; //cmp simplu (variabil)
static Copil[] copii=new Copil[nr_max]; //cmp de tip tablou (variabil)
public static void adaug_copil(Copil c) //metod
{ copii[nr_copii++] = c;
if (nr_copii==nr_max) throw new Exception("Prea multi copii");
}
public static void afisare() //metod
{
Console.WriteLine("Sunt {0} copii:", nr_copii);
for (int i = 0; i<nr_copii; i++)
Console.WriteLine("Nr.{0}. {1}", i+1, copii[i].nume);
} ...17
}
...
Fetita c = new Fetita();Copil.adaug_copil(c);
referina noului obiect se memoreaz n tabloul static copii (caracteristic clasei) i se
incrementeaz data static nr_copii
Baiat c = new Baiat(); Copil.adaug_copil(c);
Copil c = new Copil(); Copil.adaug_copil(c);
Copil.afisare();//se afieaz o list cu numele celor 3 copii
15 Poate fi folosit cel mult unul dintre modificatorii static, virtual I override ; nu pot aprea
mpreun new i override, abstract nu poate s apar cu niciunul dintre static, virtual, sealed, extern;
private nu poate s apar cu niciunul dintre virtual, override i abstract; seald oblig i la override 16 Din semntur
(amprent) nu fac parte tipul returnat, numele parametrilor formali i nici
specificatorii ref i out. 17 Se are n vedere i constructorul fr parametri definit i preluat implicit n subclasele din cadrul
primului exemplu din subcapitolul 1.8: public Copil() {nume = Console.ReadLine();} Programarea Orientat Obiect (POO)
9
Definirea datelor i metodelor nestatice corespunztoare clasei Copil i claselor derivate
public class Copil
{ ...
public string nume;
public virtual void se_joaca() //virtual se poate suprascrie la derivare
{Console.WriteLine("{0} se joaca.", this.nume);}
public void se_joaca(string jucaria) //nu permite redefinire18
{Console.WriteLine("{0} se joaca cu {1}.", this.nume, jucaria);}
} //suprancrcarea metodei se_joaca
class Fetita:Copil
{ public override void se_joaca() //redefinire comportament polimorfic
{Console.WriteLine("{0} leagana papusa.",this.nume);}
}
class Baiat:Copil
{ public override void se_joaca()
{Console.WriteLine("{0} chinuie pisica.",this.nume);}
}
...
Fetita c = new Fetita();c.se_joaca("pisica");c.se_joaca(); //polimorfism
Baiat c = new Baiat();c.se_joaca("calculatorul");c.se_joaca(); //polimorfism
Copil c = new Copil();c.se_joaca(); //polimorfism
Pentru a evidenia mai bine comportamentul polimorfic, propunem secvena
urmtoare n care nu se tie exact ce este obiectul copii[i] (de tip Copil, Fetita sau Baiat?):
for (int i=0; i<nr_copii; i++) copii[i].se_joaca;
88.
89.
pot i redefini (de exemplu, clasa Credit_acordat redefinete metoda calc din clasa Investiie,
deoarece formula de calcul implementat acolo nu i se potrivete i ei26).
De exemplu, dac presupunem c toate clasele subliniate implementeaz interfaa
VENIT, atunci pentru o avere cu aciuni la dou firme, un imobil nchiriat i o depunere la
banc, putem determina venitul total:
Actiune act1 = new Actiune();Actiune act2 = new Actiune();
I_inchiriat casa = new I_inchiriat();Depunere dep=new Depunere();
Venit[] venituri = new Venit()[4];
venituri[0] = act1; venituri[1] = act2;
venituri[2] = casa; venituri[3] = dep;
...
int t=0;
for(i=0;i<4;i++) t+=v[i].calc();
Gsii dou motive pentru care interfaa VENIT i rezovarea de mai sus ofer o soluie
mai bun dect: t=act1.calc()+act2.calc()+casa.calc()+dep.calc().
90.
Atunci cand programam este aproape imposibil sa nu primim erori: de sintaxa (abatere de la sintaxa limbajului de
programare), de logica (greseli in logica programului) sau erori la executie (exceptii).
O exceptie reprezinta o eroare care intervine la runtime, la momentul executiei. In C#, exceptiile se pot trata intr-o maniera
structurata si controlata, acest lucru insemanand faptul ca programatorul nu trebuie sa mai verifice manual daca o operatie
se executa sau nu cu succes.
C# defineste exceptii standard pentru tipurile de erori obisnuite dintr-un program. De exemplu: impartire la zero, depasirea
capacitatii unui vector, memorie insuficienta, etc.
Blocurile Try Catch Finally
Cuvintele cheie in C# rezervate pentru tratarea exceptiilor sunt try, catch, finally, throw. Acestea reprezinta un sistem
unitar, utilizarea unuia dintre ele implicand si utilizarea altuia.
Intr-un bloc try vom scrie instructiunile care trebuie verificate pentru aparitia erorilor. Daca pe parcursul executiei acestor
intructiuni apare o exceptie, aceasta este aruncata, lansata (thrown).
Cu ajutorul lui catch programul poate intercepta exceptia si o poate trata in functie de logica programului. Instructiunile
din catch se executa doar daca se lanseaza o exceptie.
Instructiunile din finally se vor executa intotdeauna.
O imagine de ansamblu a codului folosit pentru tratarea exceptiilor:
try
{
//in this block exception may get thrown
}
catch
{
//handle exception
}
finally
{
//cleanup code, optionally
}
Cuvantul cheie try nu poate aparea fara a fi completat de cuvantul cheie catch sau definally si nici invers. Finally este
optional.
Un exemplu simplu de tratare a exceptiei DivideByZeroException si de folosire a blocului try catch finally:
try
{
int x = 0;
//raise the exception
int y = 4 / x;
}
catch
{
//catch the exception
Console.WriteLine("X must be greater than zero");
}
finally
{
//this code will be allways executed
Console.WriteLine("Program completed");
Console.Read();
}
Pot exista mai multe instructiuni catch asociate unui try. Instructiunea care se va executa se va stabili in functie de tipul
exceptiei, celelalte sunt ignorate.
static void Compute(int [] numbers)
{
try
{
int secondNumber = numbers[0];
Console.Write(secondNumber);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Must provide more than an argument");
}
catch (NullReferenceException)
{
Console.WriteLine("Argument is null");
}
catch (FormatException)
{
Console.WriteLine("Argument is not a number");
}
catch (Exception)
{
Console.WriteLine("Another exception occured");
}
}
Se adauga instructiunile pentru blocurile catch cat mai specifice, inainte celor generale.
CLR cauta instructiunea catch care va trata exceptia. Daca metoda curenta in care ne aflam cu debug-erul nu contine un
bloc catch, atunci CLR va cauta in metoda care a apelat metoda curenta, si asa mai departe conform call stack. Daca nu
este gasit nici un catch, atunci CLR va afisa un mesaj cum ca exceptia nu este tratata, unhandled exception message, apoi
va opri executia programului.
In general, instructiunea catch nu are un parametru. Totusi, il putem adauga in cazul in care vom avea nevoie de accesul la
obiectul care reprezinta exceptia. Este folositor pentru furnizarea informatiilor suplimentare despre eroarea produsa.
catch (Exception exception)
{
Console.WriteLine(exception.Message);
Console.WriteLine(exception.GetType());
}
Fluxul executiei programului continua cu instructiunile aflate dupa blocul catch.
Throw
Pentru a lansa manual o exceptie se foloseste throw.
if (numbers == null)
throw new ArgumentNullException("Array is null");
Tipul obiectului trebuie sa fie o clasa derivata din Exception.
Exemplu de folosire a blocului finally
Instructiunile dintr-un bloc finally se executa intotdeauna, chiar daca o exceptie este prinsa sau nu. Acest bloc este folosit
pentru a curata resursele folosite intr-un bloc trysi pentru a asigura executarea unor instructiuni de cod indiferent de
modul in care se iese din blocul precedent de try.
static void ReadFile()
{
noi la clasa de baza, ci doar definesc radacile celor doua ierarhii de clase care reprezinta exceptii. De exemplu, in cazul
impartirii la zero se produce o exceptie de tipul DivideByZeroException.
Programatorul isi poate defini propriile clase care reprezinta exceptii prin derivarea clasei ApplicationException.
Pentru mai multe detalii, se poate consulta documentatia de pe msdn.
Un program trebuie sa trateze exceptiile intr-o maniera logica si eleganta si sa isi continue apoi executia. Daca programul
nu intercepteaza exceptia, el va fi fortat sa se inchida.
Chiar daca nu este considerata optima, o alta modalitate de raportare a erorilor o reprezinta codurile de retur. Ce parere
aveti? Voi ati utilizat-o?
Pentru ca tratarea erorilor constituie un subiect dificil voi continua intr-un viitor articol crearea propriilor clase de
O singura interfata, mai multe metode sintagma pe care se bazeaza conceptul de polimorfism. Se incearca stabilirea
unei interfete generice pentru un intreg grup de activitati asemanatoare.
Un obiect polimorfic este capabil sa ia mai multe forme, sa se afle in diferite stari, sa aiba comportamente diferite.
Polimorfismul parametric
O metoda va prelua orice numar de parametri.
Cand cream o metoda, de regula se stie numarul parametrilor care vor fi transmisi. Sunt cazuri in care nu se intampla
acest lucru si va fi nevoie de un numar arbitrar de parametri. Se va recurge la un tip special de parametru, de
tipul params. Acesta va declara un tablou de parametri, care poate memora zero sau mai multe elemente.
Exemplu :
//metoda va returna numarul minim
public int metoda(params int[] numere)
{
int minim;
//in cazul in care nu e transmis functiei
//nici un parametru, afiseaza un mesaj
if (numere.Length == 0)
{
Console.WriteLine("Nu sunt parametri");
return 0;
}
//initializam variabila
//cu primul element al tabloului
minim = numere[0];
//comparam fiecare element al tabloului
//cu valoarea minima initiala
foreach (int i in numere)
if (i < minim)
//atribuim valoarea minima variabilei minim
minim = i;
//inapoi la programul apelant al functiei
return minim;
}
Polimorfismul ad-hoc
Se mai numeste si supraincarcarea metodelor, una dintre cele mai interesante facilitati oferite de limbaju C#. Cu ajutorul
acesteia, se pot defini in cadrul unei clase mai multe metode, toate avand acelasi nume, dar cu tipul si numarul parametrilor
diferit. La compilare, se va apela functia dupa numarul parametrilor folositi la apel.
Pentru a supraincarca o metoda, pur si simplu trebuie doar declararea unor versiuni diferite ale sale. Nu este suficient insa,
ca diferenta dintre doua metode sa fie facuta doar prin tipul valorii returnate, ci e nevoie si de tipurile sau numarul
parametrilor.
Exemplu:
class SupraincarcareMetoda
{
public void CalculeazaMedia()
{
Console.WriteLine("Nici un parametru");
}
//supraincarcam cu un parametru intreg
public void CalculeazaMedia(int nota)
{
Console.WriteLine("O nota:" + nota);
}
//supraincarcam cu doi parametri intregi
public void CalculeazaMedia(int nota1, int nota2)
{
Console.WriteLine("Doi parametri: " + nota1 + " " + nota2);
}
//supraincarcam cu parametri double
public void CalculeazaMedia(double nota)
{
Console.WriteLine("Un parametru double:" + nota);
}
//eroare, daca incerc sa suprascriu
//doar prin tipul de date returnat
public int CalculeazaMedia(double nota)
{
//
}
}
In metoda principala a programului :
//apelam toate versiunile lui CalculeazaMedia
SupraincarcareMetoda sup = new SupraincarcareMetoda();
sup.CalculeazaMedia();
sup.CalculeazaMedia(10);
sup.CalculeazaMedia(23, 23);
sup.CalculeazaMedia(34.34);
Polimorfismul de mostenire
Intr-o ierarhie de clase, se pune problema apelarii metodelor care au aceeasi lista de parametri, dar care sunt in clase
diferite.
Exemplu:
class Baza
{
public void Afiseaza()
{
Console.WriteLine("Apelul functiei Afiseaza din clasa de baza\n");
}
}
class Derivata : Baza
{
public void Afiseaza()
{
Console.WriteLine("Apelul functiei Afiseaza din clasa derivata");
}
}
La compilare se rezolva problema apelarii metode Afiseaza, pe baza tipului declarat al obiectelor :
Derivata obiect2 = new Derivata();
//instantiem pe un obiect din clasa derivata
Baza obiect1 = obiect2;
//afiseaza functia din clasa de Baza
obiect1.Afiseaza();
obiect2.Afiseaza();
Modificatorii virtual si override
Virtual este folosit in declararea unei metode sau a unei proprietati. Acestea se vor numi membri virtuali. Implementarea
unui membru virtual poate fi schimbata prin suprascrierea membrului intr-o clasa derivata.
Override se foloseste pentru a modifica o metoda sau o proprietate si furnizeaza o noua implementare a unui membru
mostenit dintr-o clasa de baza. Metoda de baza suprascrisa si metoda de suprascriere trebuie sa aiba aceeasi signatura ( tip
si numar de parametri ).
Implicit, metodele nu sunt virtuale. Nu se pot suprascrie metodele care nu sunt virtuale.
Exemplu:
class Baza
{
public virtual void Afiseaza()
{
Console.WriteLine("Apelul functiei Afiseaza din clasa de baza\n");
}
}
class Derivata : Baza
{
public override void Afiseaza()
{
Console.WriteLine("Apelul functiei Afiseaza din clasa derivata");
}
}
Derivata obiect2 = new Derivata();
//instantiem pe un obiect din clasa derivata
Baza obiect1 = obiect2;
//afiseaza functia din clasa de Baza
obiect1.Afiseaza();
obiect2.Afiseaza();
Polimorfismul ajuta la reducerea complexitatii pentru ca permite unei interfete sa fie folosita de fiecare data pentru
specificarea unei clase generice de actiuni. Programatorul nu va efectua manual selectia. Selectia actiunii
specifice (metoda) va fi facuta de compilator.
92.
93.
Poziia controalelor
Locaia controalelor dintr-o fereastr trebuie s reflecte importana relativ i frecvena de
utilizare. Astfel, cnd un utilizator trebuie s introduc nite informaii unele obligatorii i
altele opionale este indicat s organizm controalele astfel nct primele s fie cele care
preiau informaii obligatorii.
Consistena
Ferestrele i controalele trebuie s fie afiate dup un design asemntor (template) pe
parcursul utilizrii aplicaiei. nainte de a implementa interfaa, trebuie decidem cum va arta
aceasta, s definim template-ul.
Estetica
Intefaa trebuie s fie pe ct posibil plcut i atrgtoare.
94.
95.
96.
97.
Controale de actiune (de exemplu button) care, atunci cnd sunt acionate, se poate
executa o prelucrare. De exemplu, cel mai important eveniment pentru Button este Click
(desemnnd aciunea click stnga pe buton).
n exemplul PV1 se adaug pe formular dou butoane i o caset
text. Apsarea primului buton va determina afiarea textului din TextBox
ntr-un MessageBox iar apsarea celui de-al doilea buton va nchide
nchide aplicaia. Dup adugarea celor dou butoane i a casetei text a
fost schimbat textul afiat pe cele dou butoane au fost scrise funciile
de tratare a evenimentului Click pentru cele dou butoane:
private void button1_Click(object sender, System.EventArgs e)
{ MessageBox.Show(textBox1.Text);}
private void button2_Click(object sender, System.EventArgs e)
{ Form1.ActiveForm.Dispose();}
Controale valoare (label, textbox, picturebox) care arat utilizatorului o informaie
(text, imagine).
Label este folosit pentru plasarea de text pe un formular. Textul afiat este coninut n
propietatea Text i este aliniat conform propietii TextAlign.
TextBox - permite utilizatorului s introduc un text. Prevede, prin intermediul
ContextMenu-ului asociat, un set de funcionaliti de baz, ca de exemplu (Cut,
Copy, Paste, Delete, SelectAll).
PictureBox permite afiarea unei imagini.
Exemplul PV2 afieaz un grup alctuit din 3
butoane, etichetate A,B respectiv C avnd iniial
culoarea roie. Apsarea unui buton determin
schimbarea culorii acestuia n galben. La o nou
apsare butonul revine la culoare iniial. Acionarea
butonului Starea butoanelor determin afiarea ntr-o
caset text a etichetelor butoanelor galbene. Caseta
text devine vizibil atunci cnd apsm prima oar
acest buton. Culoarea butonului mare (verde/portocaliu)
se schimb atunci cnd mouse-ul este poziionat pe
buton.
Dup adugarea butoanelor i a casetei text pe
formular, stabilim evenimentele care determin
schimbarea culoriilor i completarea casetei text.
private void button1_Click(object sender, System.EventArgs e)
{if (button1.BackColor== Color.IndianRed) button1.BackColor=Color.Yellow;
else button1.BackColor= Color.IndianRed;} 30 POO i Programare vizual (suport de curs)
private void button4_MouseEnter(object sender, System.EventArgs e)
{button4.BackColor=Color.YellowGreen;button4.Text="Butoane apasate";}
private void button4_MouseLeave(object sender, System.EventArgs e)
{textBox1.Visible=false;button4.Text="Starea butoanelor";
button4.BackColor=Color.Orange;}
private void button4_Click(object sender, System.EventArgs e)
{textBox1.Visible=true;textBox1.Text="";
if( button1.BackColor==Color.Yellow)textBox1.Text=textBox1.Text+'A';
if( button2.BackColor==Color.Yellow)textBox1.Text=textBox1.Text+'B';
if( button3.BackColor==Color.Yellow)textBox1.Text=textBox1.Text+'C';
}
Exerciiu Modificai aplicaia precedent astfel nct s avem un singur eveniment
button_Click, diferenierea fiind fcut de parametrul sender.
Exerciiu ( Password) Adugai pe un formular o caset text n care s introducei un
ir de caractere i apoi verificai dac acesta coincide cu o parol dat. Textul introdus n
caset nu este vizibil (fiecare caracter este nlocuit cu*). Rezultatul va fi afiat ntr-un
MessageBox.
Controale de selecie (CheckBox,RadioButton) au propietatea Checked care indic
dac am selectat controlul. Dup schimbarea strii unui astfel de control, se declaneaz
evenimentul Checked. Dac propietatea ThreeState este setat, atunci se schimb
funcionalitatea acestor controale, n sensul c acestea vor permite setarea unei alte
stri. n acest caz, trebuie verificat propietatea CheckState(Checked,
Unchecked,Indeterminate) pentru a vedea starea controlului.
98.
99.