Sunteți pe pagina 1din 185

UNIVERSITATEA DIN BACU FACULTATEA DE INGINERIE

Culea George

Gbureanu Ctlin

PROGRAMAREA ORIENTAT PE OBIECTE


Note de curs ndrumar de laborator

Editura Alma Mater Bacu 2007

1 CONCEPTE GENERALE
1.1 Introducere

Stilul de programare care l numim n mod obinuit programare orientat pe obiecte POO a aprut relativ recent n istoria limbajelor de programare. Acesta este un stil particular i foarte comod pentru numeroase situaii. El a fost creat pentru a depii limitele programrii structurate bazate n principal pe utilizarea larg a procedurilor, funciilor, a pointerilor sau a tipurilor de date mai mult sau mai puin evoluate. Programarea structurat foarte practic mai ales pentru sisteme de programe mici sau aplicaii reduse negrafice, este depit n ceea ce privete aplicaiile mari cu elemente grafice unde mult mai indicat este programarea orientat pe obiecte. Programarea orientat pe obiecte utilizeaz elementele programrii dar se bazeaz pe orientarea pe obiecte. Orientarea pe obiecte nseamn organizarea de resurse soft ca i o colecie de obiecte, distincte i discrete, care nglobeaz att structuri de date ct i funciile de prelucrare ale acestora. Aceast organizare este o extindere a programrii structurate, n care structurile de date i funciile de prelucrare sunt doar lejer conectate. Toate obiectele au identitate proprie i sunt perfect distinctibile. Un obiect se definete ca fiind un concept, o abstractizare, un element precis i util pentru aplicaia de rezolvat. Obiectele servesc dou scopuri precise: - ofer o mai bun nelegere a problemei de rezolvat; - ofer un "schelet" de pornire pentru implementare. O clas de obiecte grupeaz un numr oarecare de obiecte cu proprieti similare. Aceast similitudine se refer att la descriere (date sau atribute), ct i la comportare (funcii sau metode), dar n acelai timp i la relaiile posibile cu alte obiecte. Diferenele dintre obiectele de aceeai clas se materializeaz n diferene ntre valorile datelor de descriere. Totodat, pentru fiecare obiect este specificat tipul clasei din care provine. Clasa este elementul de programare care ne permite transcrierea ct mai bun a unui concept din viaa concret ntr-un limbaj de programare. Ea permite definirea att a datelor relativ la o entitate ct i a aciunilor asociate (funcii sau metode). Implementare software a unui concept cum ar fi un sistem de calcul se poate printr-o clas. Aceast clas va fi caracterizat de anumite date (atribute) i anumite aciuni (metode, funcii). Aceast clas va conine numai elementele caracteristice, putnd definii pe baza ei i concepte particulare cum ar fi laptop i PDA. Reprezentarea acestor clase este dat n figura 1.1. 3

Atributele reprezint caracteristici unice n cadrul unei clase de obiecte. La nivel de obiect fiecare atribut primete o anumit valoare care se poate modifica pe parcursul duratei de via a obiectului respectiv. Dou sau mai multe obiecte pot avea valori identice sau valori diferite pentru un acelai atribut.

Sistem de calcul date: tip memoriei tip unitate central echipament de intrare sistem de operare aciuni: instalare programe pornire/oprire

PDA date: dimensiuni tuch-screen programe preinstalate aciuni: lansare GPS -

Laptop date: monitor rotativ DVD WR camera web aciuni: inchidere/ deschidere laptop conectare monitor extern

Figura 1.1 Exemplu de reprezentare a coceptelor prin clase Metodele sau operaiile sunt funcii de prelucrare care se aplic obiectelor de o anumit clas. Toate obiectele unei clase admit acelai set de metode, metode care la rndul lor pot s primeasc un numr oarecare de parametri suplimentari. Identificarea unei metode se face att prin nume, ct i prin semntur. Pentru ca unui obiect s i se poat aplica metode - funcii de prelucrare - acel obiect trebuie s fie creat (definit). Definirea unui obiect poart numele de instaniere. Dup ce un obiect i-a ndeplinit misiunea el este eliminat. Durata de via a obiectelor depinde de la obiect la obiect i de la aplicaie la aplicaie. Abstractizarea este o nsuire uman fundamental care ne permite s construim modele i astfel s facem fa complexitii. n orice domeniu de activitate uman, 4

abordarea unui proiect pornete de la construirea unui model cu scopul unei mai bune nelegeri a problemei de rezolvat. Ingineria soft nu este o excepie. Prin abstractizare se izoleaz aspectele eseniale de cele neeseniale, bineneles n funcie de perspectiva de abordare a problemei de rezolvat. n consecin, pentru o aceeai problem, pot exista mai multe abstractizri, deci mai multe modele. Nu putem vorbi de modele corecte i modele incorecte, ci de modele adecvate i modele inadecvate. Prin esen, o abstractizare este o reprezentare incomplet a realitii i tocmai aceasta d valoare modelului corespunztor. La fel ca i n abordarea structurat, n abordarea orientat pe obiecte, procesul dezvoltrii unei resurse soft, pornete de la un model. Aceasta este o abstractizare menit a face posibil etapa urmtoare de implementare. n domeniul ingineriei soft, programarea structurat a fcut un mare pas nainte introducnd necesitatea abordrii unei aplicaii din trei perspective diferite, rezultnd astfel trei modele diferite. n abordare structurat, cele trei modele, pe care le numim i sub-modele sunt: modelul static, modelul dinamic i modelul funcional. n modelarea orientat pe obiecte apar dou modificri eseniale: modelul care capteaz aspectele statice ale aplicaiei devine modelul obiectual, iar accentul cade pe acest model i nu pe cel funcional. n multe aplicaii mai simple modelele dinamic i funcional se construiesc n primul rnd pentru o mai bun nelegere a modelului obiectual. Modelul obiectual pune n eviden aspectele statice ale aplicaiei, dar nu prin identificarea unor sub-ansamble, mai mult sau mai puin arbitrare, ci prin identificarea conceptelor cu care opereaz aplicaia. Acestor concepte li se asociaz obiecte, iar modelul obiectual conine o sintez a acestor obiecte, a relaiilor dintre ele, precum i a proprietilor lor, att descriptive ct i comportamentale. Construirea unui sistem n jurul obiectelor cu care opereaz, surprinde mult mai bine realitatea dect o abordare care pornete de la aspecte funcionale. Modelul dinamic sugereaz succesiunea n timp a crerii obiectelor, pe msura necesitii existenei lor, precum i distrugerea acestora dup ce i-au ndeplinit misiunea. Crearea unui obiect mai poart i numele de instaniere. Pentru obiectele implementate la nivelul unui nucleu, deciziile de instaniere i distrugere se iau la nivelul clientului acelui nucleu. Totodat, modelul dinamic indic ordinea de invocare a aspectelor comportamentale, adic a metodelor, pentru fiecare obiect instaniat. Modelul funcional descrie aspectele comportamentale ale obiectelor, indiferent de ordinea de instaniere a obiectelor i indiferent de ordinea de invocare a acestor aspecte. Fiecrui aspect comportamental i corespunde o funcie, numit i metod. Modelul funcional, descrie funcionarea n mare a acestor metode, rezumndu-se la ilustrarea relaiilor ntre parametrii de intrare i valorile de ieire ale fiecrei metode n parte, fr ns a oferi detalii legate de implementarea algoritmilor corespunztori. Exist la ora actual mai multe metodologii orientate pe obiecte pentru analiza, proiectarea i implementarea de resurse soft. Una dintre metodologii de modelare este metodologia OMT - Object Modeling Technique. Aceasta metod de modelare presupune o etapizare a etapelor de dezvoltare, precum i un sistem grafic de reprezentare a obiectelor i a relaiilor dintre acestea. Metodologia se bazeaz pe construirea unui model tridimensional al aplicaiei, pe baza cruia se adaug gradat detaliile de implementare n ultima faz a procesului de dezvoltare. Elementele caracteristice modelrii OMT sunt prezentate n figura 1.2. 5

Dezvoltarea unei aplicaii n metodologia OMT presupune parcurgerea n mod repetitiv, pn la obinerea unui produs acceptabil, a urmtoarelor etape: 1. Analiza - Aceast etap pornete de la specificaiile problemei de rezolvat. Scopul acestei etape const ntr-o nelegere profund a domeniului aplicaiei, precum i a cerinelor concrete ale aplicaiei. O analiz corect capteaz aspectele eseniale, evitndu-se, prin orice mijloace, pierderea generalitii prin introducerea de aspecte nesemnificative legate de implementare. Rezultatul etapei de analiz este modelul aplicaiei format din cele trei sub-modele.
Domeniul problemei

Model obiectual modelare Model dinamic Model funcional implementare

Figura 1.2 Caracteristice modelrii OMT Un model corect trebuie s poat fi uor neles de specialitii din domeniul aplicaiei, fr cunotine de programare. Excepie face situaia n care domeniul aplicaiei este nsi tiina i ingineria calculatoarelor. 2. Proiectarea sistem - n aceast etap se iau deciziile de nivel nalt privind arhitectura aplicaiei, n ansamblul ei. Acum se decid subansamblele mari ale aplicaiei, precum i resursele platformei gazd ce trebuie disponibilizate i gestionate. n ce privete cerinele aplicaiei, acum se aleg modalitile lor de implementare - hard sau soft -, protocoalele de comunicaie ntre nivelele logice adiacente i se stabilesc legturile ntre obiectele ce interacioneaz de pe nivele diferite. n aplicaii mari, se recomand ca fiecrui nivel s i se construiasc un model propriu. n ce privete resursele mainii, acum se stabilesc strategiile de alocare i gestiune a memoriei dinamice i a altor resurse sistem. 3. Proiectarea obiectelor - Pornind de la modelul obiectual i de la deciziile proiectrii sistem, n aceast etap se adaug o descriere mai amnunit a claselor de obiecte. Astfel, acum se specific numele atributelor i tipurile lor, precum i numele metodelor i semnturile acestora. Toate aceste nume trebuie alese cu grij pentru a se mapa ct mai bine domeniului aplicaiei. 4. Implementarea - n aceasta etap se trece la dezvoltarea claselor de obiecte i a relaiilor dintre acestea. Aceast implementare se materializeaz n module soft, sau dac este cazul, chiar i n module hard. Partea cea mai semnificativ de efort este dirijat spre codificarea algoritmilor corespunztori metodelor. Aceast etap se dorete a fi simpl i oarecum mecanic, deoarece toate deciziile majore au fost deja luate n etapele precedente. Tot n aceast etap se poate lua decizia introducerii unor obiecte nerelevante din punct de vedere al aplicaiei, dar indispensabile etapei de implementare, cum ar fi: liste nlnuite, arbori, tablouri hashing i altele. Sigur, ntregul proces prezentat trebuie privit ca i un ciclu interativ. Totodat, efortul necesar testrii i validrii, pas cu pas, a produsului nu trebuie deloc neglijat, 6

Domeniul soluiei

chiar dac abordarea orientat pe obiecte duce, printre altele, i la minimizarea acestei etape. n fine, fiecare metodologie de proiectare orientat pe obiecte, sugereaz un set de reprezentri grafice, folosite pentru reprezentarea modelelor obiectuale. Acestea trebuie s ofere o imagine clar i intuitiv a claselor i obiectelor, precum i a relaiilor dintre clase, stabilite n faza de modelare.

1.2 Caracteristicile unui limbaj orientat pe obiect


Termenii generali ce descriu cel mai bine caracteristicile eseniale ale unui limbaj orientat pe obiect sunt: - Abstracia definete caracteristicile eseniale unui obiect vzut din exterior. Selectarea obiectelor abstracte i a claselor este un punct important n realizarea unui program. - ncapsularea - este un mecanism care leag mpreun cod i date i le pstreaz pe ambele n siguran fa de intervenii din afar i de utilizri greite. Mai mult , ncapsularea este cea care permite crearea unui obiect . Obiectul este o entitate logic ce ncapsuleaz att date ct i cod care manevreaz aceste date. ntr-un obiect o parte din cod i / sau date pot fi particulare acelui obiect i inaccesibile pentru orice din afara sa. n acest fel, un obiect dispune de un nivel semnificativ de protecie care mpiedic modificarea accidental sau utilizarea incorect a prilor proprii obiectului de ctre seciuni ale programului cu care nu are legtur . - Motenirea permite definirea unor noi clase pornind de la cele existente. Marele avantaj al motenirii este obinerea prin derivare a datelor i metodelor n clasa creat. Caracteristicile motenite de clasa creat pot fi ajustate dup necesiti. Este posibil de asemenea derivarea unei clase din mai multe clase de baz (motenire multipl). Prin motenire se pot obine obiecte specializate pe baza unor obiecte mai generale. Avantajul apare cnd, pentru a crea un obiect, nu mai trebuie s pornim de la zero, ci putem deriva obiectul dintr-o clas care are proprieti comune cu obiectul care dorim s-l obinem. - Polimorfismul - este caracteristica ce permite unei interfee s fie folosit cu o clas general de aciuni. Aciunea specific selectat este determinat de natura precis a situaiei. Un exemplu din practica zilnic pentru polimorfism este un termostat . Nu are important ce combustibil se ntrebuineaz pentru nclzirea casei (gaze , petrol , electricitate etc.) , termostatul lucreaz n acelai fel. n acest caz termostatul (care este interfaa) este acelai indiferent de combustibil (metoda). Acelai principiu se poate aplica i programrii. De exemplu , putem avea un program care definete trei tipuri de memorie stiv. Una este folosit pentru valori ntregi, una pentru valori tip caracter i una pentru valori in virgul mobil . Datorit polimorfismului , putem crea trei perechi de funcii numite pune ( ) i scoate ( ) cte una pentru fiecare tip de 7

date. Conceptul general ( interfa ) este cel de a pune i de a scoate date dintr-o memorie stiv. Funciile definesc calea specific (metoda) care se folosete pentru fiecare tip de date. Cnd punem date n memoria stiv , tipul de date va fi cel care va determina versiunea particular a lui pune ( ) care va fi apelat. Polimorfismul ajut la reducerea complexitii permind aceleiai interfee s fie folosit pentru a specifica o clas general de aciuni. Rolul compilatorului este s aleag aciunea specific (metoda) care se aplica fiecrei situaii. Programatorul nu trebuie s execute personal aceasta aciune. Nu trebuie dect s-i aminteasc i s foloseasc interfaa general. - Modularitatea posibilitatea gruprii claselor n module. Un mediu creat pentru realizarea aplicaiilor Windows este Visual C++, fiind cel mai folosit compilator de C++ la ora actual. El se bazeaz pe biblioteca de clase MFC (Microsoft Foundation Classes) ce permite crearea rapid a unor cadre de aplicaii pe baza conceptului de document-view sau de aplicaie bazat pe un dialog.

2 PROGRAMARE ORIENTAT PE OBIECTE N C++


2
2.1 Clase i obiecte

O clas reprezint un tip de date definit de programator. Dac se folosete o bibliotec de clase existent cum ar fi MFC, atunci programatorul poate defini direct obiecte de tipul acelei clase. Acest tip de date (class) permite declararea unor date protejate sau private, aceste date nefiind vizibile n afara clasei, nici mcar de ctre obiectele de tipul respectiv. n C++, un obiect reprezint o variabil definit ca fiind de tipul clasei din care face parte. Controlul accesului la componentele unei clase poate fi realizat utiliznd specificatorii: - public membrul poate fi accesat de orice funcie din domeniul declaraiei clasei; - private membrul este accesibil numai de funcii din interiorul clasei sau de ctre funcii prietene (friend) ale clasei; - protected similar cu private dar accesul se extinde pentru funciile membre i prietene derivate din clasa respectiv. 8

Specificatorul de acces va fi utilizat n cadrul unei clase indicnd numele acestuia urmat de :. Eticheta public grupeaz membrii clasei pe care programul i poate accesa cu operatorul punct. Pentru a ascunde detalii elementare ale unui obiect, C++ permite separarea definiiei clasei n pri private, protejate i publice. Singura posibilitate de accesare a datelor i metodelor private este prin intermediul metodelor publice. Pentru clasa de baz, obiectele derivate pot accesa membrii protejai, ca i cum ar fi publici. n afara obiectelor derivate, ns , numai rutinele de interfa publice pot accesa membrii protejai. O funcie membr a unei clase are acces la toate datele membre din clasa respectiv, indiferent de specificatorul de acces. Dac nu specificm tipul de acces, membrii vor fi private n mod implicit. Forma general a declaraiei unui tip class este similar cu a tipurilor struct din C: class <nume_clasa> <:lista_clase_baza>{<lista_membri>}<lista_var>; - nume_clasa este numele tipului clas declarat i trebuie s fie unic n domeniul n care este valabil declaraia. - lista_clase_baza este lista claselor din care este derivat clasa declarat (dac este cazul) - lista_membrii reprezint secvena de declaraii ale membrilor clasei. Lista conine declaraii de date membre sau definiii de funcii membre. Datele membre pot fi de orice tip, mai puin tipul de clas declarat. - lista_var este lista numerelor variabilelor de tip nume_clasa. Dei nume_clas i lista_var apar opionale, ca i n cazul tipurilor de structur din C, cel puin una dintre ele trebuie s existe. De regul nume_clasa nu se omite, pentru a pute declara ulterior obiecte de acest tip. La declararea obiectelor este suficient s se specifice numele clasei fr cuvntul cheie class. Exemplu: definire clas student. class Student { public: char Nume[100]; char Prenume[100]; int Varsta; protected: char Facultatea[30]; char Sectia[30]; int anul; int nr_restante; private: long media_ultim_an; double bursa; public: Student(); long aflaMedia(); void schimbaMedia(long MediaNoua); 9

private: int Afla_nr_restante(); }; O clas conine: - o parte protejata/privata care asigura implementarea clasei; - o parte publica care reprezint interfaa clasei respective cu celelalte seciuni din program. Interfaa la o clasa se refer la informaia pe care utilizatorul trebuie s o cunoasc pentru a se putea folosi de facilitile oferite de acea clasa. De aceea trebuie cunoscut: -identificatorii funciilor membru publice ale clasei; -prototipurile funciilor membru; -scopul funciilor membru. Protecia membrilor intr-o clasa este indicata cu ajutorul unor specificatori de acces/ modificatori de protecie. ntr-o clasa, la finalul cuvntului cheie, care precizeaz modul de acces, se afla ntotdeauna ":". Domeniul unui identificator de clasa este local i ncepe din momentul declarrii clasei pana la finalul blocului respectiv. Daca o clasa este declarata n afara oricrei funcii sau clase, domeniul sau este ntregul fiier. Domeniul membrilor unei clase coincide cu domeniu clasei respective. Daca prototipurile funciilor membru se afla n declaraia clasei respective, definiiile lor (cu excepia celor inline) sunt date n exteriorul declaraiei clasei, folosind operatorul de specificare de domeniu "::". Acesta indica faptul ca domeniul funciei respective este acelai cu domeniul clasei din care face parte. Sintaxa definiiei unei funcii membre a unei clase: tip id_clasa :: id_func_membru(...){...}; Pentru a crea un obiect (dac nu l-am specificat n definiia clasei) de tipul unei clase se folosete numele clasei ca i cum ar un nume de tip. nume_clas nume_obiect; O funcie membr a clasei, sau metod poate fi apelat doar printr-un obiect al clasei. Se va realiza acest lucru folosind operatorul de apartenen punct. nume_obiect. n C++, obiectele unei clase se pot manipula folosind funciile membru i operatorii definii pentru acea clasa. O astfel de funcie are, de regula, unul sau mai muli parametri i returneaz o valoare. Mecanismul de transmitere prin valoare consta n primirea de ctre funcie a parametrilor actuali ntr-o stiva (stack) care este o structura de date de tip LIFO. Funcia preia parametrii din stiv i ii folosete n blocul sau fr a avea acces la locaiile lor de memorie. Ea folosete doar copii locale ale acestor parametrii care vor fi eliminate din stiva la revenirea din funcie. Prin urmare, printr-un astfel de mecanism, funcia respectiva nu-si poate modifica parametrii cu care a fost apelata. 10

Exemplu: void suma (int x){x+=100; } void main(){ int u=200; suma(u);//apel functie cout<<"u="<<u;} Se va observa c se afieaz valoarea 200 (valoarea transmisa parametrului formal al funciei) i nu 300 cat ar trebui dup execuia funciei. Problema se poate rezolva folosind parametrii tip pointer. Exemplu: void suma (int *x){ *x+=100;} void main(){ int u=200; suma(&u);//apel functie cout<<"u="<<u;} n acest caz se va afia pentru u valoarea 300. n C++, s-a artat c se utilizeaz conceptul de referin, ce poate fi utilizat la fel ca obiectul referit. Referina reprezint adresa obiectului respectiv deosebindu-se de pointer prin faptul ca ea nu este o variabila reala. Ea este iniializat n momentul definirii i valoarea ei nu se poate modifica ulterior. Transmiterea unei referine la un obiect evita efectuarea de copii inutile i permite o implementare eficienta. Referina se folosete n transmiterea de parametri, daca: a) funcia trebuie s modifice parametrii actuali de la apel; b) funcia nu modifica parametrii actuali, dar trebuie evitata copierea obiectelor n stiva (economie de memorie). n acest ultim caz se va folosi specificatorul const pentru a indica faptul c parametrul transmis prin referin nu va fi modificat de funcia respectiv.

2.2 Clase derivate


Prin mecanismul de motenire sau derivare se pot crea clase noi pe baza unor clase existente. Clasa din care se motenete se numete clas de baz, clasa care motenete se numete clas derivat. Clasa derivat motenete toi membrii clasei de baz, dar nu va putea avea acces niciodat la membrii declarai private n clasa de baz. Practic, datele i metodele se transfer de la clasa de baz la clasa derivat beneficiind deci de proprieti i de un comportament asemntoare cu cele ale clasei de baz. Exist i conceptul de motenire multipl o clas derivat poate s moteneasc de la mai multe clase de baz. Exemplu: class A { private: 11

int i2; }; class B: public A { public: int i3; }; Membrul i2 din clasa A, fiind declarat private, nu este vizibil n clasa derivat B, indiferent de mofificatorul de acces.

2.3 Utilizarea variabilelor globale sau a funciilor globale

n definirea funciilor membre a unor clase.


ntr-o declaraie de clasa se poate modifica accesul ori de cate ori este necesar. Tipurile struct i union reprezint cazuri particulare de clase care se distaneaz de conceptul OOP. O diferen esenial intre class i struct const n faptul ca datele membru n struct, n mod implicit, sunt publice, iar membrii din class, n mod implicit, sunt privai. Operatorul :: mai este numit i operator de scop. Scopul i accesibilitatea unui identificator se pun n evidenta cu ajutorul acestui operator. Sintaxa: ::variabila operator; Exemplu: #include<iostream.h> #include<conio.h> int i=100; // declararea i iniializarea lui i ca variabila globala void f1(){ int i=9; // declararea lui i ca variabila locala /in funcia f1 i++; // incrementarea variabilei locale i cout<<"i="<<i; cout<<"\n";} void f2(){ int i=5; // declararea lui i ca variabila locala n funcia f2 ::i++; // incrementarea lui i global dei este mascat de declararea //unui i local int k=::i; cout<<"k="<<k;} void main() {clrscr(); f1(); f2();} 12

Se observ c n C++, variabilele locale pot fi create n orice poziie din cod. Se pot folosi, cnd este util, nume de funcii standard de biblioteca (read, write, fopen etc.) drept nume de funcii utilizator, urmnd a fi reutilizate intr-o anumita maniera. Exemplu: //definirea funciei utilizator int A::fopen(char*pn="fis.dat", char*pa="rt") { //.. ::fopen(pn, pa);// apel la functie de biblioteca } Din urmatorul exemplu reiese cum se poate utiliza operatorul "::" n cadrul unei functii membru ce opereaza cu variabile membru i cu variabile globale. Exemplu: #include<iostream.h> #include<conio.h> int v=20; // declarare variabila globala cu domeniul de tip fisier care incepe din acest punct class B{ int v; // declararea unei variabile membru /privata a clasei public: void init(int x){v=x;} void f(); //declarare functie membru (prototip) }; void B::f(){ //definitia functiei membru int u=v++; //postincrementarea variabilei membru v cout<<"u="<<v; ::v++; //postincrementarea variabilei globale v int r =::v; cout<<"\n"; cout<<"r="<<r; } void main(){ B c; clrscr(); c.init(10); c.f(); } Un membru al unei clase poate fi definit prin construcia nume_clasa::membru Una din motivatiile prezentei identificatorului clasei n fata operatorului "::" este impusa i de faptul ca trebuie s se distinga functiile cu acelasi identificator care apartin la clase diferite. n plus, se permite operarea directa cu variabila membru, fara precizari suplimentare cu privire la identitatea sa. Mai exact, toate variabilele folosite intr-o functie membru a unei clase i nedeclarate n ea, se presupun, n mod implicit, ca fiind membru ale acelei clase. Daca prin procesul de compilare nu se stabileste aceasta, se va trece la identificarea lor ca variabile globale. 13

Apelul variabilei globale ntr-o funcie se va realiza utiliznd operatorul de rezoluie. Exemplu: class numarator { double v: // variabila locala void setare(int cs,int cz,int cu); ................}; void numarator::setare(int cs,int cz,int cu) {. ::v=v+1; //sau ::v+=1; utilizare variabila global la fel pentru functii: ::puts(mesaj); // utilizare funcie global n acest fel se poate face deosebirea ntre doua funcii sau variabile, ce utilizeaz aceiai notaie(una global i una local).

2.4 Funcii inline


Funciile mici, cu puine instruciuni, apelate frecvent se compileaz ineficient (se rezerv spaiu n stiv pentru parametrii i rezultat, se efectueaz salt la funcie i apoi salt pentru revenire). Mult mai eficient ar fi expandarea apelului funciei prin corpul ei, ca n macroinstruciuni. Apelul unei funcii declarate inline este nlocuit la compilare prin corpul funciei (apel realizat prin expandare). O funcie inline nu trebuie s conin bucle. Funciile membre definite n interiorul clasei sunt n mod implicit inline, dar este posibil ca i funcii definite n afara clasei s fie declarate explicit inline (expandate). class Data{ public: int zi(); ... private: int a, l, z; }; // functie declarata n mod explicit inline inafara clasei inline int Data::zi(){return z;}; // definirea clasei fiierul punct.h class punct{ private: double x0, y0; // date membre public: inline void init(double x=0, double y=0); //nu era necesara inline void setx(double x=0){ x0=x; }; //declararea explicita inline void sety(double y=0){ y0=y; }; //erau considerate inline double getx(){ return x0; }; // este implicit inline 14

double gety(){ return y0; }; void afisare(); }; // fiierul punct.cpp #include <iostream.h> #include <iomanip.h> //desi este definita n afara clasei este inline (apel expandat) inline void punct::init(double x, double y) { x0 = x; y0 = y; }; //nu este inline (apel=salt cu revenire) void punct::afisare(){ long f = ios::fixed; cout << setiosflags(f) << setw(6) << setprecision(2); cout << ( << x0 << , << y0 << ) << endl; }; };

2.5 Functii de tipul prieten friend


O funcie de tip friend este n esen o funcie standard, care nu este membra a clasei ci are numai acces la membrii de tip privat ai acelei clase. Iat o clasa denumit casa class cas { double data; public: double intalniri ; void Anca(intalniri); friend double musafiri(cas*p); }; Declaraia unei funcii prietene se poate face oriunde n cadrul declaraiei clasei i ofer funciei de a avea acces la oricare dintre membri. Funcia rmne extern, deci nu este permis un apel asociat unui obiect, de forma x.fct( ) sau x ->fct( ). Sunt posibile urmtoarele situaii: - funcie independenta este prietena a unei clase; - funcie membr a unei clase este prietena altei clase; - funcie este prietena mai multor clase; - toate funciile unei clase y sunt prietene ale altei clase x; n acest caz se spune ca clasa y este prietena a clasei x.

15

2.6 Constructori i destructori


Iniializarea asigurat de funcia membru init() este lsat la latitudinea utilizatorului. Este de preferat o iniializare mai sigur a obiectului, care s se fac n mod implicit la declararea obiectului. Iniializarea obiectelor se face prin intermediul unor funcii speciale numite constructori. Folosirea funciei initD() pentru iniializarea obiectelor clasei Data este nesigur putem uita s facem iniializarea sau s facem o iniializare repetat. Un obiect poate fi declarat neiniializat sau iniializat. Exemple: Complex z; // obiect neiniializat Complex z1(-1.5, 2.); // obiect iniializat O soluie sigur o reprezint declararea unei funcii avnd scopul explicit de iniializare a obiectelor. O asemenea funcie poart numele de constructor. Constructorul este o funcie public, care iniializeaz datele membre, avnd acelai nume cu numele clasei i care nu ntoarce nici o valoare. class Data{ ... public: Data(int, int, int); // constructorul ... }; Considerm definiia clasei Complex: #include <stdio.h> class Complex{ private: double re, im; public: void scrie(); }; void Complex::scrie(){ printf((%4.1lf , %4.1lf)\n, re, im); }; void main(){ Complex z; //obiect neiniializat z.scrie(); } Programul este corect din punct de vedere sintactic. Lipsa unui constructor definit de utilizator, care s iniializeze obiectele este remediat de compilator. Astfel, pentru clasa C, dac nu se definete n mod explicit un constructor, compilatorul genereaz n mod implicit constructorul: C::C(){}, care creeaz datele membre ale 16

clasei. Acest constructor implicit nu face nici o iniializare a datelor membre, aa c se vor afia nite valori foarte mari, reprezentnd coninutul memoriei neiniializate. Pentru a evita aceasta, se recomand programatorului s i defineasc un constructor implicit (fr parametri), care s iniializeze datele membre (n exemplul nostru iniializarea la 0 pentru partea real i cea imaginar a obiectului numr complex). Constructorul implicit acioneaz asupra obiectelor neiniializate. Clasa Complex, prevzut cu acest constructor este: class Complex{ private: double re, im; public: Complex(){re=0.; im=0.}; void scrie(); }; Se prefer scrierea constructorului, folosind o list de iniializare, conform sintaxei: Complex() : re(0.), im(0.){}; De aceast dat, n urma execuiei se va afia ( 0.0 , 0.0). Dac se declar obiecte iniializate, iniializarea acestora trebuie fcut de ctre un constructor de iniializare, care trebuie definit n mod explicit de ctre utilizator. Pentru clasa Complex, un constructor de iniializare, are forma: class Complex{ private: double re, im; public: Complex(double x, double y) : re(x), im(y){}; void scrie(); }; void main(){ Complex z1(-1., 2.); //obiect initializat Complex z2; //obiect neinitializat ... } Dac se declar un constructor de iniializare, compilatorul nu mai genereaz un constructor implicit, astfel c pentru obiectele neiniializate (n exemplul de mai sus z2)i tablourile de obiecte se va genera eroare. Putem defini deci doi constructori (i n general orici, avnd n mod evident semnturi diferite), unul implicit i cellalt de iniializare: Complex() : re(0.), im(0.){}; //constructor implicit Complex(double x, double y):re(x),im(y){}; //ctor de initializare Clasa de mai jos definete mai muli constructori: class Data{ int a, l, z; public: Data(int, int, int); // a, l, z Data(int, int); // l, z Data(int); // z 17

Data(); // implicit cu data curenta Data(const char*); // dat reprezentat de ir ... }; Se prefer nglobarea constructorului implicit n constructorul de iniializare, folosind parametri cu valori implicite. Constructorul de iniializare poate fi folosit drept constructor implicit, dac toi parametrii sunt prevzui cu valori implicite. Complex(double x=0., double y=0.):re(x),im(y){}; Folosirea argumentelor implicite poate reduce numrul de constructori. n exemplul urmtor, n lipsa argumentelor, constructorul asigur iniializarea datei cu valori preluate din obiectul static azi. class Data{ int a, l, z; public: Data(int aa=0, int ll=0, int zz=0); ... }; Data::Data(int aa, int ll, int zz){ a = aa? aa : azi.a; l = ll? Ll : azi.l; z = zz? zz : azi.z; }; Utilizatorul este obligat s-i defineasc proprii constructori numai n situaiile n care obiectul aloc dinamic spaiu n memorie. Nu pot fi definii mai muli constructori implicii .(fiind suprancrcai, diferiii constructori trebuie s aib semnturi diferite). Un constructor cu un singur argument definete o funcie pentru conversia de tip de la tipul argumentului la tipul clasei. Deci vom putea iniializa un obiect printr-o atribuire de forma: clasa ob=argument; Atribuirea de mai sus poate fi considerat ca o conversie implicit. Pentru a o dezactiva, constructorul cu un argument trebuie s fie precedat de cuvntul cheie explicit. Operaia de eliminare a unui obiect din memorie este realizat de o funcie destructor, avnd acelai nume cu al clasei, fr argumente, care nu ntoarce nici o valoare. Pentru a face distincie fa de constructor, numele destructorului ncepe cu ~. Un destructor pentru un obiect este apelat n mod implicit la ieirea din domeniul de definiie al obiectului sau la sfritul programului, pentru obiectele globale sau statice. Sunt foarte rare situaiile n care programatorul apeleaz explicit un destructor. Dac o clas nu are definit destructor, compilatorul genereaz un destructor implicit. Programatorul nu apeleaz n mod explicit constructorii sau destructorul. Constructorii se apeleaz n mod implicit la declararea obiectelor. Destructorul este apelat implicit la ieirea din blocul n care este declarat obiectul. Obiectele create (cu new[])de ctre un constructor explicit trebuiesc distruse (cu delete []) de ctre un destructor definit n mod explicit. La definirea unei funcii constructor sau destructor nu trebuie definit tipul rezultatului ntors de funcie (nici mcar void). 18

Iniializarea obiectului de ctre constructor se poate face prin iniializarea datelor membre cu valorile parametrilor sau prin copierea datelor membre ale unui obiect transmis ca parametru. n acest din urm caz, avem de a face cu un constructor de copiere. Un obiect poate fi iniializat cu o copie a unui alt obiect al clasei sub forma clasa ob1(ob2); De exemplu: Complex z1(1., -2.), z2(z1); O operaie de tipul Clasa ob = Clasa(initializare) prin intermediul constructorului, creeaz un obiect i i iniializeaz datele membre. Exemplu: Complex z2 = Complex(1., -2.); are acelai efect cu declaraia precedent. Spre deosebire de acesta: Complex z2; Z2 = Complex(1., -2.); creeaz un obiect temporar, pe care l copiaz ntr-un obiect existent. Copierea unui obiect folosind operatorul de atribuire realizeaz o copiere membru cu membru a obiectului surs (din dreapta) n obiectul destinaie (din stnga) Data d=d1; //atribuire Data *pd = new Data(d1); //creare obiect anonim iniializat Copia se face membru cu membru. Obiectul ce urmeaz a fi copiat este transmis prin referin. Compilatorul va genera pentru clasa C, un constructor implicit de copiere: C::C(const C&); care realizeaz copierea datelor membru cu membru (copiere superficial). Exemplu: punct p1;// apeleaz constructorul implicit scris de programator // care asigura iniializarea la (0, 0) punct p2(2,5); //iniializare explicita (constructor de iniializare) punct p3(p2); //iniializare prin copiere (constructor de copiere) Constructorul implicit de copiere nu funcioneaz corect n caz c obiectul aloc dinamic memorie. n acest caz programatorul trebuie s-i defineasc propriul constructor de copiere, care s realizeze o copiere profund, a datelor indicate de pointeri i nu o copiere a pointerilor. Obiectele clasei pot fi copiate prin atribuire. Copierea se face membru cu membru. Exemplu: Complex z1(-1., 2.); Complex z = z1; Data d1=Data(2004,10,5); Iniializarea este mai eficient dect atribuirea. n cazul atribuirii exist o valoare (veche) a obiectului, care trebuie tears i prin atribuire se copiaz valoarea nou a obiectului din dreapta operatorului de atribuire. Vom considera un exemplu n care se aloc dinamic memorie pentru datele membre. Fie clasa persoana, prevzut cu mai muli constructori i un destructor: class persoana{ private: char* nume; char* adresa; char* cnp; public: 19

persoana(char* n=,char* a=,char* c=); persoana(persoana& p); ~persoana(); }; persoana::persoana(char* n, char* a, char* c){ nume=new char[strlen(n)+1]; strcpy(nume, n); adresa=new char[strlen(a)+1]; strcpy(adresa, a); cnp=new char[strlen(c)+1]; strcpy(cnp, c); }; persoana::persoana(persoana& p){ nume=new char[strlen(p.nume)+1]; strcpy(nume, p.nume); adresa=new char[strlen(p.adresa)+1]; strcpy(adresa, p.adresa); cnp=new char[strlen(p.cnp)+1]; strcpy(cnp, p.cnp); }; persoana::~persoana(){ delete [] nume; delete [] adresa; delete [] cnp; }; Dac o clas conine date membre constante sau referine, acestea nu pot fi iniializate n corpul constructorului, ci printr-o list de iniializare plasat dup antetul constructorului i separat de acesta prin Constructorii i destructorii sunt apelai implicit la definirea, respectiv distrugerea obiectelor. Obiectele sunt construite n ordinea declarrii lor i sunt distruse n ordine invers declarrii. Clasele care conin membri const i membri referine trebuie s aibe un constructor definit de programator, ntruct referinele trebuiesc iniializate. n absena unor declarri explicite, compilatorul furnizeaz urmtoarele funcii membre: - un constructor implicit - un constructor de copiere - un operator de atribuire - un destructor implicit - un operator de adresare

2.7 Referine
n C++ se pstreaz lucrul cu pointeri, care permite un acces rapid la date. 20

Noiunea de referin s-a introdus pentru a simplifica transferul parametrilor i al valorilor de return prin adres. Pentru referirea la membri se folosete . Chiar dac referina este practic adresa obiectului. Metoda poate fi folosit pentru class, struct, union.

2.8 Membrii statici ai unei clase


Membrii unei clase care sunt declarai cu acest specificator se numesc statici i au un rol aparte n cadrul clasei. Pentru datele nestatice ale unei clase exist copii distincte n fiecare obiect. Datele statice exist ntr-o singur copie, comun tuturor obiectelor. Crearea, iniializarea i accesul la aceast copie sunt total independente de obiectele clasei. Funciile membre statice efectueaz operaii care nu sunt asociate obiectelor individuale, ci ntregii clasei. Un membru static poate fi referit de funciile ne-membre prin dou metode: Indicnd numele clasei i folosind operatorul de rezoluie de domeniu; Specificnd un obiect al clasei i folosind operatorul de selecie .. class A { static int i; }; int A::i; main() { A::i=10; A od; int n = od.i; }

2.9 Sistemul de I/E din C++


Dei limbajul C++ conine toate rutinele din biblioteca de I/E a limbajului C, el ne pune la dispoziie i un sistem propriu de I/E orientat pe obiecte, care ne ajut s citim/scriem obiecte de diferite tipuri. Principalul avantaj al sistemului de I/E din C++ const n faptul c el poate fi redefinit n cadrul propriilor clase. Ca i n limbajul C, sistemul de I/E din C++ nu face deosebire ntre operatori care folosesc consola i cele care utilizeaz fiiere. Sistemul de I/E din C++ opereaz prin streams. La execuia unui program scris n C++, urmtoarele patru streams (drivere) sunt predefinite: cin intrare standard - tastatur cout ieire standard - ecran 21

cerr eroare standard - ecran clog versiunea tampon a lui cerr - ecran Acestea fluxuri de I/E au prototipul n iostream.h. Utiliznd aceste fluxuri de intrare/ieire datele sunt citite sau scrise prin intermediul operatorilor << i >> : #include <iostream.h> void main() { int n; char sir[20]; cout << "Introducei un numr: " << '\n'; cin >> in; cout << " i un sir :" << '\n'; cin >> sir; cout << " Numrul este :" << n << "\n iar irul este :" << sir << '\n\'; } Programul citete un numr i un sir de pe driverul cin (de obicei tastatura) i afieaz aceste date pe cout (monitor). Putem face urmtoarele observaii: - driverele cout, cin i cerr sunt de fapt 'obiecte' dintr-o anumit clas care proceseaz intrarea i ieirea unui program; - driverul cin citete datele i copie informaiile n variabile folosind operatorul >> (deplasare dreapta). Operatorii ce manipuleaz cin, cout i cerr (adic >> i << ) manipuleaz n acelai timp i variabile de diferite tipuri. Aciunea lor depinde n final de tipul datelor. Driverele cin, cout i cerr nu fac parte din gramatica lui C++, aa cum este ea definit de compilatorul ce prelucreaz fiierul sursa. Definiiile lor apar doar n fiierul header iostream.h. Utilizarea vechilor funcii printf() i scanf(), raportate la cin i cout implic anumite dezavantaje. Comparat cu funciile standard C, printf () i scanf (), folosirea operatorilor << i >> mpreuna cu driverele corespunztoare este mult mai sigur n ceea ce privete tipul datelor (formatul lor este descris de programator n primul caz i este recunoscut de compilator n cel de-al doilea) Funciile printf () i scanf (), precum i alte funcii ce folosesc formatul explicit, implementeaz n fond un mini-limbaj care este interpretat numai la execuie. Din contra, compilatorul C++ cunoate exact ce aciune de intrare/ieire trebuie s efectueze. Clasa care gestioneaz funcionarea de baz a unui stream prin funcii i variabile membre este IOS. Aceasta asigur operaiile cu format, verificarea erorilor i a informaiilor de stare. IOS este folosit drept clas de baz pentru urmtoarele trei clase: ISTREAM, OSTREAM i IOSTREAM. Folosind sistemul de intrare/ieire din C++, se pot formata datele ntr-un mod similar funciei printf(). Fiecare stream din C++ are asociat cu el un numr de indicatori de format (flags), care determin modul de afiare; ei sunt codificai ntr-o variabil de tip integer. Tipul de enumerare urmtor definit n clasa IOS, conine constantele corespunztoare acestor indicatoare. 22

enum { skipws = 0 x 0001 left = 0 x 0002 right = 0 x 0004 internal = 0 x 0008 dec = 0 x 0010 oct = 0 x 0020 hex = 0 x 0040 showbase = 0 x 0080 showpoint = 0 x 100 uppercase = 0x 200 showpos = 0 x 400 scientific = 0 x 800 fixed = 0 x 1000 unitbuf = 0 x 2000 stdio = 0 x 4000 }; Cnd se poziioneaz un flag de format, este activat caracteristica respectiv; cnd el este ters, se utilizeaz formatul implicit. La operaia de citire cnd este fixat flag-ul: - skipws se ignor caracterele de tip whitespace (spaiu, tab, newline), cnd este ters caracterele nu mai sunt ignorate. - left se aliniaz rezultatul la stnga. - right se aliniaz rezultatul la dreapta. - internal se extinde o valoare numeric astfel nct s se completeze cmpul, prin inserarea de spaii ntre caractere de baz. - oct determin afiarea n sistem octal. - hex determin afiarea n sistem hexazecimal. - dec se revine n sistem zecimal. - showbase genereaz afiarea ieirii n baza de numeraie corespunztoare. 1F va fi afiat 0 x 1F - showpoint determin afiarea tuturor zerourilor i al punctului zecimal ale unei valori n format virgul mobil. - showpos determin afiarea semnului, naintea valorilor zecimale pozitive. - scientific genereaz afiarea numerelor n format virgul mobil, folosindu-se notaia tiinific, f. exp. - unitbuf golete tamponul dup fiecare scriere. - fixed valorile n format virgul mobil sunt afiate folosindu-se notaia normal (cu punct fix). - stdio cnd este poziionat indicatorul stdio , fiecare stream este eliberat dup o operaie de ieire, ceea ce determin scrierea n dispozitivul fizic cuplat la stream. - uppercase afiare cu majuscule. Pentru a fixa un flag de format, utilizm funcia setf() care este membr a clasei IOS. Sintaxa este: long setf (long, flags); 23

Aceast funcie restaureaz starea anterioar a indicatorilor, i activeaz flagurile specificate de argumentul flags. De exemplu petru a activa flag-ul showpos, putem folosi instruciunea: STREAM.setf (ios ::showpos); STREAM se refer la streamul afferent (cout sau cin) Setf() este o funcie membr a clasei IOS, i efectueaz stream-ul creat de aceasta. Orice apel al funciei setf() se refer la stream-ul corespunztor. Fiecare stream conine informaiile de stare a propriului format. Prin aplicarea unui operator de tip OR valorilor, putem poziiona mai muli indicatori de stare. De exemplu, apelul de mai jos poziioneaz flag-urile showbase i hex; cout.setf(ios :: showbase | ios :: hex); ntruct indicatorii de format sunt definii n clasa IOS, trebuie s obinem accesul la ei prin utilizarea operatorului de rezoluie :: i a numelui de clas. Funcia unsetf() este complementar funciei setf(). Pentru a afla strile curente ale indicatorilor se folosete funcia flags(), membr a clasei IOS. Aceasta napoiaz starea curent a fiecrui flag de format. Prototipul ei este: long flags(); funcia flags() are o a doua versiune, care ne permite s poziionm toi indicatorii (asociai unui sistem), la valorile specificate de argumentul ei. Prototip: long flags (longt); Copiaz ablonul de bii din variabila t n variabila utilizat. Aplicaie: #include <iostream.h> main() { cout << 123.33 <<salut! <<100<<\n; cout << 10 << << -10 << \n; //schimbm formatul cout.setf(ios :: hex | ios :: scientific); cout << 133.33 << salut! << 100 << \n\n; cout.setf(ios :: showpos); cout <<10 << << -10 << \n; cout.setf (ios :: showpoint); cout << 100.0; return 0; }

24

2.10 Utilizarea funciilor width(), precision() i fill()

Exist trei funcii membre ale clasei IOS, care poziioneaz parametrii de format (limea cmpului, precizia, caracterul de inserat) Cnd este afiat o valoare, ea ocup doar spaiul rezervat numrului de caractere necesar. Totui putem specifica o lime minim a cmpului, folosind funcia width() al crui prototip este urmtorul: int width(int w); w este limea cmpului, iar valoarea napoiat este anterioar a cmpului. Dac o valoare utilizeaz un spaiu mai mic dect cel specificat, cmpul este completat cu caracterul curent de inserat (implicit acesta este spaiu). Dac, totui mrimea valorii depete limea minim a cmpului, cmpul va fi suprascris i valorile nu vor fi trunchiate. La afiarea unei valori n format de virgul mobil, se folosesc (n mod implicit) ase cifre dup punct; totui, putem fixa acest numr dac apelm funcia: precision () al crei prototip este: int precision (int p); Aici precizia este stabilit la valoarea dat de parametrul p i funcia va napoia vechea valoare. Stabilirea unui caracter alternativ utilizat pentru completarea cmpului se poate realiza prin funcia fill(). Prototipul acesteia este: char fill (char ch); ch reprezint noul caracter ce completeaz cmpul. - funcia va returna vechiul caracter. Exemplu: #include <iostream.h> void main() { cout.width(10); //limea cmpului de 10 cout << salut << \n; cout.fill (%); cout.width(10); cout << salut << \n; cout.setf(ios :: left); cout.width(10); cout << salut << \n; cout <<123.234567 << \n; cout.width (10); cout.precision(3); cout << 123.234567 << \n; } 25

2.11 Suprancrcarea funciilor i operatorilor


Suprancrcarea funciilor i operatorilor (overloading) sunt elemente eseniale n programarea C++. Ele ofer o baza importanta pentru polimorfism n timpul compilrii, dnd o extensibilitate i flexibilitate limbajului. Suprancrcarea unei funcii nseamn utilizarea aceluiai identificator de funcie pentru cel puin dou funcii cu condiia ca ele s se deosebeasc prin tipuri si/sau numr de parametri, adic s aib prototipuri diferite. n acest fel compilatorul poate selecta, la un moment dat, funcia care trebuie apelat. In C++, se pot suprancrca aproape toi operatorii, astfel nct ei s efectueze diverse operaii n mai multe clase create. La suprancrcarea unui operator, nu se pierde nimic din semnificaiile sale originale, ci doar se extinde tipul obiectelor crora li se poate aplica. Suprancrcarea operatorilor se refer la o facilitate specifica limbajului C++. Este vorba de a oferi posibilitatea programatorului s atribuie operatorilor i alte sensuri dect cele predefinite. Un operator binar suprancrcat, de exemplu *, poate realiza operaia de nmulire i intre obiecte de tip matrice, numere complexe, numere raionale.

2.12 Funcie operator


Un operator se poate suprancrca prin definirea unei funcii operator. O funcie operator definete operaiile specifice pe care le va efectua operatorul suprancrcat corespunztor clasei n care opereaz. Funciile operator pot fi sau nu funcii membru ale clasei n care opereaz. De obicei, funciile operator, care nu sunt funcii membru ale clasei, sunt funcii friend. Sintaxa unei funcii operator membru a unei clase; tip_ret iden_clasa::operator semn_op(lista_par) { // operaii} Cuvntul "operator" este un cuvnt cheie, iar la crearea unei funcii operator, semn_op reprezint simbolul operatorului suprancrcat. De regula, funciile operator membru returneaz un obiect al clasei asupra creia opereaz i nu sunt funcii statice. Funcia operator membru care suprancarc un operator binar conine un singur parametru. Motivul const n faptul ca operandul din stnga operatorului binar este plasat implicit funciei prin pointerul this care este ataat funciei operator. Operandul din 26

dreapta operatorului binar este transmis funciei operator prin parametrul existent n funcie. Apelul funciei operator este generat de obiectul ce reprezint operandul stng al operatorului binar respectiv. Exemplu: Sa se implementeze clasa complex realiznd operaiile aritmetice adunare, scdere, nmulire i mprire prin suprancrcarea operatorilor respectivi cu funcii operator membru. #include<iostream.h> #include<conio.h> #include<math.h> class complex{ double re,im; public: complex(double a=0.0,double b=0){re=a;im=b;} void cit(){ cout<<"Dati partea reala. ";cin>>re; cout<<"Dati partea imaginara. ";cin>>im; getch();} complex operator+(complex &c1); complex operator-(complex &c2); complex operator*(complex &c3); complex operator/(complex &c4); void afis(){ if(im<0)cout<<re<<im<<"*i"; else cout<<re<<"+"<<im<<"*i";} }; complex complex::operator+(complex &c1){ complex u; u.re=re+c1.re; u.im=im+c1.im; return u;} complex complex::operator-(complex &c2){ complex v; v.re=re-c2.re; v.im=im-c2.im; return v;} complex complex::operator*(complex &c3){ complex t; t.re=re*c3.re-im*c3.im; t.im=re*c3.im+im*c3.re; return t;} complex complex::operator/(complex &c4){ complex z; z.re=(re*c4.re+im*c4.im)/(c4.re*c4.re+c4.im*c4.im); 27

z.im=(im*c4.re-re*c4.im)/(c4.re*c4.re+c4.im*c4.im); return z;} void main(){ complex z1,z2,z3; int n; clrscr(); z1.cit(); z2.cit(); z3=z1+z2; cout<<"\nSuma este: ";z3.afis(); z3=z1-z2; cout<<"\nDiferenta este: ";z3.afis(); z3=z1*z2; cout<<"\nProdusul este: ";z3.afis(); z3=z1/z2; cout<<"\nRaportul este: ";z3.afis(); getch();} Analiznd funcia operator-() se observa ca operandul din dreapta operatorului "" , conform semnificaiei operaiei de scdere, este sczut din operandul stng. Deoarece cel care genereaz apelul funciei operator este obiectul indicat de operandul stng, datele operandului drept trebuie sczute din cele corespunztoare indicate prin pointerul this. Exemplu: Sa se implementeze o clasa "sir" care s permit efectuarea unor operaii cu iruri ca: iniializare, copiere, atribuirea unui sir unui alt sir, afiarea lor i s se suprancarce operatorul "+" pentru concatenarea a doua iruri. #include<iostream.h> #include<conio.h> #include<string.h> class sir{ char *p; int l; public: sir(char*s); sir(int n=45); sir(const sir&); ~sir(); int ret_l(); void afis(); sir operator+(sir &s2); }; sir::sir(char*s){ l=strlen(s); p=new char[l+1]; strcpy(p,s);} sir::sir(int dim){ l=dim; 28

p=new char[l+1]; *p='\0';} sir::sir(const sir&s){ l=s.l; p=new char[l+1]; strcpy(p,s.p);} sir::~sir(){ delete p; } int sir::ret_l(){ return l; } void sir::afis(){ cout<<"\n"<<p; } sir sir::operator+(sir &s){ sir suma(l+s.l); strcpy(suma.p,p); strcat(suma.p,s.p); return suma;} void main(){ clrscr(); sir s1("CONCURSUL DE "); sir s2("PROGRAMARE n C++"); sir s3; s3=s1+s2; s3.afis(); cout<<"\nSirul afisat are lungimea:"<<s1.ret_l(); getch();} O situaie mai deosebita se ntlnete la suprancrcarea operatorului binar de atribuire (asignare) =. Copierea datelor membre ale unui obiect sursa (reprezentat prin operandul drept al operatorului de atribuire) n datele membre corespunztoare ale obiectului destinaie (reprezentat prin operandul stng al operatorului de atribuire), se poate realiza n doua moduri: 1) iniializare prin copiere id_clasa ob_d=ob_s; 2) atribuiri de obiecte id_clasa ob_s, ob_d; ob_d=ob_s; Iniializarea prin copiere este nsoit de alocare de memorie i se face cu ajutorul constructorului de copiere. Acesta este apelat automat la instanierea unui obiect printr-o declaraie de forma 1). Daca un astfel de constructor nu exista n clasa respectiva, copierea se va face la nivel de bit. Aplicaie: Se va utiliza suprancrcarea operatorilor binari + i *, cu funcii operator membru. clasa matrice. #include <iostream.h> #include <stdio.h> #include <conio.h> #include<math.h> class matrice { 29

private: int mat[10][10]; public: matrice(int i,int j); matrice(); matrice(matrice&); void afiseaza(); matrice operator+(matrice&); matrice operator*(matrice&); }; matrice::matrice(int r,int p) { int j; for(int i=0;i<r;i++) for(j=0;j<p;j++) { cout<<" mat["<<i<<"]["<<j<<"]="; cin >>mat[i][j]; } } int r; matrice::matrice(){ int j; for(int i=0;i<r;i++) for(j=0;j<r;j++) mat[i][j]=0; } matrice::matrice(matrice& m) { for(int i=0;i<r;i++) for(int j=0;j<r;j++) mat[i][j]=m.mat[i][j]; } void matrice::afiseaza(){ int i,j; for(i=0;i<r;i++){ cout<<"\n"; for(j=0;j<r;j++) cout<<mat[i][j]<<"\t"; } cout<<"\n"; } matrice matrice::operator+(matrice& k) { int i,j; matrice t; for(i=0;i<r;i++) for(j=0;j<r;j++) t.mat[i][j]=mat[i][j]+k.mat[i][j]; return t; } matrice matrice::operator*(matrice& k){ int u,v,i,rez; matrice t; for(u=0;u<r;u++) for(v=0;v<r;v++) { rez=0; for(i=0;i<r;i++) 30

rez+=mat[u][i]*k.mat[i][v]; t.mat[u][v]=rez; } return t; } void main(){ clrscr(); cout<<"\n r=";cin>>r; matrice m(r,r),n; m.afiseaza(); n=m+m; n.afiseaza(); getch(); n=m*m; n.afiseaza(); getch();}

2.13 Suprancrcarea operatorilor << i >>


Atunci cnd se dorete ca streamurile s opereze cu alte tipuri dect cele implicite cu structur simpl. Sau se dorete s se realizeze o citire sau o scriere cu anumite formatri sau n anumite configuraii se face apel la suprancrcarea operatorilor. Pentru streamul cout avem urmtoare secven general de suprancarcare a operatorului de inserie: ostream &operator <<(ostream &stream_atasat,tip_clasa structura_mea) { // facem operatiile de formatare si afisare a structurii stream_atasat<<structura_mea.camp1<< <<; stream_atasat.setf(); . //si acum returnam in mod obligatoriu streamul modificat return stream_atasat; } n program vom folosi suprancrcarea astfel: tip_ clasa a,b,c; cout<<a<<b<<c; Cum funcioneaz structura? Streamul cout de tip ostream (stream de iesire Output) este transmis ca parametru funciei de suprancrcare a operatorului la fel i coninutul variabilei a (apoi ntr-o nou apelare b, apoi c). Se lucreaz asupra streamului transmis modificndu-l, deoarece nu-i transmitem valoare ci nsui adresa (operatorul &), 31

La sfrit streamul modificat este returnat de funcie sistemului ce gestioneaz streamurile. Afiarea se face n momentul accesrii streamului returnarea la sfrit a acestuia de ctre funcie asigurnd retransmiterea adresei, o redundan specific lucrului cu pointeri i funcii. Pentru suprancrcarea operatorului de extracie care opereaz cu streamul cin se va folosi structura: istream &operator>>(istream &stream_atasat,tip_clasa &struct_mea) { //se va lucra asupra streamului de intrare //se vor face formatarile streamului si va citi efectiv prin stream stream_atasat.setf() ; stream_atasat >>ws ; cout>>Introduceti campul 1:; stream_atasat >>struct_mea.camp1 ; stream_atasat >>struct_mea.camp2; .. //se va returna obligatoriu streamul atasat return stream_atasat ; } La folosirea operatorului in program se va proceda astfel: tip_clasa a,b,c; cin>>a>>b>>c; Se observa c streamul cin este de tipul istream (stream de intrare Input stream). n plus se transmite adresa structurii prelucrate de stream pentru c structura este modificat nu doar afiat ca la suprancrcarea operatorului de inserie. n rest abordarea este la fel ca la inserie. Am numit operator de inserie pe cel asociat cu streamul cout deoarece insereaz, adaug informaie n streamul cout respectiv la ieirea de tip display, i extracie deoarece extrage din streamul cin date i le plaseaz n cmpurile structurii proprii specificate. Exemplu: #include <iostream.h> #include <iomanip.h> //Avem structura struct persoana{ char nume[25] ; char prenume[25] ; int varsta ; double salariu; char nr_telefon[15] ; } 32

//Vom defini un operator de insertie ostream &operator<<(ostream &display,persoana p) { display<<Numele <<p.nume<< <<p.prenume<<endl; display<<Are <<p.varsta<< ani.<<endl; display<<Are un salariu de <<p.salariu<<RON <<endl; display<<O puteti apela la nr.<<p.nr_telefon<<endl; return display; } //Vom defini un operator de extractie istream &operator<<(istream &tastatura,persoana &p) { cout<<Numele:; tastatura>>p.nume; cout<<Prenumele:; tastatura>>p.prenume; cout>>Varsta :: tastatura>>p.varsta; cout>>Salariul actual [RON]:; tastatura>>p.salariu; cout>>Nr. de telefon la care poate fi gasita:; tastatura>>p.nr_telefon; return tastatura; } void main() { persoana a; cin>>a; cout<<Datele introduse despre persoana sunt:<<endl<<a; }

2.14 Definirea de manipulatori personalizai


Atunci cnd dorim s realizm rapid sau s grupm sub o singur comand anumite opiuni de formatare pe care le folosim repetat sau pur i simplu dorim s dm un nume sugestiv acestor opiuni vom face apel la definirea manipulatorilor. n anumite puncte structura de redefinire va fi asemntoare structurii de suprancrcare, dar sunt i element specifice. Pentru un manipulator de ieire asociat funciei cout vom folosi structura: ostream & nume_manipulator_out(ostream &stream_atasat) { 33

//operatii de formatare stream_atasat.setf(..); //operatii de afisare stream_atasat<<<<; // in final obligatoriu vom returna streamul atasat return stream_atasat; } In program l vom folosi astfel: cout<<nume_manipulator_out<<...<<...; Pentru un manilator de intrare asociat functiei cin vom folosi urmtoarea structur de declarare: istream & nume_manipulator_in(istream &stream_atasat) { //operatii de formatare //operatii de citire // in final in mod obligatoriu vom returna streamul atasat return stream_atasat; } Vom apela manipulatorul scriind : cin>>nume_manipulator_in>>v1>>>>vk ; Trebuie avut grij s nu folosim un manipulator de iesire n locul unuia de intrare i invers pentru c manipulatorii lucreaz cu tipuri de streamuri diferite. Putem crea manipulatori parametrizai prin simpla adugare n lista de parametri a funciei de noi parametri, de exemplu: ostream &nume_manipulator(ostream &stream_atasat,tip1 p1,tip2 p2,tipn pn) { . } la apelare vom proceda astfel: tip1 a1; tip2 a2; .... tipn an; cout<<nume_manipulator(a1,a2,...an); Pentru manipulatorii de intrare se va proceda la fel. 34

2.15 Lucrul cu fiierele n C++


Dup cum exist o formatare pe baz de streamuri a intrrilor i ieirilor exist i o modalitate de lucru cu fiierele bazat pe streamuri. Astfel fiecrui fiier i se va asocia un stream n care fi se va putea numai scrie i citi, fie ambele. De asemenea exist o abordare secvenial n lucrul cu fiierele( adic pentru a citi secvena dorit trebuie s parcurgem prin citire tot ce este naintea ei) i o abordare de acces aleatoriu (n care citim sau scriem n orice moment exact secvena care ne intereseaz dac n schimb i tim poziia precis n fiier). Mai mult putem accesa fiierele n format text ca o colecie de iruri de caractere sau n format binar ca o grupare de octei. ntotdeauna n lucrul cu fiierele vom avea obligatoriu dou elemente o funcie de deschidere a fiierului (open()) i funcie de nchidere fr parametri (close()). Lucrul secvenial cu fiierele l vom utiliza cnd lucrm cu fiierele text i nu avem nevoie de optimizri fie pentru c fiierul este prea mic, fie pentru c optimizarea nu i-ar avea rost. Avem trei tipuri de streamuri de tip fiier: - ifstream pentru scriere n fiier; - ofstream - pentru citire din fiier; - fstream pentru scriere i citire din fiier; Deschidem streamul asociat fiierului cu funcia open() ce are urmtorul prototip: void open(const char *numefisier,int mod,int acces); n general vom avea nevoie doar de numele fiierului putnd scrie doar: ofstream iesire; iesire.open(test.txt ); Datele ce vor fi scrise n fiier sunt scrise ca i cum s-ar lucra cu cout numai c datele nu vor fi afiate pe ecran ci scrise n fiier cu formatrile specifice streamului ieire.De exemplu: iesire<< Salariu <<salariu_net<< RON; Dupa ce am terminat lucrul cu fiierul l vom nchide cu: iesire.close(); 35

La fel se va lucra i cu ifstream, dup cum se lucreaz cu cin, pentru a se citi nite date din fiier.

2.16 Prelucrare binar a fiierelor


Avem funciile membre asociate streamurilor fiier : - get(char &ch) asociat ifstreamurilor; - put(char ch) asociat ofstreamurilor. Pentru a citi un caracter din fiier vom avea secvena: ifstream intrare; intrare.open(in.txt,ios::in|ios::binary); char c; intrare.get(c); intrare.close(); Pentru a scrie un caracter n fiier vom avea secvena: ofstream iesire; iesire.open(aut.txt,ios::out|ios::binary); iesire.put(a); iesire.close(); Pentru a scrie dintr-o zon tampon n stream sau invers se folosesc funciile write()i read() cu urmtorul prototip: istream &read(unsigned char *buf,int ncitit); ostream &write(const unsigned char *buf,int nscrisi); read() va citi din stream ncitit octei i-i va pune n zona de memorie buf. write() va citi din buf nscris octei i-i va pune n stream. La deschidere se va seta indicatorul de access ios :: binary. Dac se dorete de exemplu scriere unei structuri oarecare : Struct persoana p ; iesire.write((unsigned char*) &p,sizeof(struct persoana)); La fel se va proceda i la citire. Pentru a afla cte au fost citite cu read() se folosete funcia membru gcount(), un exemplu: intrare.read() 36

cout<<intrare.gcount();// afiseaza numarul de caractere extrase din stream la // ultima citire Pentru a citi o linie dintr-un fiier text se folosete funcia getline() cu prototipul: istream &getline(char *buf,int nmaxcitit,char delimatator); Funcia membru citete caractere din stream pn cnd ori se ntlnete delimitatorul (care este implicit linie nou) ori s-au citit nmaxcitit caractere. Oricare din condiii ntlnit prima determin oprire citirii. Pentru a determina dac s-a atins sfritul de fiier de folosete funcia membru eof() care este diferit de zero dac da.(EOF = End Of File). Mai ntotdeauna se folosete valoarea negat a funciei ntr-o secven while cnd se parcurge cap coad un fiier. Pentru a fi siguri c informaia a fost scris din stream n fiier, pentru descrcarea zonei de memorie a streamului n fiier se folosete funcia membru flush(). Aceasta poate fi folosit ca o msur de siguran.

2.17 Lucrul aleatoriu cu fiierele


Se poate avea acces aleatoriu n fiier prin folosirea funciilor membre de poziionare seekg() i seekp() care au urmtoarele prototipuri: istream &seekg(streamoff offset,seek_dir origine); ostream &seekp(streamoff offset,seek_dir origine); Prima poziioneaz n streamul de intrare, cea de-a doua n streamul de ieire. Precizia de poziionare este de un octet, poziia precizndu-se printr-o valoare ntreag offset relativ la un punct de referin stabilit prin origine. Origine poate avea una dintre cele trei valori ios::beg (Poziia este fa de nceputul fiierului), ios::cur(Poziia este fa de poziia curent a pointerului de fiier), ios::end(Poziia este relativ fa de sfritul de fiier). De exemplu pentru fisierul deschis pentru scriere cu streamul iesire de tip ofstream pentru a ne poziiona la 10 octei fa de nceput vom scrie: iesire.seekp(10,ios::beg); Mai avem funciile membre care ne dau poziia curent a pointerului de fiier tellg() i tellp() folosite mpreun cu seekg() i seekp().

37

Este indicat ca la accesul aleatoriu fiierele s fie deschise cu indicatorul de acces ios::binary n plus la scrieri i citiri n cadrul aceluiai fiier s se foloseasc fstreamul. Toate referirile la istream sunt automat compatibile cu ifstream prin mecanismul de motenire, la fel i pentru ostream cu ofstream. Ca specificatori suplimentari utili n lucrul cu fiierele ar fi: - ios::nocreate dac nu exist fiierul va eua deschiderea pentru citire; - ios::noreplace dac fiierul exist acesta nu va fi suprascris, evitndu-se deschiderea; - ios::app se folosete pentru deschiderea spre adugare la sfritul fiierului (append).

2.18 Cuvntul cheie this


La apelarea unei funcii membre, aceasta este informat asupra identitii obiectului asupra cruia va aciona prin transferul unui parametru implicit care este adresa obiectului. De exemplu, n cazul apelului: ob.verificare(i); funcia verificare() primete i adresa obiectului ob, n afar de valoarea i. De asemenea exist cazuri n care adresa obiectului este necesar s fie utilizat n definiia funciei. Acest lucru este realizat n C++ de cuvntul cheie this, asociat unui pointer ctre obiectul pentru care s-a apelat funcia. Cuvntul this are sens i poate apare numai n definiia unor funcii membre. Exemplul urmtor adaug clasei student o funcie adresa(), care afieaz adresa obiectului: Exemplul 1: student::adresa() { cout<<Adresa obiectului pentru care s-a apelat funtcia este; cout<<this; } ............ student stEI; // Se definete un obiect stEI aparinnd clasei EI. stEI.adresa(); // Afieaz adresa obiectului stEI. Exemplul 2 Vom crea dou obiecte de tip numrtor n1 i n2. Utiliznd pointerii *n1 i *n2 putem reprezenta grafic modul n care pointeaz aceste obiecte.

38

n1>

cifra _sute cifra_zeci cifra_uniti setare() avans() afisare()

n2->

cifra _sute cifra_zeci cifra_uniti setare() avans() afisare()

Pentru adresarea unei anumite funcii membr a clasei s-a utilizat operatorul . n1. setare(); sau n2.avans(); Funcia setare din clasa numarator poate fi definit astfel: void numarator ::setare(int cs, int cz, int cu) { this->cifra_sute=cs; this->cifra_zeci=cz; this->cifra_unitati=cu; } Operatorul this va puncta pe nceputul structurii clasei ca n figura urmtoare: this -> cifra _sute cifra_zeci cifra_uniti setare() avans() afisare()

Utiliznd acest operator putem s ne referim la orice element al obiectului curent dar nu ns i n interiorul unei funcii. Notaia *this va reprezenta referirea la ntregul obiect.

2.19 Prevenirea redeclarrii claselor


Programele realizate pn acum conineau definiiile claselor n acelai fiier cu funcia main(). O tehnic obinuit n C++ este de a declara i defini clasa ntr-un fiier antet inclus cu o comand de genul urmtor: #include <nume_fiier_antet> 39

Apariia n mai multe locuri a instruciunii #include referitoare la acelai fiier antet, nu ar fi sancionat ca eroare, dar ar prelungii durata compilrii. Pentru evitarea unei astfel de situaii este recomandabil utilizarea urmtoarei secvene de instruciuni de preprocesare: #ifndef nume #define nume //declaraia i definiia clasei #endif. Exemplu: fierul antet counter.h #ifndef counter_h #define counter_h # include <iostream.h> class numarator //definitia clasei numarator { ......... ...............} #endif counter_h Aceast tehnic st la baza modularizrii programelor.

2.20 Tehnici de creare i iniializare a obiectelor


n general se creeaz mai multe obiecte, ceea ce impune utilizarea optima a spaiului de memorie dinamic. Acest lucru poate fi realizat prin eliminarea acelor obiecte a cror existen nu mai este oportun. Crearea dinamic a obiectelor poate fi realizat cu ajutorul funciilor pentru alocare (malloc(), calloc(), realloc()) i una pentru eliberare free() a spaiului de memorie avnd prototipul n alloc.h S considerm clasa urmtoare: class agent { char nume [20]; int volum _vanz; int nr_ore_lucrate; int stoc; long salar_sapt; } Cu ajutorul funciei malloc() obinem adresa n memoria dinamic unde va fi alocat o astfel de structur de date la momentul definirii unei variabile cu aspectul agent. ntruct malloc() ntoarce o adres, vom declara variabila p astfel: char *p. Putem defini : agent Agent; i vom obine spaiile n memoria dinamic prin: p=malloc(sizeof (Agent)); Acest lucru este acceptat n C i n C++. n C++ exist operatorul new , care ne permite s alocm spaiu pentru obiect la momentul execuiei. agent *p; 40

p = new agent; Exist o diferen net ntre operatorul new i funcia de alocare malloc(). Operatorul new determin n mod automat spaiul necesar prin analizarea numelui de tip ce i urmeaz. Adresa ntoars n p ne permite s avem acces la membrii structurii. Cu funcia malloc trebuie s recurgem n mod explicit la operatorul sizeof, avnd ca argument Agent. n limbajul C putem scrie de exemplu: int *p; p= malloc(100*sizeof(it)); adic aloc un spaiu de 100 de cuvinte de tip ntreg. Acest lucru n C++ se poate scrie astfel: int *p; p = new int[100]; Dup operatorul new urmeaz un nume de tip, n cazul de fa int, iar ntre paranteze drepte, dimensiunea adic numrul elementelor de acel tip, care vor fi alocate din zona de memorie. n C, eliberarea spaiului alocat dinamic se efectueaz prin intermediul funciei free(), iar n C++ putem utiliza operatorul delete. delete p; respective free(p); (delete se utilizeaz dac am folosit new) Exemplu: double *p=new double[12]; delete [4]p;

2.21 Elemente despre preprocesare


Preprocesarea este faza care precede compilarea propriu-zis a unui fiier surs. Pn acum s-au studiat directivele: # include i #define. Directiva include poate fi utilizat n dou forme: # include <nume_fiier.h> # include nume_fiier.h n primul caz compilatorul va cuta n lista definit de utilizator ..../include. A doua form instruiete compilatorul s caute fiierul antet conform regulilor proprii ale sistemului de operare, mai nti cile <..........> i apoi cele ........

41

2.22 Directive de compilare condiionat


Una dintre directivele de compilare condiionat este #ifndef simbol // urmat de #define simbol Acest cuplu de directive va fi folosit n numeroase exemple. Semnificaia lui este urmtoarea: dac pn n acel loc simbol nu a fost definit, va fi definit acum (cu #define). Dac era deja definit, atunci se va ignora instruciunea #define. Deci se evit redefinirea. Cuplul urmtor: #ifdef simbol # define simbol #endif Are efect exact contrar cazului de mai sus. Funcia #define n C++ este utilizat i pentru definirea unor macrodefiniii cu parametrii. Exemplu: # define PI 3.14 # define unghi(v) 180*arccos(v)/PI ua = (b*b + c*c -a*a)(2*b*c); a=unghi(ua); Directiva #undef anuleaz o definiie anterioar a unui identificator cu # define. Sintaxa este: # undef nume_macrodef Dup aceast directiv, nume_macrodef este detaat de semnificaia asociat anterior i este posibil redefinirea sa cu #define. #error Aceast directiv determin complilatorul s opreasc compilarea atunci cnd o ntlnete. Directiva este utilizat pentru depanare. Directivele de compilare condiionat permit compilarea unor poriuni selectate din codul surs. Sunt folosite de exemplu, cnd se dorete obinerea mai multor variante ale aceluiai program. Sintaxa construciei condiionale este: # if(exp1) sectiunea_1 #else sectiunea_2 42

# endif sau #if(exp1) sectiune_1 #elif(exp2) sectiune_2 . . . #elif(expn) sectiune_n #else(exp) sectiune_n+1 #endif

2.23 Prevenirea redeclarrii claselor


Programele realizate pn acum conineau definiiile claselor n acelai fiier cu funcia main(). O tehnic obinuit n C++ este de a declara i defini clasa ntr-un fiier antet inclus cu o comand de genul urmtor: #include <nume_fiier_antet> Apariia n mai multe locuri a instruciunii #include referitoare la acelai fiier antet, nu ar fi sancionat ca eroare, dar ar prelungii durata compilrii. Pentru evitarea unei astfel de situaii este recomandabil utilizarea urmtoarei secvene de instruciuni de preprocesare: #ifndef nume #define nume //declaraia i definiia clasei #endif. Exemplu: fierul antet counter.h #ifndef counter_h #define counter_h # include <iostream.h> class numarator //definitia clasei numarator { ......... ...............} #endif counter_h Aceast tehnic st la baza modularizrii programelor. 43

3 PROGRAMAREA N VISUAL C++


3
Visual C++ a devenit mult, mult mai mult dect un simplu compilator. Sunt incluse clasele fundamentale Microsoft (M.F.C.), care simplific i accelereaz dezvoltarea aplicaiilor Windows. Sunt incluse editoare sofisticate de resurse n scopul proiectrii casetelor de dialog complexe, a meniurilor, a barelor de instrumente, a imaginilor i a altor multe elemente ce compun aplicaiile Windows actuale. Este oferit un excelent mediu de dezvoltare integrat, numit Developer Studio, care prezint forme grafice ale structurii aplicaiei pe msur ce o dezvoltm. Un instrument pentru depanare integrat perfect ne permite s inspectm n detaliu din cadrul unui program aflat n execuie. Acestea sunt dor cteva din numrul mare de faciliti oferite de Visual C++ 6.0, care ne ajut s dezvoltm aplicaii rapide i complete folosind cele mai recente tehnologii Windows.

3.1 Crearea unui proiect


Visual C++ 6 este un instrument potrivit pentru dezvoltarea de programe cu interfa grafic. Visual Studio a purtat numele de Developer Studio i este posibil s se ntlneasc i acronimul IDE (Integrated Deyelopment Environment - mediu integrat de dezvoltare), folosit uneori ca i referire la Visual Studio. Fereastra Microsoft Visual C++ este afiat la lansarea mediului Visual C++. Microsoft Visual C++ este numele dat interfeei cu utilizatorul a lui Visual C++, interfa afiat n figura 3.1. Aceast interfa reprezint suprafaa de lucru.

3.2 Fereastra interfeei cu utilizatorul


Pentru a ncepe o nou aplicaie trebuie s se creeze mai nti un proiect. Un proiect este folosit pentru administrarea tuturor elementelor care compun un program 44

Visual C++ i care au ca rezultat o aplicaie Windows. Pentru a crea un nou proiect se selecteaz comanda New a meniului File i deschide caseta de dialog New va fi afiat ca n figura 3.2.

Figura 3.1 interfea cu utilizatorul nVisual C++

Figura 3.2 Caseta de dialog New Pentru crearea unui proiect mai nti trebuie s se specifice tipul acestuia. Dac pagina Projects din caseta de dialog New, nu este deja selectata, se face clic pe aceasta. Aici este afiat o list cu toate tipurile de proiecte care se pot crea. Pentru exemplul se selecteaz MFC AppWizard (exe) din lista cu tipurile de proiect. Selectarea acestei opiuni nseamn c proiectul va avea ca rezultat un program executabil Windows standard. 45

Orice proiect are nevoie de un nume. Acest nume se specific n caseta Project_Name din caseta de dialog New. Pentru exemplul nostru, se va tasta ExempluPO n caseta Project Name din cadrul casetei de dialog New. Caseta Location este folosit pentru precizarea directorului n care vor fi plasate fiierele proiectului. n cazul exemplului de fa nu este nevoie s se modifice aceast locaie. Calea afiat iniial n caseta Location depinde de opiunile exprimate la instalarea lui Visual C++. Pentru a modifica aceast locaie, fie se editeaz calea explicit, fie se efectueaz un clic pe butonul aflat n partea dreapt a casetei Location. Locaia implicit se bazeaz numele proiectului - n exemplul nostru, C:\Program Files\Microsoft Visual Studio\My Projects\ ExempluPO. Dup stabilirea opiunilor din cadrul casetei de dialog New, se efectueaz un clic pe OK pentru a iniia generarea proiectului. Acest proces va fi controlat de AppWizard. Scopul acestuia este s permit realizarea unui schelet de program care poate fi dezvoltat ulterior. Acest lucru este realizat permind s se selecteze tipul de program dup care este folosit biblioteca MFC, pentru generarea fiierelor care vor forma mpreun un proiect Visual Studio. Caseta de dialog AppWizard (ilustrat n figura 3.3) ofer trei opiuni pentru tipul de interfa a aplicaiei. n cazul proiectului Exemplu PO se va utiliza o interfa de tip dialog. Se selecteaz butonul de opiune Dialog Based. Se poate, de asemenea, s selectai limba care va fi folosit pentru resurse. Nu este necesar s se modifice coninutul casetei combinate Language n cazul programului ExempluPO.

Figura 3.3 Caseta de dialog MFC AppWizard Pas 1 Acum s-a precizat toate informaiile necesare pentru ca AppWizard s poat crea proiectul. Se efectueaz un clic pe butonul Finish. Se va afia caseta de dialog New Project Information, ilustrat n figura 3.4. 46

AppWizard va prezenta aceast caset de dialog pentru a confirma detaliile proiectului pe care este gata s-1 creeze. Se poate vedea aici numele claselor C++ din proiect i numele fiierelor care vor fi create. n lista Features se poate vedea, de asemenea, funcionalitatea figurat de AppWizard. Pentru a continua se efectueaz un clic pe OK n cadrul casetei de dialog New Project Information.

Figura 3.4 Caseta de dialog New Project Information AppWizard i-a ndeplinit sarcina i n Visual Studio este deschis acum proiectul nou creat - ExempluPO. n acest moment, dei nu s-a scris nici o linie de cod surs C++, se are la dispoziie o aplicaie Windows complet i perfect funcional. Seciunea afiat de ctre Visual Studio n partea stng se numete seciunea spaiului de lucru. Dup ce proiectul a fost creat, seciunea spaiului de lucru ofer trei pagini: ClassView, ResourceView i FileView. Aceste pagini permit accesarea oricrei componente a proiectului. Se poate modifica dimensiunea seciunii spaiului de lucru i a altor seciuni care apar n Visual Studio prin efectuarea unui clic pe marginea seciunii i deplasarea mouse-ului n timp ce se ine butonul apsat. AppWizard este utilizat exclusiv pentru crearea noilor proiecte. Nu se poate reveni la casetele de dialog cu opiuni AppWizard n cadrul unui proiect existent. Dac se descoper c s-a fcut o alegere greit i se dorete reluarea etapelor AppWizard, trebuie s se nlture mai nti proiectul existent. Pentru a nltura un proiect, se terge directorul acestuia. Spre exemplu, pentru a relua crearea proiectului ExempluOP, se terge directorul C:\Program Files\Microsoft Visual Studio\MyProjects\ExempluPO. 47

Figura 3.5 Fereastra ExempluPO Procesul de asamblare are ca rezultat fiierul executabil Windows corespunztor proiectului. n cazul proiectului ExempluPO, acest fiier va fi numit ExempluPO.exe. Odat generat acest fiier, se poate rula din Visual Studio. Se poate crea fie o versiune pentru depanare, fie o versiune final a unui fiier executabil. n mod implicit este asamblat o versiune pentru depanare; se va folosi aceast opiune implicit n toate exemplele dac nu se propune explicit o alt variant. Pentru programul ExempluPO nu este necesar modificarea configuraiei. n mod implicit, Visual Studio va genera o aplicaie care conine informaii pentru depanare. Aceste informaii permit s se inspecteze codul executat i s se verifice valorile variabilelor. nserarea informaiilor pentru depanare duce, ns, la o cretere a dimensiunii fiierului executabil i la o scdere a performanelor. Configuraia pentru versiunea final asambleaz executabilul fr informaii pentru depanare, fiind folosit de regul atunci cnd aplicaia este livrat ctre un client. Executabilele Visual C++ sunt fiiere Windows EXE standard Fiierul ExempluPO.exe este similar cu orice alt fiier executabil Windows. Prin urmare, el poate fi executat din Explorer, sau putei s creai o scurttur la acesta i s o plasai pe suprafaa de lucru.

3.3 Efectuarea compilrii i a editrii de legturi


Procesul de asamblare efectueaz compilarea fiierelor C++ individuale dintr-un proiect, dup care rezultatele sunt legate mpreun pentru a forma fiierul executabil. 48

Pentru a asambla proiectul ExempluPO, se efectueaz clic pe butonul Build sau se selecteaz Build ExempluPO.exe din meniul Build sau se apas tasta F7. ExempluPO.exe se afl n subdirectorul /Debug din directorul /ExempluPO al proiectului. Acest subdirector conine, de asemenea, fiierele obiect ale programelor din cadrul proiectului. Subdirectorul /Debug a fost creat din cauz c s-a ales o configuraie pentru depanare, n timp ce o configuraie pentru versiunea final ar fi plasat fiierele ntr-un subdirector numit /Release. Pagina Build a seciunii Output nfieaz informaii privind procesul de asamblare. n cazul n care codul surs conine erori, acestea sunt afiate n cadrul paginii Build, ilustrat n figura 3.6.Deoarece AppWizard a generat ntreg codul, nu ar trebui s apar erori.

Figura 3.6 Asamblarea proiectului ExempluPO Pentru a rula aplicaia, se efectueaz clic pe butonul Execute sau selecteaz Execute ExempluPO.exe din meniul Build sau se folosete combinaia de taste Ctrl+F5. Fereastra principal a aplicaiei va aprea pe ecran ca n figura 3.7. Fereastra aplicaiei conine dou butoane, OK i Cancel, i afieaz un text. Exist, totodat, o bar de titlu care afieaz o pictogram asociat, numele aplicaiei i un buton de nchidere. Bara de titlu conine i un meniu de sistem i poate fi utilizat pentru a deplasa fereastra pe ecran prin efectuarea unui clic asupra ei i meninerea butonului mouse-ului apsat. Putem afia informaiile despre aplicaie dac se efectueaz clic pe imaginea MFC din colul stnga sus al ferestrei ExempluPO i se selecteaz About ExempluPO din meniul de sistem care apare (figura 3.8). 49

Figura 3.7 Aplicaia ExempluPO

Figura 3.8 Caseta de dialog About ExempluPO

3.4 Modificarea interfeei aplicaiei


Elementele vizuale ale unui proiect se numesc resurse. Spre exemplu, casetele de dialog, pictogramele i meniurile constituie resurse. Numit sugestiv editor de resurse, acesta este instrumentul din Visual Studio care se folosete pentru proiectarea resurselor de diferite tipuri i modificarea aspectului efectiv al aplicaiei. Pentru a aduga un nou buton, va trebui s se deschid macheta casetei de dialog. Pentru aceasta se parcurg urmtorii pai: 1. Se selecteaz pagina ResourceView a seciunii spaiului de lucru al proiectului. Se va afia lista cu resursele proiectului. 2, Se expandeaz lista de resurse prin efectuarea unui clic pe semnul + din stnga etichetei ExempluPO Resources i se expandeaz catalogul Dialog. Aa cum se vede n figura 3.9, apar doi identificatori de dialog, IDD_ABOUTBOX I IDD_EXEMPLUPO_DIALOG. 50

Figura 3.9 Identificatorii de dialog din pagina ResourceView 3. Se efectueaz un dublu clic pe identificatorul IDD_EXEMPLUPO_DIALOG. n consecin va fi afiat macheta ferestrei dialog principale a aplicaiei ExempluPO, ca n figura 310.

Figura 3.10

Editare idd_ExempluPO_dialog 51

La rularea programului, dialogul va aprea aa cum apare n editorul de resurse. Acum se poate modifica macheta dialogului prin intermediul editorului de resurse. Pentru adugarea unui buton n cadrul dialogului ExempluPO se parcurg urmtorii pai: 1. nainte de a aduga butonul, se nltur controlul etichet TODO care apare n centul machetei dialogului ExempluPO. Se efectueaz un clic pe textul TODO: place dialog controls here; n jurul textului este afiat un dreptunghi de formatare (figura 3.11). Se apas tasta Delete. Controlul etichet este nlturat de pe macheta dialogului.

Figura 3.11

tergerea textului implicit din caseta de dialog

2. Se selecteaz controlul buton din caseta cu controale, aa cum se vede n figura 3.12. Se deplaseaz mouse-ul deasupra machetei dialogului. Aflat pe suprafaa machetei, cursorul mouse-ului devine o cruce pentru a indica poziia n care va fi plasat noul buton. Se plaseaz pointerul (crucea) departe de butoanele OK i Cancel i apoi se efectueaz un clic cu mouse-ul. Astfel se va afia un nou buton, etichetat Buttonl, ilustrat n figura 3.13.

52

Figura 3.12

Selectarea controlului de tip buton din caseta de controale

Figura 3.13

Adugarea unui buton n cadrul casetei de dialog 53

3. Pentru, a modifica eticheta butonului, trebuie ca acesta s fie selectat (ncadrat de un dreptunghi de formatare), ca n figura 3.11. Dac butonul nu este selectat, se selecteaz prin efectuarea unui clic pe suprafaa sa. Tastai Confirma. Odat ce tastai, este afiat caseta de dialog Push Button Properties, nfiat n figura 1.14. 4. Se tasteaz IDC_CONFIRMA n cadrul casetei combinate ID din caseta de dialog Push Button Properties, nlocuind textul implicit IDC_BUTTON1. Astfel, identificatorul butonului are o semnificaie mai evident.

Figura 3.14

Caseta de dialog Push Button Properties

5. Dup nchiderea casetei de dialog Push Button Properties, eticheta noului buton din cadrul dialogului idd_ExempluPO__dialog va fi acum CONFIRMA.

3.5 Asocierea de cod cu interfaa


Pentru a fi utilizat butonul trebuie s se scrie secvena de cod care de fapt const dect ntr-o singur linie. Pentru a asocia codul necesar unui buton se parcurg urmtorii pai: 1. Se deschide dialogul ExempluPO n cadrul editorului de resurse. 2. Se efectueaz un clic cu butonul drept (de la mouse) pe butonul Confirma de pe suprafaa dialogului, dup care se selecteaz opiunea Events din meniul contextual afiat. Se va deschide caseta de dialog New Windows Message and Event Handlers corespunztoare clasei dialog (figura 3.15). La efectuarea unui clic asupra butonului Confirma (n timpul rulrii aplicaiei), Windows trimite dialogului ExempluPO un mesaj. Caseta de dialog New Windows Message and Event Handlers va permite s se intercepteze acest mesaj i s executai o - numit secven de cod care s rspund la eveniment. 3. Se va selecta BN_CLICKED din lista New Windows Messages/Events. Se observ c primul element din list este selectat n mod implicit. 4. Se efectueaz un clic pe butonul Add and Edit. Se va afia caseta de dialog Add Member Function, ilustrat n figura 3.16. Aici se va da un nume funciei din program care va fi apelat de fiecare dat cnd caseta de dialog primete mesajul BN_CLICKED pentru butonul CONFIRMA. 54

Figura 3.15

Adugare de cod pentru evenimentul de acionare a butonului

Figura 3.16

Denumirea funciei apelat de eveniment 55

5 Se efectueaz un clic pe OK pentru a accepta numele implicit OnConfirma. Corpul noii funcii apare n fereastra editorului, ca n figura 3.17.

Figura 3.17

Codul funciei membru OnConfirma

Funcia este adugat ca i membru al clasei CExempluPODlg. Aceast clas a fost creat i denumit n mod automat la crearea proiectului de ctre AppWizard. Funcia OnConfirma poate fi completat cu urmtorul cod void CExempluPODlg::OnConfirma() { // TODO: Add your control notification handler code here MessageBox(Multumesc de ajutor!); } Prin folosirea funciei predefinite MessageBox (), oricnd se efectueaz un clic pe butonul Confirma va fi afiat ntr-o fereastr mic mesajul Multumesc de ajutor!. Atunci cnd se aduce modificri unui proiect i dorim s vedem dac acestea funcioneaz corect, va trebui s se repete procesul de asamblare i rulare. Se efectueaz un clic pe butonul Build sau se selecteaz Build ExempluPO.exe din meniul Build sau 56

se apas F7. Astfel se va relua asamblarea fiierului executabil, fiind incluse toate modificrile aduse resurselor sau codului. Modificrile sunt salvate automat la asamblarea proiectului Visual Studio salveaz automat orice fiier modificat nainte de a ncepe asamblarea proiectului, astfel c nu mai trebuie s se salveze fiecare fiier editat. Dac n timpul compilrii apar erori, acestea vor fi afiate n pagina Build a seciunii Output aa. cum se vede n partea inferioar a ferestrei Visual Studio ilustrat n figura 3.18.

Figura 3.18

Erorile sunt afiate n pagina build

n continuare se efectueaz un clic pe butonul Execute sau se selecteaz Execute ExempluPO.exe din meniul Build sau se apas CTRL+F5. Dialogul ExempluPO ar trebui s fie afiat ca n figura 3.19. Dac se efectueaz un clic pe butonul Confirma va apare o fereastr de mesaj, similar cu cea din figura 3.20, care afieaz mesajul Multumesc de ajutor!. Dac se efectueaz un nou clic asupra butonului Confirma, se va primi acelai mesaj. Aceasta se ntmpl deoarece la fiecare clic asupra butonului programul acceseaz aceeai funcie OnConfirma ().

57

Figura 3.19

Execuia aplicaiei ExempluPO

Figura 3.20

Afiarea mesajului

Dac se efectueaz un nou clic asupra butonului Confirma, se va primi acelai mesaj. Aceasta se ntmpl deoarece la fiecare clic asupra butonului programul acceseaz aceeai funcie OnConfirma ().

3.6 Salvarea i nchiderea proiectului

Se poate salva un fiier anume n orice moment prin efectuarea unui clic pe butonul Save . Este posibil, n plus, s se salveze toate fiierele specificate prin . efectuarea unui clic pe butonul Save All

Salvarea unui proiect nu necesit nici o operaie. Odat ce s-a terminat lucrul cu un proiect, este suficient s se nchid. Pentru a nchide un proiect se selecteaz Close Workspace din meniul File sau pur i simplu se nchide Visual Studio. 58

3.7 Utilizarea mediului Deweloper Studio


Mediul Developer Studio utilizat de Visual C++ pare destul de complex la prima vedere. O numrtoare rapid arat c exist peste 100 de opiuni de meniu i aproximativ tot attea butoane de pe bara cu instrumente care pot fi selectate. Multe dintre acestea conduc la casete de dialog complexe i la pagini de proprieti care conin numeroase opiuni. Funcionalitatea att de bogat oferit de Developer Studio este justificat de faptul c acest mediu este utilizat pe scar larg pentru a produce aplicaii complexe, profesionale.

3.8 Personalizarea mediului Developer Studio


Exist multe modaliti prin care mediul Developer Studio poate fi personalizat. Opiunile de meniu i barele cu instrumente pot fi personalizate prin selectarea opiunii Customize din meniul Tools. Se pot personaliza, de asemenea, fonturile i culorile din ferestrele de editare, precum i alte elemente, prin intermediul comenzii Options din meniul Tools. I

3.9 Deschiderea unui proiect existent


Cea mai rapid modalitate de a redeschide un proiect este s se apeleze lista Recent Workspaces. n acest scop, se efectueaz un clic pe meniul File; apoi se selecteaz proiectul dorit din cadrul listei Recent Workspaces. Pentru a deschide un proiect care nu figureaz n lista Recent Workspaces, se selecteaz Open Workspace din meniul File. Pe ecran este afiat fereastra Open Workspace, nfiat n figura 3.21. Se acceseaz directorul folosit pentru proiectul ExempluPO. Sel selecteaz din list fiierul ExempluPO.dsw i se efectueaz un clic pe Open. Indiferent de metoda utilizat, proiectul ar trebui s fie acum deschis, cu titlul su afiat n bara de titlu a ferestrei Developer Studio. Mediul de lucru va deschide automat ultimul fiier surs editat (figura 3.22).

59

Figura 3.21

Deschiderea unui proiect existent prin selectarea fiierului .dsw

Figura 3.22

Aplicatia ExempluPO 60

Pentru a nltura fereastra Output care apare n partea inferioar a ecranului, efectuai un clic pe cruciulia din colul stnga sus al ferestrei. Un spaiu de lucru poate s conin mai multe proiecte.

3.10 Fereastra spaiului de lucru ai proiectului


Fereastra spaiului de lucra al proiectului este o fereastr andocabil. Exist mai multe astfel de ferestre (fereastra Output este una dintre ele), unele aprnd n modul depanare. Pentru a comuta ntre modul liber i modul andocabil pentru o fereastr, se efectueaz un dublu clic pe bara de titlu a respectivei ferestre. Fereastra spaiului de lucru al proiectului poate fi nchis prin efectuarea unui clic pe micul buton de nchidere aflat n colul dreapta sus. Redeschiderea ferestrei se realizeaz prin selectarea comenzii Workspace din meniul View. Toate ferestrele andocabile au comportamente similare. Fereastra spaiului de lucru al proiectului permite vizualizarea proiectul din mai multe perspective. Atunci cnd este deschis un proiect, n partea inferioar a ferestrei spaiului de lucru sunt disponibile trei pagini: ClassView, ResourceView i File View. n cazul proiectelor dezvoltate pentru aplicaii de baze de date este posibil s apar n plus o pagin DataView. Paginile din partea inferioar a ferestrei mpart proiectul n componente logice. Se va efectua un clic pe o pagin pentru a vizualiza reprezentarea corespunztoare. Fiecare reprezentare afieaz o structur arborescent de elemente care reprezint componente ale proiectului. Se poate expanda sau condensa elementele arborelui efectund clic pe simbolul plus (+) sau minus (-) alturat n partea stng a acestora.

3.11 Lucrul cu reprezentarea claselor


Dac se efectueaz un clic pe eticheta de pagin ClassView va fi afiat pagina ClassView (reprezentarea claselor), ilustrat n figura 3.23. Aceast reprezentare afieaz toate clasele folosite n cadrul proiectului. AppWizard a creat aceste clase odat cu crearea iniial a proiectului. Fiecare element aflat la nivelul secundar (mai puin elementul Global) reprezint o clas i afieaz numele respectivei clase. La expandarea unei clase, fiecare element subordonat reprezint fie o funcie tu, fie o variabil membru a clasei. De exemplu, n cadrul CExempluPODlg se poate vedea funcia membru OnConfirma(). Pagina ClassView se dovedete de multe ori a fi cea mai utilizat. De aici se poate accesa orice clas, orice funcie membru sau orice variabil din proiect. Efectuarea unui dublu clic asupra unui element va deschide fiierul cu cod surs corespunztor n fereastra editorului, avnd cursorul plasat pe linia corespunztoare elementului n cauz. 61

Figura 3.23

Selectarea paginii ClassView

Efectuarea unui dublu clic pe numele unei clase acceseaz definiia clasei. Efectuarea unui dublu clic pe o variabil membru acceseaz definiia variabilei. Efectuarea unui dublu clic pe o funcie membru acceseaz nceputul definiiei funciei din cadrul fiierului care implementeaz clasa. Pe lng posibilitatea de a naviga printre clasele din proiect, seciunea ClassView ofer i alte faciliti prin intermediul meniurilor contextuale. Un meniu contextual este afiat pe ecran lng cursorul mouse-ului la efectuarea unui clic cu butonul drept asupra unui element. Pentru a afia meniul contextual pentru un element din arborele de clase, se selecteaz respectivul element cu butonul drept al mouse-ului. Elementul n cauz va ii evideniat i alturi de el va fi afiat meniul de context. Meniul contextual afiat depinde de tipul elementului selectat. Dac efectum un clic pe numele clasei CExempluPODlg se va afia meniul contextual al clasei (figura 3.24)

62

Figura 3.24

Afiarea meniului contextual

Meniul contextual permite efectuarea unor operaii diverse asupra clasei selectate. Selectarea opiunii Go to Definition are acelai efect cu efectuarea unui dublu clic pe numele clasei, i anume accesarea fiierului surs care conine definiia clasei. Patru dintre opiunile meniului sunt folosite pentru adugarea de funcii sau variabile n cadrul clasei. Dac se efectueaz un clic pe opiunea References, pe ecran va aprea mesajul din figura 3.25

Figura 3.25 63

Dac se efectueaz un clic pe Yes, se va genera fiierul de navigare. Proiectul va fi asamblat automat. Odat ncheiat procesul, se va nchide fereastra Output prin efectuarea unui clic pe cruciulia aflat n colul din stnga sus. Informaiile de navigare aduc faciliti suplimentare de navigare, disponibile prin intermediul meniului contextual din ClassView. Opiunea References permite afiarea tuturor locaiilor din proiect care fac referire la elementul selectat. Pentru fiecare referin sunt afiate numele fiierului surs i numrul ei, oferind posibilitatea de a accesa direct oricare dintre linii. Opiunea Derived Classes afieaz detalii privind clasa selectat i clasele derivate din aceasta. Opiunea Base Classes afieaz detalii privind clasa selectat i toate clasele sale de baz, inclusiv clasele din biblioteca MFC ( figura 3.26).

Figura 3.26

Activarea opiunii Base Classes

Atunci cnd se apeleaz meniul contextual pentru funciile sau variabilele membru, opiunea Calls afieaz toate funciile apelate de ctre funcia membru selectat, iar opiunea Called By afieaz toate locaiile din proiect care conin un apel al funciei. Opiunea Group By Access din meniul contextual este folosit pentru a ordona membrii clasei. Acetia sunt afiai n ordine alfabetic n cazul n care opiunea Group By Access nu este bifat; n caz contrar, membrii sunt afiai n ordinea tipului de acces - privat, protejat i apoi public. Pentru a prezenta avantajele meniului contextual vom dezvolta aplicaia ExempluPO, permind ieirea din program numai dac butonul Confirma a fost acionat cel puin odat. nainte de prsirea aplicaiei se va afia de cte ori a fost acionat butonul Confirma. Se va aduga o variabil membru activnd meniul contextual pentru clasa CExempluPODlg i selectnd Add Member Variable. Va fi afiat caseta de dialog Add Member Variable, prezentat n figura 3.27. 64

Figura 3.27

Adugarea unei noi variabile

Va trebui s se specifice tipul, numele i modul de acces pentru noua variabil. Se va tasta int n caseta Variable Type i i m__numara n caseta Variabile Declaration. Se va lsa modul de acces s fie Public. Astfel se creeaz n cadrul clasei CExempluPODlg o variabil de tip ntreg numit m__numara. Aceast variabil va fi utilizat pentru a reine de cte ori s-a efectuat clic asupra butonului Confirma. Dup introducerea informaiile necesare, se efectueaz un clic pe OK. Noua variabil ar trebui s fie acum afiat n pagina ClassView ca element subordonat clasei CExempluPODlg. n continuare se va efectua un dublu clic pe elementul m_numara pentru deschiderea fereastrei editorului, cursorul fiind plasat n linia de cod care a fost adugat pentru definirea noii variabile. Deoarece aceast variabil va reine de cte ori s-a efectuat clic asupra butonului Confirma, ea va trebui s aib valoarea iniial zero. Locul potrivit pentru iniializarea variabilei este constructorul clasei CExempluPODlg. Pentru a aduga codul de iniializare, se efectueaz un clic pe elementul corespunztor funciei membru constructor CExempluPODlg (acesta fiind primul element subordonat clasei CExempluPODlg). Fereastra editorului va conine fiierul surs corespunztor. Pentru iniializarea variabilei contor, se va aduga prezentat n continuare: CExempluPODlg::CExempluPODlg(CWnd* pParent /*=NULL*/) : CDialog(CExempluPODlg::IDD, pParent) { //{{AFX_DATA_INIT(CExempluPODlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_numara=0; }

65

Variabila m_nClickCount este iniializat cu zero n constructorul clasei caset de dialog. Acum numrtoarea ncepe de la zero; mai departe va trebui s realizm incrementarea contorului la fiecare clic asupra butonului Confirma. Se efectueaz un dublu clic pe funcia membru OnConfirma () a clasei CExempluPODlg, vizualiznd codul acesteia. Pentru a se incrementa variabila contor, se adauga m_numara++ coform secvenei de cod urmtoare: void CExempluPODlg::OnConfirma() { // TODO: Add your control notification handler code here MessageBox("Multumesc de ajutor!"); m_numara++; } OnConfirma() este o funcie pentru tratarea mesajelor care este apelat de fiecare dat cnd se efectueaz un clic pe butonul lDC_CONFIRMA. Pe lng afiarea unui mesaj pentru utilizator, funcia incrementeaz o variabil contor pentru a numra de cte ori a fost apsat butonul. Variabila contor va reine numrul de clicuri. Urmtorul pas const n crearea unei funcii logice care va trata situaiile n care s-a fcut sau nu clic pe butonul Confirma. Pentru aceasta se efectueaz un clic cu butonul drept pe numele clasei CExempluPODlg pentru apela meniul contextual. Se selecteaz Add Member Function i va fi afiat caseta de dialog Add Member Function ( figura 3.28). Aceast caset de dialog este folosit pentru adugarea unei funcii membru ntr-o clas.

Figura 3.28

Adugarea unei funcii membru ntr-o clas

Se va specifica tipul funciei BOOL n caseta Function Type i numele funciei Clicnumara n caseta Function Declaration. Dac noua funcie necesit parametri, acetia pot fi introdui de asemenea n caseta Function Declaration. De asemenea ar trebui ca butonul de opiune care stabilete modul de acces Public s fie selectat, iar casetele de validare Static i Virtual trebuie lsate ambele invalidate. Dup terminarea operaiilor se efectueaz clic pe OK. Noua funcie ar trebui 66

s apar acum n seciunea ClassView ca i element subordonat clasei CExempluPODlg. Corpul acestei funcii este vizibil n fereastra editorului. n continuare se adaug liniile de cod. BOOL CExempluPODlg::clicnumara() { if (m_numara==0) { MessageBox("Nu ai confirmat", "Nu poti termina", MB_ICONSTOP); return FALSE; } if(m_numara>1) { CString str; str.Format("Ai confirmat de %d ori", m_numara); MessageBox(str); } else { MessageBox("S-a confirmat odata"); } return TRUE; } Funcia realizat clicnumara este gata, dar nc nu este folosit nicieri n program. Pentru a integra funcia se va deschide pagina ResourceView de la baza ferestrei spaiului de lucra a proiectului, ce fieaz o list cu resursele din cadrul proiectului (figura 3.29).

Figura 3.29

Selectarea pagini Resource View 67

Aceast reprezentare afieaz toate resursele folosite n proiect. O Funcia MessageBox () are mai multe forme. n acest caz este transmis indicatorul mb_iconstop, ceea ce duce la afiarea unui semn de stop alturi de textul mesajului. Funcia Format () a clasei Cstring este utilizat pentru a compune un mesaj textual care este transmis apoi funciei MessageBox ().

3.12 Resurse Visual C++


Noiunea de resurs cuprinde elementele vizuale ale unui proiect. De pild, casetele de dialog sunt resurse, la fel ca i meniurile sau pictogramele. Asemeni reprezentrii claselor, reprezentarea resurselor afieaz un meniu contextual la efectuarea unui clic cu butonul drept asupra unui element. Se va selcta Insert din meniul contextual ExempluPO Resorces. Pe ecran va aprea caseta de dialog Insert Resource, ca n figura 3.30.

Figura 3.30

Caseta de dialog Insert Resources

Fereastra spaiului de lucru al proiecrtului este o fereastr andocabil. Exist mai multe tipuri de astfel de ferestre, unele aprnd n modul depanare Pentru a comuta ntre modul liber i modul andocabil pentru o fereastr, se va efectua un dublu click pe bara de titlu a respectivei ferestre. Fereastra spaiului de lucru al proiectului poate fi nchis prin efectuarea unui click pe micul buton de nchidere din colul dreapta sus. Fereastra spaiului de lucru al proiectului ne permite s vizualizm proiectul din mai multe perspective. Atunci cnd este deschis un proiect n partea inferioar a ferestrei spaiului de lucru sunt disponibile obligatoriu paginile: ClassView ResourceView, FileView. 68

Seciunea ClassView conine structura de clase ale proiectului iar prin acionarea ptratului din faa numelui unei clase, semnul + se transform n i are loc expandarea nodului respectiv fiind afiat un nivel ce descinde din nodul ce conine numele clasei i care conine toate prototipurile funciilor membre ale clasei ca i variabilele membre. Fiierele dintr-un proiect VisualC++ se mpart n : - Fiiere header - sunt fiiere care conin partea de implementare a clasei. n interiorul clasei se vor afla doar declaraiile metodelor(funcii membre ale clasei) i de asemenea declaraii ale variabilelor membre ale clarei. Acestea mai pot conine i implementarea unora dintre funciile membru, o astfel de implementare mai poart numele de implementare inline a metodelor. Aceste metode vor funciona n momentul cnd vor fi apelare ca nite macrouri, adic vor expanda i nu vor crea propria stiv n memorie. - Fiiere surs - sunt fiiere care includ fiierele header i conin definiia metodelor declarate n fiierele header. - Fiiere resurs - sunt fiiere ce conin resurse ale proiectului ex:imagini. Seciunea FileView conine lista tuturor fiierelor aplicaiei. Acestea sunt afiate sub forma unui arbore cu patru noduri care se desprind din rdcin. Primul dintre acestea, Header Files, conine fiierele header ale proiectului i prin expandarea sa va fi afiat nc un nivel ce conine toate fiierele de acest tip. Fiierele surs se vor gsi in nodul cu numele Source File iar fiierele de resurse se vor gsi n nodul Resource File. Mai exist un nod a crui expandare va duce la afiarea tuturor fiierelor externe ca noduri fii ale acestuia i care are numele External Dependencies. Seciunea ResourceView conine lista cu resursele folosite n cadrul proiectului. Resursa reprezint un element vizual al unui proiect. De pild casetele de dialog ca i meniurile sau pictogramele sunt resurse. Motivul pentru care resurse de genul meniurilor, al tabelelor de iruri i al casetelor de dialog sunt desprite de codul surs este acela c se dorete posibilitatea de modificare a acestora independent de acesta. Astfel se nlesnete foarte mult crearea de aplicaii internaionale. Spre exemplu, toate irurile dintr-o tabel de iruri pot fi traduse ntr-o a doua limb, fr a fi modificat codul surs.

3.13 Tipuri de resurse


Se pot vedea n aceast caset diferitele tipuri de resurse care pot fi utilizate ntrun proiect Visual C++. O tabel de acceleratori reprezint o list de asocieri ntre combinaii de taste i comenzi din program. O denumire uzual pentru accelerator este cea de combinaie de taste. O combinaie de taste reprezint o modalitate mai rapid de a executa o comanda dect selectarea acesteia dintr-un meniu. O resurs de tip bitmap este o imagine de o dimensiune oarecare compus din puncte. Fiecare punct poate avea o culoare distinct. Bitmap-urile sunt utilizate pentru afiarea imaginilor care apar pe barele cu instrumente. Un cursor este o resurs de tip imagine. Cursoarele sunt folosite n principal ca reprezentri ale indicatorului mouse-ului (cursorul standard din Windows este o 69

sgeata). Trstura distinctiv a unui cursor este prezena unui punct senzitiv, care este folosit pentru a urmri poziia acestuia pe ecran. O pictogram este, de asemenea, o resurs de tip imagine. Proiectul ExempluPO conine o pictogram care se numete IDR_MAINFRAME. Dac se efectueaz un dublu clic pe elementul IDR_MAINFRAME n fereastra editorului va fi deschis pictogram MFC standard. O resurs de tip dialog este o machet de fereastr care poate conine celelalte tipuri de resurse, aa cum sunt meniurile i butoanele. O resurs de tip meniu conine exact ceea ce sugereaz numele su, i anume un meniu. De regul, o aplicaie include un meniu n partea superioar a ferestrei sale principale (aa cum este si cazul cu Developer Studio), ns pot exista mai multe meniuri. De exemplu este posibil adugarea ntr-un proiect a unei resurse de tip meniu i utilizarea acesteia ca i meniu de context. O resurs de tip tabel de iruri ar trebui s conin toate irurile de caractere folosite ntr-o aplicaie. Fiecare element are asociat un identificator unic, utilizat pentru a referi irul respectiv n cadrul codului surs. Motivul pentru care toate irurile sunt introduse ntr-o tabel de iruri i nu direct n fiierele surs este nlesnirea traducerii n alte limbi. Dac toate textele utilizate ntr-o aplicaie se afl ntr-o tabel de iruri, este posibil crearea unei a doua tabele intr-o alt limb. Dup lansarea aplicaiei este utilizat tabela de iruri corespunztoare. O resurs de tip bar cu instrumente conine o mulime de butoane. De regul, fiecare buton reprezint o comand de meniu. Pe suprafaa butoanelor pot fi desenate imagini sub form de bitmap-uri i fiecare buton poate avea asociat o explicaie care va fi afiat atunci cnd mouse-ul se deplaseaz deasupra butonului. O resurs de tip versiune conine informaii despre aplicaii, ca de pild firma productoare, numele produsului, un numr de versiune i aa mai departe. Aceste informaii se afl ntr-un format standard care permite accesarea lor din alte aplicaii. Resurse noi pot fi adugate n orice moment. La creare, fiecare resurs primete automat un nume unic. De exemplu, o nou machet de dialog ar putea primi numele IDD_DIALOG1.

Figura 3.31

Caseta de dialog Resource Symbols 70

Programatorii nlocuiesc de obicei numele generate automat cu nume de resurse mai sugestive pentru contextul programului, aa cum s-a fcut cnd s-a locuit numele IDC_BUTTON1 cu IDC_CONFIRM. Pentru a afia numele tuturor resurselor din proiect, se va selcta Resource Syjmbols din meniul View. Va fi afiat caseta de dialog Resource Symbols (figura 3.31). Se poate utiliza caseta de dialog Resource Symbols pentru a identifica o resurs anume pe numelui su simbolic prin selectarea numelui n cadrul listei i efectuarea unui clic pe butonul View Use. Fiecare resurs din cadrul proiectului poate fi editat prin efectuarea unui dublu clic pe numele acesteia din seciunea ResourceView. Instrumentele i opiunile disponibile n fereastra editorului se modific n concordan cu tipul resursei editate. Prin intermediul seciunii Resource View se parcurg paii urmtori: 1. Se efectueaz dublu clic pe elementul IDD_ExempluPO_DIALOG pentru a deschide macheta dialogului. 2. Se efectueaz dublu clic pe butonul OK i se afieaz caseta de dialog Add Member Function. Se accept numele implicit al funciei membru OnOK. Se va afia scheletul noii funcii n fereastra editorului. 3. Se edita funcia OnOk conform secvenei de cod urmtoare void CExempluPODlg::OnOK() { // TODO: Add extra validation here if(clicnumara()==TRUE) { CDialog::OnOK(); } }

void CExempluPODlg::OnCancel() { // TODO: Add extra cleanup here if (clicnumara()==TRUE) { CDialog::OnCancel(); } } 4. Se va efectua dublu clic pe elementul IDD_ExempluPO_DIALOG pentru a deschide din nou macheta dialogului. 5. Se efectueaz dublu clic pe butonul Cansel. 6. Se efectueaz un clic pe OK pentru a acepta numele implicit al funciei membru: OnCancel 7. Se editeaz funcia implicit OnCancel conform secvenei de cod urmtoare 71

void CExempluPODlg::OnCancel() { // TODO: Add extra cleanup here if (clicnumara()==TRUE) { CDialog::OnCancel(); } } Acum aplicaia poate fi asamblat i rulat. Dac se ncearc ieirea din program fr confirmare este afiat mesajul urmtor:

Figura 3.32 Dac se apas butonul confirm este afiat mesajul urmtor.

Figura 3.33 Dup ce este apsat butonul confirm se poate iei din program i se afieaz numrul de confirmri.

Figura 3.34

72

3.14

Utilizarea controalelor

n cadrul unei resurse de tipul caset de dialog pot fi plasate o serie de instrumente numite controale. Acestea au rolul de a facilita afiarea i introducerea de date ca i de a executa o comand ca urmare a acionrii asupra unora dintre ele. Dintre aceste controale menionez: butoane de comand, radio butoane, casete de opiune, casete de editare, etichete, casete de grupare, controlul spin, bare de derulare, indicatorul de evoluie, controlul imagine, caseta combinat, glisorul, si altele. Controalele se gsesc n caseta Controls. Aceast caset poate s fie activat sau dezactivat din meniul Tools selectnd opiunea Customize iar din caseta de dialog ce va fi afiat, se va selecta seciunea Toolbars din partea de sus a acesteia. Asiguraiv acum c este selectat opiunea Controls dac dorii afiarea casetei de instrumente Controls, sau c nu este selectat dac dorii dezactivarea acesteia.

3.14.1 Controale de tip buton de comand


Butoanele sunt controalele utilizate cel mai frecvent. Ele se ntlnesc n aproape toate casetele de dialog. Butonul de comand este cel mai simplu control din Windows. Fiecare buton de comand reprezint o singur comand i, la acionarea unui clic asupra sa, ndeplinete aciunea care execut acea comand. Aproape toate casetele de dialog conin cel puin dou butoane de comand: Cancel i OK. Editorul de resurse adaug n casetele de dialog nou create butoanele de comand Cancel i OK. Clasa MFC de baz pentru toate casetele de dialog este CDialog iar aceasta conine implementri implicite care rspund la mesajele BN_CLICKED ale acestor butoane: OnOK() i OnCancel(). Putei s supradefinii aceste funcii n propriile clase dialog derivate din CDialog pentru a le ajusta comportmentul. AppWizard creeaz automat aceste butoane pentru aplicaiile de tip dialog. Multe casete de dialog implic i alte butoane de comand; acestea pot fi adugate prin intermediul editorului de resurse. Proprietile i opiunile de stil iniiale pentru fiecare buton sunt specificate tot prin intermediul editorului de resurse.

3.14.2 Controlul etichet static


Deseori se adaug text cu rol de etichet pentru controale sau pentru a descrie o opiune, sau pur i simplu pentru a afia o propoziie. Atunci cnd ntr-o caset de dialog este nevoie de afiarea unui text simplu apelai la controlul etichet static. Fiecare control etichet static poate afia pn la 255 de caractere, introduse ca i etichet. Putei folosi caracterul (\n) linie nou pentru a desfura textul pe mai multe linii, fiind posibil alinierea la stnga, la dreapta sau pe 73

centru. O serie de opiuni de stil permit ncadrarea controlului cu margini adncite, ridicate sau de alte diverse tipuri.

3.14.3

Casete de editare

Casetele de editare permit introducerea de informaii n timpul rulrii programului. Pentru acest lucru inserai o caset de editare prin intermediul editorului de resurse din caseta de instrumente Controls. Din meniul contextual afiat la executarea unui clic dreapta pe acest control va fi selectat opiunea ClassWizard. Din caseta ce va fi afiat alegei seciunea Member Variables i asigurai-v c n caseta derulant Object IDs este selectat controlul corespunztor(numele casetei de editare). Acionai apoi butonul Add Variable iar n caseta da dialog ce se va deschide introducei cmpul Member variable name un nume pentru variabila ce o vei asocia controlului (acesta va ncepe obligatoriu cu m_). Din caseta combinat Category alegei tipul noii variabile membru, acesta va fi CString dac dorii s introducei un ir de caractere, int pentru un numr ntreg etc. Aceast variabil apare ca i variabil membru a clasei asociate casetei de dialog creia i aparine controlul caset de editare i are rolul de a-i nsui valoarea introdus de utilizator n caseta de editare, pentru ca aceasta s poat fi utilizat n program. Variabila mai poate fi folosit i la setarea unei valori n caseta de editare. Dac se dorete preluarea de informaie, dup ce utilizatorul a introdus o valoare n caseta de editare, vom apela funcia UpdateData(). n acest moment variabila este setat pe valoarea introdus, i apelul acestei funcii se va face, de exemplu la acionarea unui buton. Dac se dorete afiarea coninutului variabilei n caseta de editare se seteaz mai nti variabila pe valoarea ce va fi afiat iar mai apoi se apeleaz aceeai funcie ca i pentru operaia invers prezentat mai sus dat cu argumentul FALSE de maniera UpdateData(FALSE).

3.14.4 Controlul bar de derulare


Barele de derulare se ntlnesc de multe ori ataate de marginile unei ferestre n scopul derulrii coninutului acestora. Cu toate acestea ele se pot utiliza pentru a specifica o poziie n cadrul unui interval specificat. Paleta Controls conine dou instrumente, unul asociat barelor de derulare orizontale i unul barelor de derulare verticale. Pagina Style a casetei de dialog ScrollBar Properties conine o opiune ce ne permite alinierea barei de derulare, opiunea Align. Aceasta poate lua valorile: None deseneaz o bar de derulare avnd aceleai dimensiuni cu cele ale barei de derulare plasate pe macheta casetei de dialog. Top/Left va fi desenat o bar de derulare avnd limea standard i fiind aliniat la marginile din stnga i sus ale barei derulante plasate pe caseta de dialog. 74

Buttom/Right Asemntor cu opiunea anterioar doar c alinierea se va face la marginile din dreapta i jos ale barei de derulare. Maparea unei variabile peste un control de tip bar de derulare presupune urmtorii pai: - Se acceseaz meniul contextual pentru controlul bar de derulare printr-un clic dreapta pe acest control; - Se apeleaz opiunea ClassWizard care va deschide caseta de dialog corespunztoare; - Vom accesa seciunea Member Variables a acestei casete de dialog; - Ne asigurm ca n seciunea Control IDs este selectat numele resursei bar de derulare; - Acionm butonul Add Variable - n seciunea Member variable name a casetei de dialog deschise vom introduce numele noii variabile care va ncepe obligatoriu cu m_. - n seciunea Category vom alege control - Acionm butoanele OK pentru toate casetele de dialog deschise. Unei astfel de variabile asociate unui indicator de evoluie i vom asocia un interval. Poziia la care se afl iteratorul de pe bara de derulare va reprezenta la un moment dat o valoare din intervalul setat. Fixarea intervalului se va face cu funcia SetScrollRange. Aceasta primete dou valori pentru cele dou capete ale intervalului si este identic pentru cele dou tipuri se scrollbar-uri (orizontal i vertical). Putei transmite orice valori ntregi ca limite inferioar i superioar pentru interval, dar diferena dintre aceste dou limite nu trebuie s depeasc 32767. Se poate stabili poziia curent a barei de derulare, ilustrat de caseta mobil ce se afl pe bar , cu ajutorul funciei SetScrollPos() i transmind o valoare ntreag ce reprezint poziia n cadrul intervalului definit. Exist i o funcie invers GetScrollPos() care ntoarce valoarea poziiei curente.

3.14.5 Controlul glisor


Un control de tip glisor permite utilizatorului s stabileasc o valoare prin tragerea unui indicator de-a lungul unui interval liniar i plasarea acestuia ntr-o anumit poziie asemntor unui poteniometru de volum al unui sistem audio. Controlul glisor este un echivalent sofisticat al controlului bar de derulare prin aceea c are asociat de asemenea un interval ce poate fi definit, i o poziie curent. Cu toate acestea, controlul glisor permite o personalizare i o configurare mult mai complexe dect controlul bar de derulare. Se poate plasa un control glisor pe suprafaa unei casete de dialog dup selectarea sa din cadrul paletei Controls, aa cum s-a indicat i n cazul altor controale. Se poate dimensiona i poziiona controlul dup nevoie i este bine s stabileasc un identificator adecvat pentru control prin intermediul paginii General a casetei de dialog Slider Properties . 75

n pagina Styles se afl dou casete combinate. Prima dintre ele este Orientation, care permite alegerea uneia din opiunile Horizontal sau Vertical. Glisorul este implicit orizontal, dac schimbai orientarea s-ar putea s fii nevoit s redimensionai fereastra controlului pentru a o adapta noului aspect. Cea de-a doua caset combinat permite alegerea unui tip de cursor. n mod normal este selectat tipul Both, care are ca efect desenarea unei casete rectangulare pe post de indicator de poziie. Pute nlocui tipul Both cu tipul Top/Left ceea ce va duce la afiarea unui indicator al crui vrf este ndreptat spre partea superioar a unui glisor orizontal, respectiv ctre partea din stnga a unui glisor vertical. Se poate selecta ca alternativ tipul Buttom/Right pentru afiarea unui indicator al crui vrf este ndreptat n partea opus fa de indicatorul Top/Left. De asemenea mai pot fi selectate o serie de casete de validare: - Tick Marks. Dac aceast opiune este selectat glisorul va afia linii mici perpendiculare pe direcia controlului i situate n partea indicat de cursor, scopul lor este acela de a ajuta utilizatorul s aproximeze mai bine poziia cursorului. - Auto Ticks. Selectarea acestei opiuni duce la plasarea diviziunilor de-a lungul intervalului astfel nct s corespund valorii de increment curente. - Enabled Selection. Dac opiunea este selectat, este adugat o bar alb care permite programului s afieze un interval de selecie prin intermediul unor mici triunghiuri. - Border Dac se selecteaz aceast opiune, n jurul glisorului se va trasa un cadru negru subire. Maparea unei variabile peste un control glisor se realizeaz aproape identic cu maparea unei variabile peste o bar de derulare. O variabil mapat peste un control de tip glisor va fi de tipul CSliderCtrl. Putei folosi o astfel de variabil pentru activarea sau dezactivarea din program a controlului respectiv. Aceasta se poate face apelnd funcia EnableWindow() a variabilei mapate, transmind TRUE sau FALSE pentru a activa, respectiv dezactiva fereastra. Acest lucru l-ai putea dori pentru a mpiedica utilizatorul s modifice starea controlului n anumite circumstane. Intervalul unui control glisor poate fi stabilit prin apelul funciei SetRange() asociate, n apel transmindu-de ca primi doi parametrii valorile ntregi minim i maxim pentru poziia glisorului. Al treilea parametru poate lua valoarea FALSE i are ca efect prevenirea redesenrii automate a cursorului. Acest parametru este cu caracter opional. Exist de asemenea funcii care stabilesc limitele inferioar i superioar ale intervalului, n acest scop transmindu-se un ntreg n apelul funciilor SetRangeMin() sau SetRangeMax(). Funciile reciproce GetRangeMin() i GetRangeMax() ntorc limitele curente ale intervalului de valori. Acea suprafa a controlului glisor de-a lungul creia se deplaseaz glisorul reprezint canalul rectangular. Dimensiunile i poziia acestei suprafee rectangulare pot fi determinate apelnd funcia GetCannelRect() a clasei CSliderCtrl. Poziia cursorului poate fi stabilit prin apelul funciei SetPos(), transmindu-se o valoare ntreag care reprezint noua poziie din cadrul intervalului, i poate fi determinat prin valoarea ntoars de apelul funciei membru GetPos(). 76

3.15 Lucrul cu imagini n Visual C++


Imaginile grafice domin mediul Windows. Lucrurile stau astfel din mai multe motive. Imaginile vor fi nelese de orice persoan indiferent de limba pe care o vorbete, ocup mai puin spaiu dect echivalentele textule i n plus arat bine. Principalul scop al utilizrii imaginilor grafice este s ajute utilizatorul s recunoasc un program sau o funcie anume mai rapid dect din parcurgerea unui text descriptiv. Aplicaiile Windows folosesc mai multe tipuri de imagini grafice: - imagine pictogram este asociat cu nsi aplicaia i este afiat n Windows Explorer. De asemenea pictograma unei aplicaii este afiat de regul pe suprafaa de lucru pentru a indica o scurttur. - Imaginile bitmap sunt folosite n cadrul ecranelor introductive i pe butoanele de pe barele de instrumente, putnd fi plasate i n casetele ce dialog sau n alte ferestre. - Imaginile cursor sunt folosite pentru a modifica reprezentarea grafic a cursorului de mouse. Acestea se ntlnesc frecvent n programele de desenare, avnd rolul de a sugera cum poate fi editat sau deplasat un obiect selectat de pe ecran. - Editorul de resurse din Developer Studio permite s se creeze i s se editeze fiecare tip de imagine. Se poate aduga ntr-un proiect pictograme, bitmap-uri i cursoare cte se doresc.

3.15.1 Utilizarea editorului de imagini


Editorul de resurse de tip imagine permite crearea de imagini de tipul bitmap, pictogram, sau cursor. Se poate desena cu mna liber sau s se foloseasc diferite opiuni i instrumente care v ajut la trasarea de figuri pline i contururi. Fereastra editorului este n mod normal mprit n dou seciuni, n stnga fiind afiat imaginea n mrime natural, iar n dreapta fiind afiat n versiune mrit. Aceasta din urm permite distingerea fiecrui pixel n parte n scopul unei editri ct mai precise. Ambele imagini sunt actualizate automat n timpul editrii. Indiferent de tipul resursei editate, multe din funciile de editare grafic sunt identice. Meniul Image este disponibil oricnd este activat o fereastr de editare a unei imagini. Acest meniu conine mai multe instruciuni de desenare. Opiunea Invert Colors ofer posibilitatea de a inversa culorile dintr-o zon selectat a unui bitmap. n plus, o zon selectat poate fi oglindit sau rotit. Tot prin intermediul meniului Image se poate defini i salva propriile palete de culori Instrumentele de desenare se afl n caseta cu instrumente Graphics, iar culorile se selecteaz din paleta Colors. 77

3.15.2 Crearea i editarea resurselor de tip pictogram


Din punct de vedere vizual distincia ntre bitmap-uri i pictograme este greu de fcut, dar exist o serie de deosebiri importante. Un bitmap este o secven de date care reprezint o imagine n culori format din pixeli. O pictogram se compune din dou bitmap-uri; primul reprezint o imagine n culori, iar cel de-al doilea reprezint un bitmap masc. mbinarea informaiilor coninute n aceste dou bitmap-uri face posibil existena zonelor de transparen i de inversare n cadrul pictogramelor. Se pot ntlni pictograme care au aspecte neregulate rotunde, de pild. n realitate, toate pictogramele sunt dreptunghiulare; masca de transparen este cea care le permite s par neregulate. O pictogram poate conine mai tulte imagini care difer prin dimensiune i numr de culori, fiind destinate unor dispozitive de afiare diferite. Un proiect poate conine oricte resurse de tip pictogram. Acestea pot fi create i desenate de la zero sau pot fi importate dintr-un proiect existent sau un fiier cu extensia .ico. Pictogramele nou create sunt iniial transparente i sunt destinate implicit dispozitivelor VGA, avnd dimensiunea de 32x32.

3.15.3 Crearea i editarea resurselor de tip bitmap


Resursele de tip bitmap au numeroase ntrebuinri. Pot fi utilizate pentru efecte vizuale, sau pentru afiarea lor pe butoane de comand ca alternativ la o etichet. Spre deosebire de dimensiunile relativ limitate ale pictogramelor, o imagine bitmap poate avea pn la 2048x2048 de pixeli. Din nou spre deosebire de pictograme, bitmap-urile nu conin atribute de culoare transparent sau invers. Un proiect poate conine oricte resurse de tip bitmap, acestea putnd fi create de la zero sau importate dintr-un fiier cu extensia .bmp.

3.15.4 Importarea imaginilor


Se poate importa resurse din fiiere i proiecte existente, sau chiar din fiiere executabile aflate n sistem.

3.15.5 Importul imaginilor din fiiere .ico i .bmp


Pentru a importa o pictogram sau un bitmap dintr-un fiier .ico sau .bmp, se vor parcurge urmtorii pai. - Se seleaz Import din meniul contextual al paginii Resource View, sau se selecteaz Resource din meniul Insert i apoi se efectueaz un click pe butonul 78

Import din caseta de dialog Insert Resource. Va fi afiat caseta de dialog Insert Resource. Aceast caset de dialog este o versiune puin modificat a dialogului File Open. Se acceseaz directorul corespunztor i se selecteaz fiierul coninnd resursa pe care se dorete a fi importat, apoi se efectueaz un click pe butonul Import Se poate utiliza caseta combinat File of Type pentru a determina afiarea exclusiv a unui anumit tip de fiiere resurs. Dac fiierul selectat are un tip recunoscut, resursa va fi adugat la proiect, va fi generat automat un identificator unic i n directorul proiectului va fi plasat o copie a fiierului importat.

3.15.6 Importarea resurselor din fiiere executabile


Pentru importarea resurselor din fiiere executabile se parcurg urmtorii pai: Se selecteaz Open din meniul File. Va fi afiat caseta de dialog Open obinuit. Se selecteaz Resource din caseta combinat Open As. Se selecteaz directorul corespunztor i n continuare fiierul executabil (.exe, .dll sau .ocx) din care se dorete s se importe; apoi se efectueaz un clic pe butonul Open. Resursele ncapsulate n fiierul executabil vor fi afiate n fereastra editorului. Ca exemplu, se selecteaz fiierul Cards.dll, plasat n mod normal n directorul c:\\Windows\\System. La deschiderea fiierului din sistem este bine s se valideze opiunea Open as Read-Only. Pentru vizualizarea resurselor, se deschide caseta de dialog cu proprieti i se efectueaz un clic pe pioneza afiat n colul din stnga sus pentru a menine caseta deschis. Cadrul Prewiew va nfia fiecare resurs selectat. Pentru a insera o resurs din lista afiat, se selecteaz cu mouse-ul, se ine butonul mouse-ului apsat mpreun cu tasta Ctrl i se va deplasa cursorul n interiorul paginii Resource View. Se elibereaz butonul mouse-ului n momentul n care alturi de cursorul su este afiat un semn plus. Resursa selectat va fi adugat la proiect. Din meniul File se selecteaz Close.

3.15.7 Utilizarea imaginilor n casetele de dialog


Exist multe modaliti de a afia imagini n cadrul casetelor de dialog. Pictogramele i bitmap-urile sunt afiate cu uurin ntr-o caset de dialog, folosind un control imagine i stabilindu-i proprietile pentru a afia resursa imagine dorit. Controalele imagine pot fi folosite i pentru crearea unor dreptunghiuri colorate sau a unor cadre n scopul de a grupa elementele dintr-o caset de dialog. n caseta de proprieti a controlului imagine, n seciunea General avem posibilitatea de a opta pentru unul din tipurile de imagine: 1. cadru - afieaz un cadru alb, gri sau adncit, folosit ca efect vizual pentru gruparea elementelor. 79

caset afieaz o caset alb, gri, sau tridimensional. pictogram afieaz o resurs imagine de tip pictogram. bitmap afieaz o resurs imagine de tip bitmap. metafiier extins afieaz imaginea stocat ntr-un metafiier extins. Se poate opta pentru una din aceste variante prin selectarea sa din caseta derulant a cmpului Type a casetei Picture Properties. n seciunea Image poate fi selectat una din resursele de tip imagine disponibile, resurs ce va fi afiat pe ecran n zona controlului imagine. O imagine bitmap poate fi ncrcat prin intermediul unui obiect CBitmap, apelnd funcia LoadBitmap a acestuia i transmindu-i identificatorul resursei. Bitmap-ul este apoi afiat n cadrul controlului de tip imagine prin apelarea metodei SetBitmap a acestui control, metoda va primi ca argument variabila de tip CBitmap. Exemplu: . . . CBitmap m_bmp; VERIFY(m_bmp.LoadBitmap(IDB_SUMSET)); m_b1.SetBitmap(m_bmp); . . . Unde m_b1 este variabila de tip control asociat unui control de tip imagine, IDB_SUMSET este o resurs de tip imagine creat n prealabil iar VERIFY a fost utilizat pentru a verifica corectitudinea modului n care se execut LoadBitmap.

2. 3. 4. 5.

3.15.8 Crearea butoanelor grafice


Deoarece imaginile sunt adesea mai uor de perceput dect cuvintele, uneori este de preferat afiarea unei imagini pe suprafaa unui buton n locul unei etichete textuale. Tocmai n acest scop, biblioteca MFC pune la dispoziie clasaCBitmapButton. Se folosete editorul de imagini pentru a crea bitmap-urile, iar butoanele de comand sunt plasate ntr-o machet de dialog n maniera cunoscut. La crearea de resurse pentru butoanele grafice trebuie s inem seama de dou lucruri. n primul rnd, se va specifica un ir de caractere ca identificator al bitmap-ului, i un numr care s fie folosit apoi cu #define. n al doilea rnd selectai proprietatea Owner Draw a controlului buton de comand. Resursa Bitmap va fi asociat cu butonul de comand prin intermediul funciei CbitmapButton::AutoLoad. Un buton de comand poate avea patru stri (ridicat, apsat, dezactivat sau selectat). Starea butonului se modific atunci cnd utilizatorul efectueaz un clic sau apas tasta tab, dar se poate schimba i prin cod. Butoanele de comand normale, care conin etichete textuale, se ocup automat de modificarea aspectului odat cu starea. De exemplu eticheta poate fi afiat adncit atunci cnd butonul este dezactivat. De afiarea butoanelor grafice este responsabil cel care le controleaz, rin urmare vom fi responsabili de furnizarea unei imagini pentru fiecare stare. n cazul n care se pune la dispoziie o singur imagine, utilizatorul nu va sesiza nici o schimbare 80

atunci cnd, de pild, efectueaz un clic pe buton. Trebuie, aadar, s furnizai imagini mcar pentru strile ridicat i apsat. Identificatorul unui astfel de bitmap trebuie s fie un ir de caractere (inclusiv ghilimelele) bazat pe eticheta butonului. De exemplu, dac butonul are eticheta SUMSET identificatorii pentru cele patru imagini vor fi: SUMSETU (ridicat), SUMSETD (apsat), SUMSETX (dezactivat) i SUMSETF (selectat).

3.16 Lucrul cu fiiere n Visual C++


Serializarea este o tehnic folosit pentru transformarea datelor aplicaiei ntr-o list secvenial de elemente de date individuale, urmat de stocarea lor pe disc. Serializarea documentelor este foarte util n cadrul aplicaiilor care trebuie s stocheze date din cadrul documentelor, dar sunt situaii n care este necesar crearea de fiiere, scrierea n acestea, ca i citirea lor n mod direct. Pe de alt parte este bine s folosim ct mai puin facilitile oferite de mediul de dezvoltare, pentru a putea s facem o eventual trecere relativ uoar pe un alt mediu ce nu ofer attea faciliti. MFC ofer o clas de ncapsulare pentru fiierele de pe disc, clas numit CFile. Aceast clas ncorporeaz toate operaiile cu fiiere i toate atributele asociate unui fiier de pe disc. Prin crearea i utilizarea obiectelor CFile putem s crem, deschidem, citim i scriem fiiere, apelnd la funciile oferite de clasa CFile. Indiferent dac serializm datele unui document sau scriem direct ntr-un fiier, vom fi nevoii s folosim pn la urm clasa CFile sau una din derivatele sale.

3.16.1 Crearea obiectelor de tip fiier


Exist trei moduri de a crea un obiect de tip CFile. Cel mai simplu mod de a crea un obiect CFile este de a apela constructorul implicit fr a transmite nici un fel de parametru, obiectul astfel creat ne avnd nici un corespondent pe disc i sigur c nu va fi nici deschis. Un astfel de obiect necesit deschiderea sau crearea unui nou fiier pe disc dup momentul crerii sale. O a doua versiune a constructorului primete un parametru, un identificator hFile, care trebuie s corespund unui fiier deschis.Aceast form poate fi utilizat pentru ataarea unui obiect CFile la un fiier deja deschis. A treia variant de constructor necesit doi parametrii: primul este un ir care conine calea i numele fiierului pe care dorim s-l deschidem sau s-l crem, iar cel de-al doilea reprezint o combinaie de indicatori de deschidere a fiierului. CFile, asemenea multor clase MFC, ncapsuleaz un indicator de fiier folosit de nucleul Win32 al sistemului de operare. Acest indicator poate fi accesat direct, aflnduse n variabila membru m_hFile a obiectului CFile. Dac fu a fost creat sau deschis nici 81

un fiier valid aceast variabil va avea valoarea CFile::hFileNull, iar n caz contrar va reine indicatorul asociat fiierului curent.

3.16.2

Deschiderea fiierelor

Una din cele mai importante operaii n manipularea fiierelor este deschiderea iniial a fiierului. Prin specificarea unor diferii indicatori se poate anuna anticipat modul n care se va lucra cu fiierul specificat. Se poate opta pentru o deschidere a fiierului numai pentru scriere, sau numai pentru citire sau att pentru scriere ct i pentru citire. Funcia membru Open() permite deschiderea unui fiier n unul din modurile specificate mai jos, prin transmiterea corespunztoare a celui de-al doilea parametru. Tipuri de indicatori: CFile::modeCreate - Creaz un fiier chear dac mai exist unul cu numele specificat CFile::modeNoTruncate - Poate fi combinat cu CFile::modeCreate efectul fiind cel de a nu crea fiierul dac el mai exist pe disc. CFile::modeRead - Fiierul va fi deschis doar pentru citire, scrierea fiind interzis CFile::modeWrite - Fiierul va fi deschis exclusiv pentru scriere, citirea datelor nu se poate realiza. CFile::modeReadWrite - Fiier deschis att n scriere ct i n citire. CFile::shareDenyNone - Fiierul poate fi citit i scris i de alte procese. CFile::shareExclusive - Fiierul nu poate fi scris sau citit de alte procese att timp ct el e exploatat de procesul curent. CFile::shareDenyRead - Nici un proces nu poate s citeasc fiierul atta timp ct acesta este deschis de procesul curent. CFile::shareDenyWrite - Nici un proces nu poate s scrie n fiier atta timp ct acesta este deschis de procesul curent. CFile::typeText - Fiier folosit pentru prelucrri specifice coninutului textual n cadrul unora dintre clasele derivate CFile::typeBinary - Nu se efectueaz nici un fel de prelucrri speciale asupra caracterelor la citirea sau scrierea acestora n fiier. Acest indicator este necesar doar n unele clase derivate. Primul parametru al funciei Open() reprezint numele fiierului sau calea complet pn la acesta dac el nu se afl n directorul de lucru curent. Unii identificatori pot fi combinai. Pentru crearea unui fiier ne putem confrunta cu dou situaii, anume fiierul poate s nu existe pe disc la locaia specificat, caz n care va fi creat un nou fiier gol, sau poate s existe deja un fiier cu numele dat, caz n care se va crea un nou fiier iar fiierul existent fa fi ters. Pentru a evita pierderile de date se va apela la o utilizare a indicatorului de deschidere CFile::modeCreate cu un indicator ce atenioneaz asupra 82

rescrierilor, este vorba de CFile::modeNoTruncate. Cei doi indicatori pot fi combinai folosind operatorul + sau operatorul sau logic( | ) ca mai jos. CFile fis; Fis.Open(MyFile, CFile::modeCreate + CFile::modeNoTruncate) ; sau CFile fis; Fis.Open(MyFile, CFile::modeCreate | CFile::modeNoTruncate) ; Dac fiierul va fi deschis cu succes funcia Open() va ntoarce valoarea TRUE iar n caz contrar va ntoarce valoarea FALSE. Dac la deschiderea unui fiier apare o eroare, este transmis un pointer la un obiect CFileException. Cauza erorii poate fi determinat pe baza variabilelor m_cause i m_IOsError, ambele fiind membre ale obiectului CFileException. Valorile tipice pentru valoarea m_cause sunt CFileException::fileNotFound, CFileException::diskFull i CFileException::accessDenied, specificnd faptul c fiierul nu exist, discul este plin i nu avem spaiu pentru scriere, sau nu avem drept de scriere.

3.16.3

Citirea i scrierea unui fiier

n funcie de modul de acces n care a fost deschis fiierul, dup deschiderea acestuia se poate trece la efectuarea operaiilor de citire i scriere. Pentru efectuarea acestor operaii clasa CFile pune la dispoziie funciile Read() i Write(). Operaiile de scriere i citire se vor face la o poziie dat n fiier. Dup deschiderea fiierului aceast poziie este stabilit la nceputul acestuia. Dac se citesc primii 200 de octei din fiier poziia va fi reactualizat, o viitoare citire realizndu-se de la poziia 200. Funcia Read() primete doi parametrii iar primul dintre acetia reprezint adresa unui buffer destinaie. Orice date citite vor fi depuse n acest buffer. Prin cel de-al doilea parametru se specific funciei Read() ci octei se dorete a se citi. Numrul de octei ce se vor citi nu va depi dimensiunea buffer-ului destinaie, i va fi mai mare dect zero. Dac se citesc mai muli octei dect permite buffer-ul exist riscul de a suprascrie zone de memorie vitale ale programului. Apelul funciei Read() ntoarce numrul de octei citii. Valoarea ntoars poate fi egal cu numrul octeilor solicitat a se citi, caz n care s-au citit toi octeii cerui, sau poate fi mai mic dect numrul de octei specificat n apel, indicnd faptul c pn la sfritul fiierului sunt mai puini octei dect numrul specificat, operaia de citire va decurge normal pentru octeii ce se pot citi. Dac funcia Read() ntoarce valoarea zero, poziia n fiier este la sfritul acestuia, operaia nu se poate deci realiza. Exemplu: CFile myFile(MyFile.tit,CFile::modeCreate); char buff[200]; UINT nrBytesRead; nrBytesRead = myFile.Read(buff,sizeof(buff)); 83

n exemplul de mai sus se citesc din fiierul myFile n buffer-ul buff un numr de octei egal cu dimensiunea buffer-ului. Dac dup citire valoarea lui nrBytesRead este mai mare dect zero, s-au citit un numr de octei egal cu valoarea ntoars, altfel nu s-a citit nimic. Dup citire se realizeaz un avans al poziiei curente n cadrul fiierului cu un numr de poziii egal cu valoarea ntoars de funcia Read(). Scrierea n fiier se realizeaz la poziia curent. Funcia Write() primete doi parametri, primul parametru este un buffer n care se gsete informaia ce va fi scris iar cel de-al doilea este un numr ntreg ce specific numrul de octei ce va fi scris din buffer. Dup scriere are loc un avans al poziiei curente n fiier cu un numr de poziii egal cu numrul de octei scrii.

3.16.4 Manipularea poziiei curente n fiier


Exist o poziie curent n cadrul fiierului care este folosit ca funcie de nceput pentru funciile Read() i Write(). La scrierea n fiier de informaie cu o dimensiune constant a nregistrrilor, se poate dori scrierea ntr-un loc specificat n fiier i nu neaparat la nceputul fiierului sau la poziia curent. Poziia actual a cursorului n cadrul fiierului poate fi determinat utiliznd funcia GetPosition(), care ntoarce o valoare de tip DWORD. Aceast poziie poate fi de asemenea modificat prin intermediul funciilor Seek(), SeekToBegin i SeekToEnd(), care plaseaz cursorul la o poziie anume, la nceputul sau, respectiv, la sfritul fiierului. Singura dintre aceste funcii care necesit parametrii este funaia Seek(), aceasta necesitnd doi parametrii. Primul parametru reprezint numrul de octei cu care se face deplasarea i este un numr de tip LONG, iar cel de-al doilea este poziia relativ fa de care se face deplasarea poate lua una din valorile: CFile::begin - deplasare relativ la nceputul fiierului. CFile::end - deplasare relativ la sfritul fiierului. CFile::current - deplasare relativ la poziia curent. Deplasarea se poate face n fa sau n spate relativ la punctul specificat, prin specificarea numrului de octei cu care se face deplasarea nensoit de semnul - sau respectiv nsoit de semnul -. Exemplu de deplasare nainte fa de nceputul fiierului cu 80 de octei: MyFile.Seek(80,CFile::begin); Exemplu de deplasare napoi fa de poziia curent a fiierului cu 30 de octei: MyFile.Seek(-30,CFile::current);

3.16.5 Informaii despre fiier


Exist un set de funcii ce furnizeaz informaii despre fiierul deschis curent. GetLength() ntoarce lungimea fiierului deschis curent ca o variabil de tip DWORD, de asemenea exist o funcie SetLength() care trunchiaz sau extinde fiierul la dimensiunea specificat ca parametru. Se poate spune despre cele dou funcii c sunt funcii pereche. Funcia GetStatus() este o funcie ce genereaz informaii despre 84

momentul crerii, al ultimei modificri ca i informaii despre atribute de citire i scriere. Aceast funcie are dou variante. Una dintre acestea opereaz asupra fiierului deja deschis punnd informaiile ntr-o variabil de tip CFileStatus transmis va parametru, ea este o funcie membru. Cea de-a doua variant primete ca prim parametru numele fiierului si va genera informaiile ntr-o variabil de tip CFileStatus transmis prin referin ca al doilea parametru. Aceast a doua variant este o funcie prieten (friend) pentru clasa CFile. Exemplu de utilizare: CFileStatus varStat; CFile::GetStatus(c:\\fis.tit, varStat); n acest moment informaiile sunt stocate n variabila varStat i por fi utilizate n diverse operaii. Structura unei variabile CFileStatus este: CTime m_mtime - Data i ora ultimei modificri CTime m_atime - Data i ora ultimei accesri CTime m_ctime - Data i ora crerii LONG m_size - Dimensiunea n octei a fiierului BYTE m_attribute - Atribute de citire, scriere etc. char m_szFullName - Numele fiierului i calea complet

3.16.6

Redenumirea i tergerea unui fiier

Exist dou funcii statice care au ca efect redenumirea i tergerea fiierelor: Rename() i Remove(). Rename() primete doi parametrii: vechiul nume al fiierului i viitorul nume al fiierului. Fiind o funcie static, nu este nevoie s se deschid un fiier, ci este suficient prefixarea apelului cu operatorul de domeniu ca mai jos: CFile::Rename(CFile:\\myFile.tit, CFile::\\newFile.tit); O funcie static este o funcie membru a unei clase C++ care nu are nevoie de un obiect context. Funcia Remove() este de asemenea o funcie static ce primete ca parametru numele fiierului se trebuie ters. CFile::Remove(c:\\myFile.tit); Pentru a se terge un fiier este necesar ca obiectul de tip CFile asociat acestuia(dac este cazul) s fie nchis, adic acestui obiect s i se apeleze pai nti funcia membru Close(). De exemplu pentru a nchide fiierul fis.tit de mai jos procedm astfel: CFile fis; fis.Open(fis.tit,CFile::modeCreate); . . . fis.Close() CFile::Remove(fis.tit); Ambele funcii genereaz o excepie dac eueaz dintr-un anumit motiv. 85

3.17

Elemente de grafic n Visual C++

Grafica pe calculator se ocup de sinteza pictural a unor obiecte imaginare sau reale pe baza unor modele construite cu ajutorul calculatorului. Un proverb chinez spune c O imagine valoreaz ct zece mii de cuvinte, i ntr-adevr o imagine poate fi oricnd o metod de a realiza o comunicare ntre dou persoane care nu cunosc o limb comun n care s converseze.

3.17.1

Noiunea de context dispozitiv

Un context dispozitiv reprezint suprafaa pe care se reprezint toate punctele, liniile, ptratele, fonturile, culorile i tot ceea ce se observ pe ecran. Cuvntul dispozitiv din context dispozitiv reprezint faptul c se poate desena pe ecran, la imprimant, la plotter, ntr-o casc pentru realitate virtual sau pe orice alt dispozitiv de desenare n dou dimensiuni. n esen, un context dispozitiv este o structur Windows care conine atribute ce descriu opiunile implicite de desenare folosite n orice operaie grafic, aa cum ar fi trasarea unei linii. Spre deosebire de toate celelalte structuri din Windows, un program nu va putea niciodat s acceseze structura unui context dispozitiv, el va putea ns s modifice opiunile acestei structuri prin intermediul unor funcii de acces standard. Microsoft a standardizat ntreg suportul de desenare i dispozitive n cadrul sistemului de operare Windows. Dac avem la dispoziie o imprimant model foarte recent, prin simpla instalare a driver-elor pentru aceast imprimant se poate lista din orice aplicaie, fr discriminare. Contextul dispozitiv este cel ce le unete i ofer ntreg suportul pentru desenare. Contextele dispozitiv efective sunt obiecte GDI(Graphics Device Interface interfa cu dispozitivele grafice). GDI reprezint o mulime de funcii ce se afl ntr-o bibliotec DLL n inima sistemului de operare. Aceste funcii fac legtura dintre apelurile funciilor de desenare pe care le efectum i driver-ele de dispozitiv care comunic cu dispozitivele hardware pentru a transforma totul n realitate, sub form de lumin sau cerneal.

3.17.2 Utilizarea clasei CDC


Clasele de context dispozitiv folosite n aplicaii au ntotdeauna clasa de baz CDC. Aceast clas conine doi indicatori legai de obiectul GDI aflat dedesubt: indicatorul m_hDC i indicatorul m_hAttribDC. m_hDC este indicatorul de context dispozitiv care face legtura dintre clas i obiectul GDI pentru a gestiona ieirile 86

funciilor de desenare. m_hAttribDC este indicatorul de context dispozitiv care leag toate informaiile de atribute, cum ar fi culori i modurile de desenare. Este bine de reinut faptul c la apelarea unor funcii ca GetDC() sau ReleaseDC() (care obin i respectiv elibereaz contextul dispozitiv pentru o fereastr) aceti indicatori GDI sunt ataai i detaai de clasa CDC.

3.17.3 Contextul dispozitiv client


Clasa CClientDC automatizeaz apelurile GetDC() i ReleaseDC(). La construirea unui obiect CClientDC se va transmite ca parametru un pointer la o fereastr, iar clasa va folosi apoi acest pointer pentru a accesa contextul dispozitiv al ferestrei respective. La distrugerea clasei, aceasta apeleaz automat ReleaseDC(), aa c nu ne va preocupa acest lucru. Termenul Client se refer la suprafaa normal de desenare a ferestrei, exist de asemenea o clas corespunztoare, CWindowDC, ce ne permite ce ne permite s accesm i bara de titlu i marginile ferestrei, dar aceasta se folosete rar deoarece mai toate aplicaiile moderne se rezum la a desena n propriile zone client. Clasa CClientDC reine indicatorul ctre fereastra asociat n variabila sa membru m_hWnd . Poate fi transmis indicatorul de fereastr m_hWnd(de tip HWND) funciei Attach() a unui obiect CWnd pentru a accesa funciile ferestrei asociate. Se propune n continuare s scriem o funcie simpl pe care o vom numi MyOnDraw() i care va avea scopul de a desena n colul din stnga, sus al ferestrei client, drapelul Romniei de dimensiune 300x300 pixeli. Se va presupune c avem deschis un proiect de tip DialogBased (acest lucru presupune crearea unui nou proiect de tip MFC AppWizard(exe) iar la primul pas se va valida opiunea DialogBased) al crui nume este Drapel. De asemenea se va merge n ferestrei spaiului de lucru a proiectului(vezi 2.3), n seciunea ClassView i se va face clic dreapta pe clasa CDrapelView iar din meniul contextual afiat va fi aleas opiunea Add Menber Variable. n caseta de dialog deschis, vei opta pentru tipul funciei ca fiind void iar numele l vei seta MyOnDraw(). Acionai apoi butonul OK i facei dublu clic pe numele funciei (OnDraw()) ce va aprea acum ca metod a clasei CDrapelView n seciunea ClassView a ferestrei spaiului de lucru a proiectului. Vei fi poziionat astfel automat pe definiia funciei MyOnDraw(). Funcia va fi: void CDrapelView:: MyOnDraw() { //TODO: Add your control notification handler code } ea va fi modificat astfel: void CDrapelView:: MyOnDraw() { 87

//TODO: Add your control notification handler code CClientDC cDC(this); for(int i=0;i<=300;i++) for(int j=0;j<=300;j++) { if (i<100) cDC->SetPixel(i, j, (255<<16)|(0<<8)|0); else if(i<200) cDC->SetPixel(i, j, (0<<16)|(255<<8)|255); else cDC->SetPixel(i, j, (0<<16)|(0<<8)|255) } } Prima linie introdus declar un obiect de tip CClientDC numit cDC i prin utilizarea pointer-ului this i atribuie acestuia CDC-ul ferestrei curente(al casetei de dialog ). La sfritul funciei nu se mai apeleaz ReleaseDC() deoarece am spus c acesta este apelat automat de destructorul obiectului de tip CClientDC. Cele dou for-uri imbricate parcurg pixel cu pixel zona ptrat bidimensional, ce va fi desenat. Dac avem o linie de pixeli ntre pixel-ul 0 i 100 vom desena pixelul n rou, dac aceasta are valoarea ntre 101 i 200 pixel-ul va lua culoarea galben, iar dac este ntre 201 i 300 vom desena un pixel albastru. Acesta este rolul cascadei de ifuri din cadrul funciei. Stabilirea valorii unui pixel se seteaz cu ajutorul funciei SetPixel() care va primi trei parametrii de tip LONG. Primii doi parametrii reprezint coordonatele pixelului (linia i coloana).Cel de-al treilea parametru reprezint valoarea culorii ce va fi afiat pentru acel pixel. Ecranul are un numr foarte mare de pixeli, numrul acestora este stabilit prin reglarea rezoluiei. Aceasta se face pe orice sistem de calcul ce folosete sistemul de operare Windows printr-un click dreapta pe desktop, selectnd apoi Properties din meniul contextual, i mergnd n seciunea Settings. Se va observa un glisor n caseta de grupare cu numele Screen Resolution, prin tragerea acestui glisor se poate stabili rezoluia ecranului. Aceasta este de obicei de 1024 / 768 sau 800 / 600. Caseta de dialog pe care vom desena va ocupa o poriune din pixelii ntregului ecran. Pixelul din stnga-sus al casetei de dialog va avea poziia (0,0) numrul liniei crescnd de sus n jos iar cel al coloanei de la stnga le dreapta. Exist trei culori complementare (rou, verde i albastru) iar pentru fiecare din aceste culori exist cte un tun de electroni n monitorul calculatorului. Prin trimiterea cu o anumit intensitate a electronilor corespunztori fiecreia din cele trei culori, spre un acelai punct de pe ecran(numit pixel (Picture element)) n acest punct se va crea impresia unei culori. De exemplu dac intensitatea cu care sunt trimii electronii este maxim pentru toate cele trei tunuri, atunci vom obine o culoare alb a pixel-ului respectiv, iar dac spre un pixel nu se trimit nici un fel de electroni, culoarea acestuia va fi neagr. Dac doar tunul pentru rou trimite electroni spre un pixel, culoarea acestuia va fi roie. Observm ce importan are intensitatea cu care sunt trimii electronii n formarea culorilor pe ecran. Astfel fiecrui pixel i se pun n coresponden trei variabile de tip int, asociate celor trei culori complementare i fiecare variabil poate lua o valoare ntre 0 i 255. Valorile acestor variabile reprezint intensitatea nuanei de rou, verde i respectiv de albastru pentru pixel-ul respectiv. Pentru a se economisi memorie, n locul a trei variabile de tip int se va asocia fiecrui pixel o singur variabil de tip LONG. Presupunnd c variabilele de tip int 88

asociate unui pixel sunt r,g,b pentru red(rou), green(verde) respectiv blue(albastru), valoarea variabilei de tip LONG (s-o notm rgb) ce se va ataa pixel-ului se va calcula ca mai jos: rgb = (((r) << 16) | ((g) << 8) | (b)) unde << este operatorul de deplasare la stnga pe bii, iar | este sau pe bii. Operaia invers se realizeaz astfel: r = ((rgb) >> 16) & 0xff
g = ((rgb) >> 8) & 0xff b = (rgb) & 0xff

unde >> e operatorul de deplasare la dreapta pe bii, iar & e i pe bii. 0xff n hexazecimal este 255 n zecimal.

3.17.4 Contexte dispozitiv de memorie


Un context dispozitiv de memorie este un context dispozitiv care nu are asociat nici un dispozitiv. Aceste contexte dispozitiv se folosesc de obicei mpreun cu un context dispozitiv obinuit pentru copierea i lipirea unor zone pe ecran. Este posibil crearea unui context dispozitiv de memorie compatibil cu un context dispozitiv de afiare. Apoi putei s copiai n memorie imaginile care nu mai sunt afiate, aducndule napoi n contextul dispozitiv de afiare atunci cnd este nevoie. Nu exist nici o clas MFC care s implementeze un context dispozitiv de memorie; aa ceva nu este necesar deoarece clasa CDC este foarte potrivit. Fiind vorba despre o clas context dispozitiv CDC o putei folosi pentru desenare ca de obicei, singura diferen este c vei desena n memorie iar utilizatorul nu va vedea nimic pn ce nu copiai rezultatele n contextul dispozitiv de afiare al unei ferestre. Se poate crea un context dispozitiv de memorie compatibil i s modifice codul de desenare pentru a lucra cu memoria i nu cu ecranul. Odat creat imaginea n memorie o putem copia pe ecran cu un apel al funciei BitBlt(). Pentru a crea o imagine n memorie trebuie s crem nu numai un context dispozitiv de memorie ci i un bitmap asociat acestuia. Spre deosebire de contextele dispozitiv de afiare, care sunt legate de ferestre, un context dispozitiv de memorie nu dispune automat de un bitmap compatibil cu ecranul. Un bitmap dintr-un context dispozitiv de memorie poate fi mult mai mic sau mult mai mare dect contextul dispozitiv de afiare asociat. Prin crearea unui bitmap mare putei obine o suprafa de desenare cu o rezoluie mult mai nalt dect a ecranului. Trebuie s reinei, ns, c un bitmap mai mare are nevoie de mai mult memorie de la sistem. n situaia n care bitmap-ul necesit mai mult dect memoria RAM existent , sistemul va fi ncetinit considerabil prin utilizarea memoriei virtuale n scopul compensrii lipsei de RAM. Memoria virtual este o zon de pe disc utilizat ca i memorie pentru a suplini memoria RAM. Memoria virtual este nceat deoarece segmente mari de memorie, numite pagini sunt schimbate permanent ntre RAM i disc. Se propune n continuare s rescriem funcia MyOnDraw() care a fost creat la punctul 2.7.1.2 al lucrrii, utiliznd un context dispozitiv de memorie: 89

void CDrapelView:: MyOnDraw() { //TODO: Add your control notification handler code CClientDC cDC(this); //Crem un context dispozitiv de memorie compatibil CDC memDC; memDC=CreateCompatibleDC(&cDC); //Determinm zona client CRect rc; GetClientRect(&rc); //Crem un bitmap compatibil CBitmap bmp; Bmp.CreateCompatibleBitmap(&cDC, rc.Width(), rc.Height()); //selectm bitmap-ul n cadrul contextului dispozitiv de memorie memDC.SelectObject(&bmp); //desenm for(int i=0;i<=300;i++) for(int j=0;j<=300;j++) { if (i<100) cDC->SetPixel(i, j, (255<<16)|(0<<8)|0); else if(i<200) cDC->SetPixel(i, j, (0<<16)|(255<<8)|255); else memDC->SetPixel(i, j, (0<<16)|(0<<8)|255) } //copiem memDC n cDC cDC.BitBlt(0,0,300,300,&memDC,0,0,SRCINVERT) } Este indicat utilizarea funciei BitBlt() n loc de o copiere direct, pixel cu pixel deoarece este cu mult mai rapid. Numele acestei funcii vine de la un termen hardware mai vechi, bit blitting, care se refer la un circuit capabil s copieze rapid o zon de memorie dintr-un loc n altul. n unele cazuri s-ar putea ca placa grafic s efectueze exact acest gen de copiere la apelul funciei dar n alte cazuri copierea va fi realizat de procesor. Funcia BitBlt() primete urmtorii opt parametrii: - linia din contextul dispozitiv de memorie ncepnd cu care se va face copierea, tipul este long - coloana din contextul dispozitiv de memorie ncepnd cu care se va face copierea, tipul este long - linia din contextul dispozitiv de memorie pn la care se va face copierea, tipul este long 90

coloana din contextul dispozitiv de memorie pn la care se va face copierea, tipul este long - un pointer la contextul dispozitiv de memorie. - Linia de la care ncepnd are loc crearea imaginii n contextul dispozitiv asociat echipamentului fizic. - Coloana de la care ncepnd are loc crearea imaginii n contextul dispozitiv asociat echipamentului fizic. - Un parametru ciudat SRCINVERT care ne specific faptul c imaginea va fi copiat inversnd culorile. n consecin imaginea din fereastra destinaie va avea un colorit diferit, ceea ce demonstreaz faptul c imaginea va fi copiat mai nti n memorie i abia apoi n contextul dispozitiv al casetei de dialog. Apelul funciei BitBlt() are loc ntotdeauna pentru un obiect de tip context dispozitiv.

3.17.5 Penie i pensule


Peniele reprezint unul dintre obiectele GDI(Graphics Device Interface) de baz.; ele sunt implementate chiar n inima sistemului Windows i practic se afl acolo de la bun nceput. nainte de a desena ceva trebuie s selectai sau s creai o peni potrivit pentru operaia vizat. Peniele sunt folosite pentru trasarea de linii i curbe. Atunci cnd desenai figuri pline, peniele sunt utilizare pentru trasarea conturului iar pensulele pentru colorarea interiorului. Sunt situaii cnd nu dorii s umplei figurile ci doar s trasai conturul. Aceste situaii se rezolv prin folosirea unei pensule transparente sau vide mpreun cu funciile de desenare ale figurii respective.

3.17.6 Utilizarea clasei CPen


MFC ofer o clas de ncapsulare CPen care simplific manipularea penielor(ca obiecte de desenare). Aceast clas conine obiectul GDI aflat la baz i se ocup de alocarea i eliberarea acestuia. Pentru crearea unei penie trebuie s declarai un obiect corespunztor i s transmitei nite parametrii de iniializare. Linia de cod de mai jos creeaz o peni continu de culoare roie. CPen penRed(PS_SOLID,3,RGB(255,0,0)); Parametrul PS_SOLID precizeaz tipul peniei. Este posibil crearea unei varieti de penie prin intermediul tipurilor disponibile. Tipurile disponibile pentru penie sunt: PS_SOLID PS_DASH PS_DOT PS_DASHDOT -linii continue -linii ntrerupte(segmentate) -linii ntrerupte(punctate) -linii ntrerupte(de tip linie-punct) 91

Grosimea sau limea peniei poate fi modificat prin intermediul celui de-al doilea parametru. Valoarea1 pentru acest parametru va avea ca rezultat o peni a crei lime este de 1 pixel (cea mai mic posibil). Se poate specifica ns o grosime mai mare pentru peni. Este bine de reinut c stilurile de penie cu linii ntrerupte se pot stabilii doar pentru penie ce au o grosime unitar(egal cu 1). Al treilea parametru care poate fi specificat la crearea unei penie este culoarea acesteia. Tipul acestui parametru va fi de tip COLORRREF, care nu este altceva dect un numr pe 32 de bii care reprezint o combinaie a componentelor de rou verde i albastru ce formeaz o culoare. Specificarea direct a valorilor pentru o variabil COLORREF este uneori greoaie motiv pentru care se va utiliza o macrodefiniie numit RGB care v vine n ajutor. Iat cum se utilizeaz n cod aceast macrodefiniie: COLORREF myrgb = RGB(255,0,255); CPen myPen(PS_DASH,1,myrgb); Dei codificarea culorilor pe 24 de bii (True Color) v permite s operai cu 16,7milioane de culori i nuane, culorile afiate efectiv depind de caracteristicile plcii grafice i ale monitorului. n cazul n care modul grafic curent suport mai puine culori, Windows va ncerca s compenseze prin crearea unei palete de culori care s reprezinte ct mai bine culorile afiate curent de sistem. Uneori va recurge la amestecarea a dou culori ntr-un model haurat de pixeli cu scopul de a produce pe baza culorilor disponibile un rezultat ct mai apropiat de culoarea dorit. Macrodefiniia RGB primete trei parametrii care reprezint intensitile nuanelor de rou, verde, respectiv albastru. Fiecare dintre cei trei parametrii poate lua valori ntre 0 i 255, unde valoarea 0 reprezint lipsa culorii respective, iar 255 reprezint intensitatea maxim a culorii respective. Nu este ntotdeauna necesar s specificai caracteristicile unei penie, deoarece Windows are disponibile cteva penie de stoc. Acestea sunt configurate deja cu parametrii implicii i sunt utilizate la desenarea suprafeei de lucru i a controalelor. Pentru a putea utiliza o astfel de peni vei declara un obiect de tip CPen dar nu vei transmite nici un parametru. Vei apela apoi CreateStockObject(), care va stabili caracteristicile penielor la cele ale obiectului din stoc specificat. Iat, de exemplu, cum putei alege din stoc penia neagr: CPen blackPen; BlackPen.CreateStockObject(BLACK_PEN); Stilul NULL_PEN ar putea prea puin ciudat, deoarece nu prea are sens s desenm o linie care practic nu se va vedea pe ecran, dar atunci cnd dorim s desenm o figur plin al crui contur nu este vizibil aceast peni vom vedea c ne este de real folos. Peniele de stoc sunt cele de mai jos: BLACK_PEN - traseaz linii negre WHITE_PEN - traseaz linii albe NULL_PEN - traseaz cu culoarea curent de fundal Pentru a putea s desenai cu peniele create este necesar ca acestea s fie selectate n cadrul contextului dispozitiv. Un context dispozitiv are un slot pentru penie 92

n care se poate afla o singur peni la un moment dat. Aceasta este penia cu care desenai. La selectarea unei noi penie n contextul dispozitiv, penia anterioar este eliberat. Pentru selectarea noii penie vom apela la o metod a contextului dispozitiv, anume la metoda SelectObject(). Selectarea unui obiect de tip peni se va face ca n exemplul de mai jos, care ncearc s deseneze un obiect rou i unul albastru. Funcia definit mai jos va putea fi apelat la apsarea unui buton, de exemplu, avnd ca efect desenarea celor dou obiecte pe contextul dispozitiv. void CDesenView::MyOnDraw() { CClientDC cDC(this); CPen redpen(PS_SOLID,3,RGB(255,0,0)); CPen *pOldPen=NULL; pOldPen=cDC->SelectObject(&redpen); // ..desenez obiectul rou CPen bluepen(PS_SOLID,3,RGB(0,0,255)); cDC->SelectObject(&bluepen); // ..desenez obiectul albastru cDC->SelectObject(pOldPen); } pOldPen este un pointer la un obiect de tip CPen i l-am utilizat pentru a pstra n el valoarea peniei iniiale pentru a putea reveni la aceasta dup terminarea desenrii obiectului. Metoda SelectObject() are proprietatea de a ntoarce un pointer la obiectul de tip CPen care era selectat nainte de apelul funciei. De aceea am setat valoarea lui pOldPen pe valoarea ntoars de SelectObject(). Pentru cel de-al doilea apel nu este necesar repetarea procedeului ci este chiar contraindicat deoarece funcia SelectObject()ar ntoarce de aceast dat un pointer la obiectul redpen deoarece acesta era selectat naintea apelului. Ultimul rnd de cod are rolul de a selecta din nou vechia peni pentru ca eventualele desenri ce vor mai avea loc s se realizeze cu aceasta. Odat ce nu mai avei nevoie de peniele ce le-ai creat, trebuie s le tergei. n acest fel este eliberat obiectul GDI aflat dedesubt i sunt disponibilizate resurse preioase ale sistemului. Clasa CPen se ocup automat de toate acestea la distrugerea sa, dar ai putea dori s efectuai explicit aceste operaii n cazul n care vrei s refolosii un obiect de tip CPen cu ali parametrii(apelnd CreatePen()).] Dei MFC ofer clase elegante care ncapsuleaz obiectele grafice, aa cum este CPen, obiectele propriu-zise sunt identificate prin indicatori care sunt variabile membru ale claselor MFC de ncapsulare. De fiecare dat cnd apelai o funcie SelectObject() 93

sau DeleteObject() a unui obiect context dispozitiv, un astfel de indicator ctre un obiect grafic este de fapt selectat sau ters la nivelul Win32. Funcia membru care distruge obiectul GDI aflat la baz este DeleteObject().Codul urmtor prezint un obiect peni care este creat, folosit, ters i apoi creat din nou. void MyDesenView::MyOnDraw() { CClientDC pDC(this); CPen penMainDraw(PS_DASH,1,RGB(128,255,255)); CPen *pOldPen = NULL; POldPen=pDC->SelectObject(&penMainDraw)); //Desenm cu penia segmentat pDC->SelectObject(pOldPen); penMainDraw.DeleteObject(); penMainDraw.CreatePen(PS_SOLID,5,RGB(200,20,5)) pOldPen=pDC->SelectObject(&penMainDraw); //Desenm cu penia continu pDC->SelectObject(pOldPen); } DeleteObject() este automat apelat atunci cnd penMainDraw este tears odat cu nchiderea funciei. Dac se apeleaz funcia DeleteObject() pentru o peni n timp ce aceasta este nc selectat ntr-un context dispozitiv, obiectul de tip GDI corespunztor va fi distrus i orice operaii de desenare ulterioare care implic respectiva peni pot duce la prbuirea aplicaiei sau la rezultate neateptate.

3.17.7 Trasarea de linii i figuri cu ajutorul penielor


Pentru a desena ceva cu ajutorul penielor avem nevoie de un context dispozitiv. Contextul dispozitiv ofer mecanismul pentru desenarea cu aceleai obiecte n cadrul unei ntregi mulimi de dispozitive, rezultatele obinute fiind identice. Fereastra dintr-o aplicaie SDI poate fi un suport ideal pentru tendinele dumneavoastr artistice. Prezint mai jos modul n care poate fi creat o aplicaie SDI care folosete o reprezentare simpl destinat desenrii. 1. Efectuai clic pe meniul File i selectai New. 2. Selectai pagina Projects. Din lista cu tipurile de proiecte alegei MFC AppWizard(exe). 3. Acum efectuai un clic n caseta Project Name i introducei numele proiectului. 4. Efectuai un clic pe OK. Va fi afiat caseta de dialog MFC AppWizard Step 1 94

5. Selectai Single Document i efectuai un clic pe Finish. n consecin, va fi creat infrastructura unei aplicaii SDI care va utiliza clasa de baz Cview pentru a deriva clasa reprezentare a noii aplicaii 6. Efectuai un clic pe OK n caseta de dialog New Project Information i AppWizard va crea noul proiect i fiierele sale surs. Un context dispozitiv pstreaz coordonatele unei poziii curente a peniei. La desenarea liniilor, acestea sunt trasate ntre poziia curent i poziia specificat, dup care poziia specificat devine noua poziie curent. Contextele dispozitiv dispun de o funcie membru , MoveTo() care stabilete aceast poziie curent. MoveTo() se apeleaz cu doi parametrii care specific poziia pe orizontal i pe vertical. Poziia curent poate fi determinat prin apelul funciei GetCurrentPosition() a contextului dispozitiv, aceasta ntorcnd poziia curent sub forma unui obiect CPoint. Obiectele de tip CPoint conin doi membri ntregi care specific numrul liniei i cel al coloanei i acetia sunt x i respectiv y.

3.17.8 Desenarea de linii


Contextele dispozitiv ofer o metod LineTo(), asemntoare metodei MoveTo(). Parametrii primii sunt aceeai i efectul este trasarea unei linii de la poziia curent la poziia specificat. Dup trasare poziia curent va deveni automat poziia indicat de parametrii funciei LineTo(). Vom folosi funcia OnDraw() a unui nou document de tipul SDI pentru a desena un triunghi pe ecran. Pentru aceasta vom modifica funcia OnDraw() n maniera urmtoare: void CMyDesenView::OnDraw(CDC * pDC) { CmyDesenDoc * pDoc = GetDocument(); ASSERT_VALID(pDoc); //TODO: add draw code for native data here //Crem o peni CPen penRed(PS_DOT, 1, RGB(255,0,0)); CPen *pOldPen = NULL; pOldPen= pDC->SelectObject(&penRed); pDC->MoveTo(50,100); // Desenm latura de baz pDC->LineTo(100,100); // Desenm prima latur lateral pDC->LineTo(75,50); // Desenm a doua latur lateral pDC->LineTo(50,100); //Selectm la loc penia iniial pDC->SelectObject(pOldPen); } 95

3.17.9 Desenarea de cercuri i elipse


Un cerc nu este dect o elips care n loc s fie nscris ntr-un dreptunghi este nscris ntr-un ptrat, deci pentru ambele figuri avem nevoie de aceeai funcie a contextului dispozitiv. Funcia Ellipse() are dou forme. Prima form primete un dreptunghi transmis ca obiect CRect. Cea de-a doua form necesit patru parametrii, reprezentnd coordonatele pe orizontal i pe vertical ale colului stnga sus i ale colului dreapta jos. Pentru a desena o elips se ca selecta n prealabil a peni i se poate scrie n cadrul funciei OnDraw() despre care am mai discutat, o secven de forma: // prelum dreptunghiul suprafeei contextului dispozitiv CRect rcClient; GetClientRect(&rcClient); //crem un dreptunghi n centrul dreptunghiului client de lungime i lime 0. CRect rcEllipse(rcClient.CenterPoint(), rcClient.CenterPoint()); //redimensionm dreptunghiul la o dimensiune de 10/10 rcEllipse.InflateRect(10,10); //desenm elipsa pDC->Ellipse(rcEllipse);

3.17.10 Desenarea de curbe


PolyBezier() este numele unei funcii care vine de la matematicianul Bzier, care a redus curbele la polinoame cubice. Polinomul descrie linia curb, iar faptul c este cubic nseamn c exist un punct de nceput, unul de sfrit i dou puncte de control nspre care este flexat curba prin interpolare. Particula Poly arat c este posibil trasarea mai multor curbe conectate ntre ele. Funcia primete un vector de obiecte CPoint(cel puin patru) i numrul de puncte din vector. Din cauza calculelor suplimentare care sunt necesare pentru trasarea liniilor curbe , timpul necesar este substanial mai mare dect n cazul liniilor drepte. Probabil c nu se remarca diferena de vitez dac nu se traseaz dect cteva curbe, dar aceasta poate deveni semnificativ dac aplicaia va trasa un numr mare de curbe. Urmtorul fragment de program deseneaz o curb bezier. CPoint pB[4]; pB[0].x=10; pB[0].y=10; 96

pB[1].x=5; pB[1].y=5; pB[2].x=10; pB[2].y=3; pB[3].x=50; pB[3].y=10; pDC->PolyBezier(pB,4); De asemenea Visual C++ ofer o funcie Polyline() pentru trasarea curbelor polinomiale, care primete aceeai parametrii ca i funcia PolyBezier().

3.17.11 Crearea pensulelor


Peniele sunt utile pentru trasarea contururilor de figuri, dar umplerea acestora cu culoare necesit o pensul. Majoritatea funciilor de desenare GDI folosesc att o peni ct i o pensul. Penia este necesar pentru trasarea conturului, iar pensula se folosete la desenarea interiorului figurilor. n acest fel avem posibilitatea de a alege o peni cu o anumit culoare i un anume stil i, respectiv, o pensul de alt culoare, desennd ntreaga figur ntr-un singur apel de funcie. Clasa MFC care ncapsuleaz obiectul GDI pensul este CBrush. O pensul poate fi o culoare plin, o haur sau poate s provin dintr-un bitmap sau dintr-un ablon. Exist deci constructori care primesc parametrii corespunztori acestor tipuri, fiind de asemenea posibil s crem un obiect neiniializat i abia dup aceea s apelm una din multiplele funcii de create disponibile. Clasa CBrush este o alt clas care ascunde un indicator HBRUSH ctre un obiect GDI. Acest indicator se poate determina i utiliza n mod direct prin aplicarea unei conversii (HBRUSH) asupra unui obiect CBrush. Pensula ce se creeaz cel mai uor este pensula de culoare uniform. Este suficient s declarai un obiect de tip CBrush i s transmitei ca unic parametru o referin de culoare pentru culoarea respectiv. CBrush brYellow(RGB(192,192,0)); n cazul pensulelor ce folosesc hauri se vor utiliza doi parametrii, unul pentru a indica haura i cel de-al doilea pentru culoare: CBrush brYellowHatch(HS_DIAGCROSS, RGB(192,192,0)); Avem la dispoziie urmtoarele tipuri de hauri: HS_CROSS - Caroiaj orizontal i vertical HS_DIAGCROSS - Caroiaj diagonal HS_HORIZONTAL - Linii orizontale HS_VERTICAL - Linii Verticale HS_BDIAGONAL - Linii oblice (dinspre stnga sus spre dreapta jos) HS_FDIAGONAL - Linii oblice (dinspre stnga jos spre dreapta sus) Pensulele pot fi folosite pentru a modifica fundalul unei ferestre prin tratarea mesajului WM_ERESEBKGND trimis de Windows. Pentru aceasta se procrdeaz astfel: 1. Se efectueaz clic dreapta pe clasa CView (n exemplul dat mai nainte va avea forma CMyDrawView) i va fi afiat un meniu contextual. 2. Se selecteaz opiunea Add Windows Message Handler 97

3. Se selecteaz WM_ERESEBKGND i se efectueaz clic pe butonul Add and Edit. 4. Se modifici funcia OnEraseBkgnd() ca mai jos. BOOL CmyDrawView::OnEraseBkgnd(CDC *pDC) { CBrush mybr(HS_DIAGCROSS, RGB(192,192,0)); CRect rc; GetClientRect(&rc); pDC->FillRect(rc, &mybr); return TRUE; }

3.17.12 Crearea pensulelor pe baz de abloane sau imagini


Posibilitatea de a crea pensule pe baza unor imagini este o facilitate destul de elegant oferit de Windows. n acest fel putei s acoperii zone de ecran cu imagini dispuse alturat. Pentru crearea unei resurse de tip imagine bitmap se va utiliza editorul de imagini prezentat la punctul 2.5.3 al lucrrii. Numele resursei de tip bitmap va fi dat de exemplu IDB_INVADER. Pentru a aplica o pensul de tip imagine vom modifica funcia OnEraseBkgnd() n maniera urmtoare: BOOL CmyDrawView::OnEraseBkgnd(CDC *pDC) { //declarm un bitmap CBitmap bmInv; //ncrcm resursa bitmap bmInv.LoadBitmap(IDB_INVADER); //crem o pensul pe baza bitmap-ului CBrush brInv(&bmInv); CRect rc; GetClientRect(&rc); pDC->FillRect(rc, &brInv); return TRUE; } Windows 95 nu poate folosi dect pensule de 8x8 pixeli, dar de la Windows NT nu avem astfel de limite.

98

3.17.13 Utilizarea pensulelor din stoc


Ca i n cazul penielor exist un set de pensule de stoc ce pot fi folosite n orice moment. BLACK_BRUSH - Pensul neagr WHITE_BRUSH - Pensul alb DKGRAY_BRUSH - Pensul gri nchis LTGRAY_BRUSH - Pensul gri deschis GRAY_BRUSH - Pensul gri NULL_BRUSH -Pensul transparent Pentru selectarea unei pensule se poate utiliza funcia SelectObject() a contextului dispozitiv. Aceasta funcioneaz ca i n cazul penielor i ntoarce un pointer la pensula selectat anterior. Este bine s se rein acest pointer ca i n cazul penielor pentru ca la sfrit s se selecteze pensula original. Asemenea penielor o pensul poate fi tears pentru a elibera resursa asociat, fiind posibil apoi utilizarea uneia dintre funciile Create n scopul crerii unei alte pensule. Funciile Create disponibile sunt urmtoarele: CreateSolidBrush(); CreateHatchBrush(); CreateBrushIndirect(); care primete un parametru LOGBRUSH CreatePatternBrush(); care primete un bitmap CreateSysColorBrush(); Toate acestea primesc parametrii identici cu funciile constructor corespunztoare

3.17.14 Desenarea de figuri umplute cu ajutorul pensulelor


O mulime de funcii de desenare genereaz figuri umplute cu ajutorul pensulelor. Pot fi desenate mai multe tipuri de poligoane, sectoare de cerc sau elips i dreptunghi.

3.17.15 Desenarea de dreptunghiuri i dreptunghiuri rotunjite


Figurile rectangulare pot fi desenate cu ajutorul funciilor Rectangle() i RoundRect(). Rectangle() primete parametrii identici cu Ellipse(), astfel primete un dreptunghi sau patru ntregi ce specific coordonate colurilor stnga-sus i dreapta-jos. Roundrect() necesit nc o pereche de coordonate primit fie ca obiect CPoint fie prin doi ntregi. Aceast pereche de coordonate precizeaz limea elipsei care este desenat n fiecare col al dreptunghiului. Ex. PDC->RoundRect(rcClient, CPoint(15,15)); 99

3.17.16 Desenarea de cercuri i elipse umplute


Funcia Ellipse() despre care am mai vorbit lucreaz la fel de bine i cu pensulele. Dac a fost selectat o pensul nul va fi mpiedecat generarea interiorului. De multe ori vei dori s desenai elipse avnd diametre i centru bine determinate. O soluie rapid este s creai un obiect CRect() folosind pe post de coordonate stnga-sus i dreapta-jos acelai obiect CPoint corespunztor centrului dorit. Ex: CRect rcEllipse(ptCentru, ptCentru); Apoi vei folosi funcia InflateRect() pentru a stabili diametrele elipsei i vei transmite dreptunghiul obinut n apelul funciei Ellipse().

3.17.17 Desenarea de poligoane


Funcia Polygon() primete acelai tip de parametrii ca i funciile Polyline() i PolyBezier(). Estenecesar o mulime de perechi de coordonate pentru fiecare punct, i de numrul acestor puncte.

100

4 LUCRRI DE LABORATOR
4
4.1 Lucrarea de laborator 1. 4.1.1 Sistemul de intrri/ieiri de baz din C++
n C++ ntre intrrile i ieirile fizice se interpun zone tampon organizate sub forma unor clase ierarhizate, aceste zone tampon se numesc streamuri. Spre deosebire de zonele tampon din C care erau doar nite locaii de memorie asupra crora acionau o serie de funcii n mod explicit sau implicit (printf, scanf) n C++ acestea au devenit clase, avnd asociate i doi operatori unul de inserie (<<) i altul de extracie (>>) care pot fi suprancrcai. n principiu sunt definite 4 streamuri standard: cin - pentru intrri standard de la Tastatur; cout pentru ieiri standard spre display (sau fereastr); cerr pentru ieiri standard de eroare spre display; clog ieirile de eroare sunt pstrate trec printr-o memorie tampon nainte de ajunge la display; n continuare se vor expune funcionarea streamurilor cin i cout. Biblioteca n care sunt descrise arhetipurile acestor streamuri i care trebuie ncarcat cu #include este <iostream.h>. Avantajul utilizrii streamurilor este folosirea direct fr specificri sau configurri speciale lundu-se n acest caz setrile implicite sau setri fcute anterior. Dei atunci cnd se va dori o anumit formatare se va apela la funcii i constante suplimentare spre deosebire de printf i scanf aceste formatari se vor pstra, astfel dac se dorete ca afirile de la un punct la alt punct al programului s se fac cu aceeai formatare se va specifica formatarea o singura data, apoi aceasta pstrndu-se. Pentru a afia nite variabile,constante, iruri de caractere pe ecran vom scrie: cout<<v1<<v2<<k1<<abcdefg<<a<<*; Se vor afia una dup alta fr spaii ntre ele valoare lui v1, a lui v2 a constantei k1, irul de caractere dintre ghilimele, caracterul a i *. Pentru a citi o variabil sau un ir de caractere vom scrie: 101

int a; char s[100]; cin>>a; cin>>s; sau cin>>a>>s; Se observ c sgeile indic ntotdeauna sensul de deplasare a informaiei la cout toate informaiile se deplaseaz dinspre variabile spre stream, pe cnd la cin dinspre stream spre variabile. Exerciiu 1: Citii trei valori float, calculai media lor i afiai-o.

4.1.2 Formatarea streamurilor


Formatarea afirilor i intrrilor se poate face cu o serie de indicatori de format i o serie de funcii prin care se activeaz aceti indicatori. Indicatorii de format sunt efectiv valori ntregi pe 16 bii. Aceste valori n format binar au doar un singur bit setat, permind astfel implementarea a 16 indicatori maxim pe acest principiu. Ca tip de date aceti indicatori sunt definii ca enumerare. Acetia sunt definii astfel: Enum{ skipws=0x0001, left=0x0002, right=0x0004, internal=0x0008, dec=0x0010, oct=0x0020, hex=0x0040,showbase=0x0080, showpoint=0x0100, uppercase=0x0200, showpos=0x0400, scientific=0x800,fixed=0x1000,unitbuf=0x2000 }; Pentru setarea acestor indicatori se folosete funcia setf(indicator), Pentru resetarea lor se folosete funcia unsetf(indicator). Pentru a seta indicatorul hex scriem: stream.setf (ios::hex); unde stream poate fi cin sau cout. Pentru a seta mai muli indicatori vom folosi urmtoare secven de cod: stream.setf(ios::ind1| ios::ind2 | ios::ind3 | . ios ::indn) ; Pentru a reseta indicatorii de format ai unui stream folosim aceleai expresii dar n loc de setf vom scrie unsetf. Semnificaiile indicatorilor de format: skipws la citirea unui ir de caractere nu ia n considerare spaiile goale (spaii i tabulatori); 102 membru

Exemplu: char s[100]; cin.setf(ios::skipws); cin>>s; cout<<s; left alineaz afiarea pe ecran la stnga; ( abc______) right alineaz afiarea pe ecran la dreapta;(______abc) internal alineaz semnul valorii la stnga;(-_____123) dec specific c streamul va lucra cu valori n baza 10; oct specific c streamul va lucra cu valori n baza 8; hex specific c streamul va lucra cu valori n baza 16; showbase specific c se va afia baza de numeraie n care se lucreaz ( 01234 pentru octal, 0xFFA9 pentru hexazecimal, fr nici o specificaie pentru zecimal); showpoint arat punctul zecimal pentru valori reale chiar i atunci cnd nu au zecimale diferite de zero (1234.0000) uppercase arat notaia bazelor cu liter mare i pentru baza 16 toate cifrele literare (a,b,c,d,e,f) vor fi scrise cu liter mare;(FFB9) showpos dispune n faa valorilor pozitive semnul +. ( +1234); scientific valorile reale vor fi afiate n notaie tiinific (1.234e+03); fixed valorile reale vor fi afiate n notaie cu virgul, opiune ce este implicit; unitbuf se golese memoria tampon asociat streamurilor dup fiecare operaie de ieire; Exerciiu 2. S se citeasc un numr ntreg n baza 16 i s se afieze valoare citit n baza 8. S se active afiarea simbolizrii bazei. Exerciiu 3. S se citeasc o valoare float i s se afieze fr punctul zecimal.(dac valoarea nu are zecimale), altdat s se afieze n notaie tiinific, i mai apoi n notaie fix. Alte funcii membre ale streamurilor: flags(), width(), precision(), fill() Pentru a citi sau a scrie valorile tuturor indicatorilor de formatare se va folosi funcia flags(). Exemplu: long a; a=flags(); // am citit toate valorile flags(a); // am suprascris toate valorile 103

Pentru a specifica lungimea minima a spaiului(cmpului) de afiare a unei variabile, ir de caractere sau constante se folosete funcia width() avnd prototipul: int width(int dimensiune_camp); Pentru a specifica precizia(numrul de zecimale) cu care va fi afiat un numr real se fa folosi funcia membru precision() avnd prototipul: int precision(int nr_de_zecimal); Pentru a specifica caracterul cu care se umple spaiile libere ale unui cmp cnd informaia efectiv afiat ocup mai puin dect lrgimea cmpului se folosete fill() avnd prototipul: char fill(char noul_caracter_de_umplere); // funcia va returna caracterul de umplere anterior Exerciiu 4. S se afieze pe cte un rnd valoare radicalului primelor 15 numere ncepnd cu 2. Valoarea va fi afiat cu 7 zecimale. Pe prima coloan se va afia numrul, pe cea dea doua radicalul su. Fiecare cmp va avea o lrgime de 20 de caractere iar valorile vor fi alineate la dreapta.(Ca n figura de mai jos.)(pentru radical se va include biblioteca math.h i din aceast bibliotec se va folosi funcia sqrt(), pentru linie nou se va folosi caracterul `\n`) Este setarea fcut cu funcia width() permanent?

4.1.3 Utilizarea manipulatorilor pentru formatarea ieirilor


Manipulatorii sunt o serie funcii speciale declarate n biblioteca IOMANIP.H. Acetia sunt : - dec, oct, hex pentru a specifica baza de numeraie a intrrilor i ieirilor; 104

setbase(int baza) stabilete baza valorilor numerice ce intr sau ies din stream; endl pentru un caracter de linie nou (echivalentul unui Enter din tastatur); ends scrie n stream un caracter null (0x00 sau `\0`); ws pentru streamuri de intrare emite spaiile libere introduse nainte de valoarea efectiv; flush golete un stream; resetiosflags(long f) dezactiveaz indicatorii specificai n f; setiosflags(long f) activeaz indicatorii specificai f; setprecision(int precizie) stabilete numrul de zecimale al valorilor cu virgul ; setfill(int ch) stabilete caracterul de umplere; setw(int w) stabilete lrgimea cmpului n care se va afia o valoare sau ir de caractere; Pentru a folosi un manipulator vom folosi expresia: cout<<manip1<<v1<<<<manip2<<manip3<<vk; cin>>manip1>>v1>>manip2>>;

Exerciiul 5. S se afieze pe cte un rnd,n cmpuri de 20 de caractere,alineate la dreapta, valoarea lui radical din 2, mai nti cu o zecimal i apoi crescnd cu unu numrul de zecimale. Vor fi afiate astfel zece rnduri. Se va da prioritate folosirii manipulatorilor mai sus prezentai.(Rezultatul programului va fi cel din figura de mai jos.)

Definirea propriilor manipulatori Se pot crea manipulatori proprii care sa acioneze asupra unor streamuri. Pentru a crea un manipulator se poate utiliza aceast structur general valabil: Pentru manipulatori folosii mpreun cu cout: 105

ostream & nume_manipulator_out (ostream & stream_de_lucru) { // se fac operatii cu streamul stream_de_lucru<<<<; stream_de_lucru.setf() ; stream_de_lucru.precision() ; stream_de_lucru<<endl<<ends; // aceste operatii sunt date ca exemplu putandu-se alege oricare // combinatie ce este utila return stream_de_lucru ;//aceasta comanda este absolut necesara // este ultima comanda din corpul functiei //de definire }

Pentru manipulatori folosii mpreun cu cin: istream & nume_manipulator_in (istream & stream_de_lucru) { // se fac operatii cu streamul stream_de_lucru>>>>; stream_de_lucru.setf() ; stream_de_lucru.precision() ; stream_de_lucru>>ws; // aceste operatii sunt date ca exemplu putandu-se alege oricare // combinatie ce este utila return stream_de_lucru ;//aceasta comanda este absolut necesara // este ultima comanda din corpul functiei //de definire } Pentru a folosi aceti manipulatori se va folosi secventa: cout<<<<nume_manipulator_out<<; cin<<<<nume_manipulator_in<<; Exerciiu 6 Creai un manipulator de ieire cu numele rand_nou, care atasat unui stream cout sa fac acelai lucru ca manipulatorul endl. Sau un manipulator da_un_bip 106

care atasat lui cout s scoat un sunet scurt de avertizare. (Se va folosi caracterul special \a). Exerciiu 7 Creai un manipulator de intrare cu numele cere_parola, care ataat unui stream cin s cear introducerea unui ir de caractere ce semnific parola. Dac parola este greit se va emite un sunet de avertizare folosindu-se manipulatorul da_un_bip creat mai nainte i se va repeta secvena de solicitare a parolei. Altfel se va confirma c parala este corect i se va ncheia programul.( Pentru compararea irului introdus cu parola dorit se va folosi funcia strcmp(sir1,sir2) din biblioteca string.h).

107

4.2 Lucrarea de laborator 2. 4.2.1 Crearea claselor i lucrul cu obiecte n C++


Organizarea programelor sub forma unor nlnuiri de clase reprezint urmtorul pas dup ce s-a deprins lucrul cu funciile i construcia structurilor de date. Pentru cine este obinuit cu acestea, definirea i lucrul cu clase li se va prea ca i cum ar avea o structur de date (struct) creia i s-au asociat o serie de funcii. Dar asemnrile din pcate se opresc aici, dei imaginea simplificatoare este n mare parte valabil. Odat cu avantajele utilizrii claselor apar i unele restricii. Funciile definite n clas (care poart numele de funcii membre ale clasei) au acces preferenial asupra datelor definite n interiorul clasei i uneori pot fi chiar singurele funcii ce au acces la aceste date. Pe de alt parte datele din clas sunt de cele mai multe ori inaccesibile din afar,doar funciile membre le pot citi i modifica. Important de reinut sunt avantajele pe care le aduce folosirea claselor : ncapsularea, Polimorfismul i Motenirea. ncapsularea nseamn c datele clasei nu sunt accesibile din afar ci mai ntotdeauna sunt accesate prin medierea funciilor membre.(nu nseamn c chiar nu se pot accesa datele ci doar c clasele au fost concepute s funcioneze astfel). Polimorfismul nseamn c putem defini o funcie de mai multe ori, astfel nct s accepte diferite combinaii de parametri i s realizeze aceeai sarcin folosind parametri diferii dar specificai.(funcia va avea acelai nume dar va diferi numrul i tipul parametrilor la fiecare declarare). Motenirea presupune c caracteristicile unei clase datele i funciile sunt puse la dispoziia sau mai degrab devin baza pe care se construiete alt clas. Astfel clasa nou creat clasa fiu va moteni elementele clasei tat. Se pot crea clase prin moteniri succesive, sau prin motenirea mai multor clase deodat. Clasa fiu va putea defini noi funcii i date n completarea celor motenite. Definirea unei clase se face astfel: class nume_clasa{ tip1 data1; tip2 data1[10]; tipn datan; specificator1: nume_clasa(); ~nume_clasa(); tip1 functie1(); specificator2: tip2 functie2(); tipn functien(): } [obiect1],[obiect2];

108

Aceasta este structura general de definire a unei clase. Se observ cuvntul cheie class de la nceput, acesta se va regsi n toate definiiile de clase. Specificator1n sunt specificatori de acces care stabilesc accesul la membrii clasei cei care se gsesc dup el fiind afectai, pn ce apare un nou specificator de acces. nume_clasa() este o funcie constructor a clasei, se apeleaz automat cnd se declar un obiect de clasa respectiv. ~nume_clasa() este o funcie destructor a clasei, se apeleaz cnd s-a terminat lucrul cu obiectul definit, pentru a elibera memoria. Tipk functiek() este o funcie membru al clasei. Dup ce s-a definit clasa trebuie definite i funciile membre. n general pentru a accesa orice membru al unei clase pentru definire se folosete operatorul de specificare a domeniului :: . Exemplu: tipk nume_clasa::functiek() { // scriem continutul functiei return tipk; } n definiia clasei observm c opional se pot defini variabile de tipul clas numite obiecte. Pentru a accesa membrii clasei atunci cnd avem declarat un obiect vom folosi operatorul de selecie . (punct) atunci cnd lucrm cu obiectul sau operatorul de selecie indirect -> (minus, mai mare) atunci cnd lucrm cu pointer spre obiect. Astfel: nume_clasa obiect1,obiect2,* obiect3; obiect1.functiek(); obiect2.functiek(); // dar obiect3->functiek(); Specificatorii de acces tipici sunt private (setat implicit pentru toi membrii unei clase), public i protected. Primii doi n special public sunt cei mai utilizai. Private interzice accesul oricrui nemembru al clasei. Public permite accesul oricui la membrii clasei. Protected specific c membrii declarai protected n clasa tat vor putea fi accesai n cazul unei moteniri fr specificatori de ctre clasa fiu. Pentru a avea acces fr protected la membrii clasei tat la motenire clasa tat va fi motenit de clasa fiu n mod public. Pentru a specifica c o nou clas motenete pe altele vom folosi structura: Class clasa_fiu:[specificator1] clasa_tata2,] { //noi elemente specifice clasa_fiu }; clasa_tata1[,[specificator 2]

109

Astfel o clasa_fiu poate moteni una sau mai multe clasa_tata, motenirea fiind filtrat prin specificatorii de acces ce preced clasa_tata motenit. (Este bine ca aceti specificatori s fie public - pentru ca accesul clasei fiu s fie permis la toi membrii clasei tat indiferent de specificatorii din aceasta clasa_tata, aceasta deoarece specificatorul implicit este private n cazul unei moteniri fr precizarea specificatorului). Exerciiu 1. Definii o clasa cu numele persoana, cu urmtoarele date, nume,adresa,vrst, cnp.Definii o funcie constructor i una destructor. Definii funciile spune_nume, spune_adresa, spune_varsta , spune_cnp care s citeasc de la tastatura datele respective. Definii alte funcii care sa returneze aceste date ,separat pentru fiecare dat n parte.(ex. da_nume(char * numecurent)). Apoi funcii de transfer a datelor de la un obiect la altul. (trans_nume(persoana *altpers)). Nu folosii deocamdat nici un specificator de acces. ncercai s modificai numele unei persoane prin accesarea direct a datei respective. Se poate?.Ce trebuie schimbat dac nu?. La fel ncercai s folosii o funcie membr a clasei fr a avea un specificator de acces n clas. Cum trebuie modificat programul pentru ca accesul la datele membre s fie interzis i accesul la funcii membre permis? ncercai s creai o clas prin motenirea clasei persoana , anume clasa angajat, care s aib suplimentar urmtoarele date: nume_firma,salariu_net, data_angajarii(de tip char n format zz-ll-aaaa). Creai i pentru aceasta clas funcii de citire a datelor noi, de returnare a datelor noi, de transfer de date. Facei motenirea fr precizarea unui specificator de acces. V este permis accesul direct la numele persoanei din clasa angajat ? Ce trebuie modificat ?(Avei dou variante) . Scriei o funcie extern claselor pentru a afia informaii despre angajat. Avei acces la membrii clasei? Pentru a rezolva problema n mod profesionist putei apela la funcii prietene. Citii rndurile de mai jos i rezolvai problema. Folosirea funciilor prietene. Avnd declarat deja o funcie, pentru a permite accesul la membrii unei clase o vom declara n interiorul clasei ca fiind funcie prieten cu specificatorul friend. Acesta va fi folosit astfel: class nume_clasa{ // declaram date membre // declaram functii membre friend tip_returnat functie_prietena(); // functia a devenit prietena a //clasei }; //se observa ca definitia functiei nu se schimba deloc tip_returnat functie_prietena() { }; 110

Astfel indiferent de ce specificatori de acces au membrii clasei, funcia prieten va avea acces nengrdit la toi membrii clasei. Se pot defini i clase prietene unei clase nu numai funcii prietene, cam n acelai mod. class nume_clasa{ // declaratii member friend class nume_clasa_prietena; } Astfel nume_clasa_prietena are acces la toi membrii nume_clasa, dar nume_clasa nu are acces neaprat la toi membrii clasei nume_clasa_prietena. Deci reciproca nu este valabil.(dect specificat n mod expres) Cnd lucrm cu pointeri la obiect, iar obiectului respectiv nu i s-a alocat memorie, va trebui ca nainte de folosire s folosim operatorul de alocare new, iar cnd nu mai lucrm cu obiectul operatorul delete. Ei au urmtoarea adresare: nume_obiect=new nume_clasa; delete nume_obiect; Putem folosi aceti operatori i cu alte tipuri dect clase. n loc de nume_obiect avnd nume_variabil i n loc de nume_clasa numele tipului. Cnd avem definii constructori apelarea acestora se va face n momentul alocrii,respectiv destructori la apelul operatorului delete. Pn acum nu s-a pus problema constructorilor i destructorilor cu parametri. Acetia sunt declarai i definii n modul n care sunt definite funciile desigur fr a returna un tip. n schimb la declararea obiectelor va trebui specificat ntre paranteze dup numele obiectului fiecare parametru specificat n prototip. nume_clasa obiect(p1,p2,p3); Pentru obiect alocate dinamic : obiect = new nume_clasa(p1,p2,p3); Exerciiu 2. Modificai programul anterior astfel nct obiectele definite s fie alocate dinamic. Pentru a ne referi strict la o instan a unui membru al clasei, adic acea declarat i folosit ntr-un obiect anume, pentru a avea acces la datele i funciile din memoria alocat acestuia vom folosi pointerul this (trad. acesta). Acesta returneaz adresa obiectului. Pentru a ne referi la un membru al clasei din interiorul unei funcii membru vom folosi apelare: 111

this->membru=; this->functie_membru(); =this->membru; Un alt element al programrii pe obiecte este utilizarea funciilor virtuale. Declararea virtual a unei funcii are utilitate n procesul de motenire (sau derivare). Astfel o funcie declarat virtual n clasa de baz este motenit ca virtual n clasele derivate. Cu toate c avem funcia definit n clasa de baz dac ea este redefinit n clasa derivat aceast funcie va face cnd va fi apelat ceea ce s-a precizat n clasa derivat i nu ceea ce fcea n clasa de baz. Deci faptul c o funcie este virtual permite suprascrierea ei n toate clasele ce vor rezulta prin derivarea clasei de baz (prin utilizarea aceluiai nume). Exemplu: class animal_inferior{ //caracteristici generale specifice oricarui animal inferior virtual void mod_de_deplasare() {cout<<Inoata!<<endl;} }; class peste:public animal_inferior{ //caracterisitici specifice // nu redeclaram functia pt ca este valabila afirmatia Inoata! }; class patruped:public animal_inferior{ void mod_de_deplasare(){cout<<Merge! <<endl;;} }; class pasare: public animal_inferior{ void mod_de_deplasare(){cout<<Zboara! <<endl;;} }; void main() { animal_inferior meduza; peste rechin; patruped elefant; pasare vultur; animal_inferior. mod_de_deplasare(); elefant. mod_de_deplasare(); rechin. mod_de_deplasare(); vultur. mod_de_deplasare(); } Programul va afia: Inoata! Merge! Inoata! Zboara! 112

Se observ c-n toate clasele mod_de_deplasare() a fost suprascris.

derivate

afar

de

peste

funcia

Exerciiu 3. Creai modificnd exemplul de mai sus o clas pinguin derivat din pasare, iar n aceast clas modificai funcia virtual astfel nct s afieze paseste si inoata. Declarai un obiect de tip pinguin i verificai dac funcia virtual a fost suprascris i programul funcioneaz corect.(De remarcat c n toate celelalte clase derivate funcia declarat virtual n clasa de baz nu mai trebuie precedat de virtual, acest atribut fiind subneles.) Obs. Se pare c programul nu funcioneaz. Problema apare pentru c la suprascrierea funciilor virtuale se suprascrie i specificatorul de acces, i pentru c nu este precizat este luat implicit private. Asta nseamn c accesul la funcia membru mod_de_deplasare nu v este permis. Rezolvai problema Dup ce ai rezolvat problema adugai un constructor clasei de baz i prin acesta transmitei un ir de caractere cu numele efectiv al speciei animalului pe care l pstrai ntr-un ir de caractere. Aceste nume l vei afia nainte de a spune cum se deplaseaz animalul fcnd o modificare n funciile virtuale din fiecare clas preferabil la aceeai apelare a cout. ( pentru copierea irului de caractere n alt ir folosii funcia strcpy(dest,sursa) din biblioteca string.h). Vei constata erori deoarece constructorii nu se motenesc n mod implicit. Chiar i derivarea trebuie din nou specificat pentru constructori n mod obligatoriu.(sintaxa este nume_clasa(char *numeanimal):clasa_baza(numeanimal){}; i redefinirea se face pentru fiecare clas derivat. ). Trebuie reinut c la rularea unui program mai nti sunt apelai n ordinea derivrii mai nti constructorul clasei de baza, apoi cei ai clasei derivate pe urm cei ai clasei derivate din aceasta .a.m.d., ultimul apelat fiind cel al clasei din care face parte obiectul. Pentru destructori aceeai regul numai c ordinea este inversat.

113

4.3 Lucrarea de laborator 3. 4.3.1 Visual C++6.0 MFC Desenarea i afiarea imaginilor
Utilizarea documentelor, a reprezentrilor i a cadrelor Pentru programatorul n VisualC++, biblioteca MFC ofer un sprijin substanial la generarea unei noi aplicaii prin intermediul AppWizard, care poate s creeze automat un meniu, o bar de instrumente, o bar de stare i alte componente, permind apoi personalizarea uoar a fiecrui element. Clasele create cu AppWizard lucreaz mpreun pentru a forma o structur omogen cunoscut sub numele de arhitectura Document/View. Conceptul fundamental al arhitecturii Document/View l reprezint separarea datelor propriu-zise de reprezentarea a ceea ce datele semnific pentru utilizator. Aceasta se realizeaz stocnd datele ntr-o clas (clasa document) i informaiile privind reprezentarea ntr-o alt clas (clasa vizualizare). Exist dou categorii de aplicaii Document/View: SDI (Single Document Interface) i MDI (Multiple Document Interface). Exerciiu 1. S se creeze o aplicaie de tip SDI cu AppWizard . Aplicaia pe care o vei dezvolta va afia un teanc de monede. Opiunile de meniu vor permite adugarea sau nlturarea unei monede din teanc. Datele, care reprezint de fapt numrul de monede, sunt reinute n clasa document, fiind accesate de clasa vizualizare n scopul afirii teancului sau de clasa cadru pentru actualizare. Dei este un exemplu simplu, el ofer o imagine asupra scopului fundamental al arhitecturii Document/View, i anume ncapsularea datelor. Prin ncapsulare, datele sunt stocate exclusiv n clasa document, fiind oferite funcii de acces care s permit clasei vizualizare sau clasei cadru s prezinte informaiile ctre utilizator, respectiv s permit actualizarea acestor informaii. Folosind opiunea AddMemberVariabile adugai o variabil protected cu numele m_nNrMonede clasei document a proiectului. O variabil protejat nu poate fi modificat dect prin intermediul funciilor membru ale clasei din care face parte sau ale unei clase derivate. Prevenind alterarea datelor documentului de ctre oricare alt clas, rmne un singur punct de modificare a unei variabile. Pentru a permite accesul la datele membre, clasa document trebuie s ofere funcii de acces sau de modificare a variabilelor membre. . Folosind opiunea AddMemberFunction adugai trei metode clasei document: - o metod int GetNr() care s returneze valoarea datei membre m_nNrMonede, 114

- dou metode void Inc() i void Dec() pentru incrementarea respectiv decrementarea valorii variabilei m_nNrMonede. Pentru ca reprezentarea s poat extrage date ale documentului, ea trebuie s fie mai nti capabil s acceseze obiectul document. Infrastructura MFC se ocup automat de acest aspect, adugnd n clasa reprezentare a aplicaiei metoda GetDocument. Clasa derivat din CView este responsabil de afiarea teancului de monede. Codul care se ocup efectiv de desenarea monedelor se afl n funcia OnDraw()a clasei respective. AppWizard creeaz un schelet al acestei funcii, care trebuie apoi completat: void CSDIView::OnDraw(){ //Obtinerea pointerului la document CSDIDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); //Salvarea pensulei curente CBrush* pOldBrush=pDC->GetCurrentBrush(); //Crearea unei noi pensule de culoare galbena CBrush br; br.CreateSolidBrush(RGB(255,255,0)); //Selectarea pensulei galbene in contextul dispozitiv pDC->SelectObject(&br); //Obtinerea numarului de monede de la document si //reprezentarea fiecarei monede prin doua elipse for(int i=0;i<pDoc->GetNr();i++){ int y=200-30*i; pDC->Ellipse(40,y,100,y-30); pDC->Ellipse(40,y-5,100,y-35); } //Restaurarea vechii pensule pDC->SelectObject(pOldBrush); } Exerciiu 2. Adugai dou opiuni de meniu Add i Rem pentru adugarea i eliminarea unei monede. Tratai aceste resurse de meniu n clasa CMainFrame:
void CMainFrame::OnAdd() { //Obinerea pointerului spre document CSDIDoc* pDoc=(CSDIDoc*)GetActiveDocument(); pDoc->Add(); //Actualizarea vizualizrii documentului pDoc->UpdateAllViews(NULL); } void CMainFrame::OnRem() {

115

//Obinerea pointerului spre document CSDIDoc* pDoc=(CSDIDoc*)GetActiveDocument(); pDoc->Rem(); //Actualizarea vizualizrii documentului pDoc->UpdateAllViews(NULL); }

Acum compilai i executai .

4.3.2 Desenarea i afiarea imaginilor dispozitiv

folosind

contexte de

Un context dispozitiv reprezint suprafaa pe care se deseneaz toate punctele, liniile, ptratele, fonturile, culorile. Cuvntul dispozitiv din context dispozitiv nseamn c se poate desena pe ecran, la imprimant, pe un plotter fr a cunoate prea multe detalii despre ce dispozitiv se folosete sau ce marc sau model este acesta. Exist un context dispozitiv standard brut, i exist contexte dispozitiv pentru situaii speciale i operaii particulare. MFC ofer ncapsulri ale contextelor dispozitiv care simplific interaciunea cu obiectele GDI aflate dedesubt. Clasa care ncapsuleaz contextul dispozitiv standard brut este CDC. Aceast clas conine un numr mare de funcii de desenare, de mapare de coordonate i de decupare pentru implementarea reprezentrilor grafice. Toate celelalte clase de context dispozitiv, mai specializate, sunt bazate pe aceast clas i o extind. Capacitatea clasei CDC de a se ataa i a desena ntr-un context dispozitiv poate fi ilustrat printr-un program simplu. Fiecare fereastr are asociat un context dispozitiv care acoper ntreaga fereastr; nu face excepie nici fereastra suprafeei de lucru, care se ntinde pe ntregul ecran. Aplicaia urmtoare acapareaz un context dispozitiv i l folosete pentru desenare. Exerciiu 3. Creai o aplicaie de tip SDI.Adugai un buton cu numele Draw resursei de meniu din cadrul proiectului. Cu ajutorul ClassWizard tratai mesajul generat de apsarea butonului, ntr-o funcie Draw() situat n clasa CSDIView.Completai corpul funciei cu urmtorul cod:
void CSDIView::OnDrawIt() {

116

lucru

//Obtinerea unui pointer la fereastra suprafatei de CWnd* pDeskTop=GetDesktopWindow();

//Obtinerea unui pointer la contextul dispozitiv al //acesteia CDC* pDC=pDeskTop->GetWindowDC(); for(int i=0;i<300;i++) for(int j=0;j<300;j++) //Desenarea fiecarui pixel cu o alta culoare pDC->SetPixel(i,j,i*j)); //Eliberarea contextului dispozitiv pDeskTop->ReleaseDC(pDC); }

4.3.3 Utilizarea contextelor dispozitiv client - CClientDC


Pentru a desena n contextul dispozitiv al ferestrei aplicaiei i nu n fereastra suprafeei de lucru se folosete un pointer pDC de tip CClientDC. Se va folosi proiectul creat la punctul anterior, modificndu-se corpul funciei Draw():
void CSDIView::Draw(){ // Construim un DC pentru fereastra client CClientDC pDC(this); for(int x=0;x<300;x++) for(int y=0;y<300;y++) pDC->SetPixel(x,y,x*y); }

4.3.4 Utilizarea contextelor dispozitiv de redesenare - CPaintDC


Clasa CPaintDC este o ncapsulare special de context dispozitiv care ajut la tartarea mesajului WM_PAINT transmis de Windows. Mesajul WM_PAINT este transmis unei ferestre atunci cnd suprafaa acesteia a fost descoperit parial sau total de o alt fereastr. n loc s se redeseneze ntreaga fereastr de fiecare dat cnd este descoperit o mic poriune, Windows transmite coordonatele unui dreptunghi care ncadreaz zona descoperit. Aceste informaii se pot folosi pentru a desena exclusiv 117

poriunea afectat, fr a mai irosi timp pentru a desea zone de ecran pe care utilizatorul oricum nu le poate vedea. Pentru a experimenta redesenarea se creeaz un nou proiect SDI i cu ajutorul AppWizard-ului se trateaz mesajul WM_PAINT n funcia OnPaint(). Se completeaz aceast funcie astfel:
void CSDIView::OnPaint(){ //Crearea unui context dispozitiv pentru desenare CPaintDC paintDC(this); //Crearea uni pointer spre dreptunghiul de redesenare RECT* pRect=&paintDC.m_ps.rcPaint; for(int x=pRect->left;x<pRect->right;x++) for(int y=pRect->top;y<pRect->bottom;y++) paintDC.SetPixel(x,y,x*y); }

Compilai i rulai aplicaia. La prima afiare a ferestrei este transmis un mesaj WM_PAINT pentru redesenarea ntregii suprafee. Pentru a vedea efectul mesajului de redesenare, acoperii fereastra aplicaiei cu o alt fereastr. Deplasai apoi aceast fereastr pn cnd nu se va mai suprapune peste fereastra aplicaiei. Se va observa c redesenarea se va face mai repede deoarece regiunea acoperit devine din ce n ce mai mic, fiind astfel necesare mai puine apeluri SetPixel.

4.3.5 Contexte dispozitiv de memorie - CDC


Un context dispozitiv de memorie este un context dispozitiv care nu are asociat nici un dispozitiv. Aceste contexte dispozitiv se folosesc de regul mpreun cu un context dispozitiv obinuit pentru copierea i lipirea unor zone de ecran. Este posibil crearea unui context dispozitiv de memorie compatibil cu un dispozitiv de afiare. Apoi se pot copia n memorie imaginile care nu mai sunt afiate, aducndu-le napoi n contextul dispozitiv de afiare atunci cnd este nevoie. Exerciiu 4.Creai o aplicaie de tip SDI. Adugai un buton cu numele Draw resursei de meniu din cadrul proiectului. Cu ajutorul ClassWizard tratai mesajul generat 118

de apsarea butonului ntr-o funcie Draw() situat n clasa CSDIView. Completai corpul funciei cu urmtorul cod:
void CDCDrawDlg::OnDrawIt(){ //Construim un DC client pentru fereastra dialog CClientDC clientDC(this); //Creem un context dispozitiv de memorie care s fie //compatibil cu un context dispozitiv de pe ecran CDC memDC; memDC.CreateCompatibleDC(&clienDC); //Determinm zona client CRect rcClient; GetClientRect(&rcClient); //Creem un bitmap compatibil cu atributele contextului //dispozitiv de pe ecran CBitmap memBitmap; memBitmap.CreateCompatibleBitmap(&ClientDC, rcClient.Width(),rcClient.Height()); //l selectm n cadrul contextului dispozitiv de memorie memDC.SelectObject(&memBitmap); //Parcurgem dreptunghiul de desenare pe orizontal for(int x=0; x<rcClient.Width(); x++) { // Parcurgem dreptunghiul de desenare pe vertical for(int y=0; y<rcClient.Height(); y++) { //Desenm fiecare pixel cu alt culoare; //desenarea are loc n memorie, n acest moment //nu se vede nimic memDC.SetPixel(x,y,x*y); } } //Copiem imaginea din memorie napoi n contextul //dispozitiv client; ntreaga imagine este copiat acum pe //ecran, devenind vizibil utilizatorului clientDC.BitBlt(0,0, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY);

119

} }

Compilai i executai .

120

4.4 Lucrarea de laborator 4.


Visual C++ 6.0 MFC Bare de control. Dialoguri comune. Foi de proprieti.

4.4.1 Bare de control


Barele de control sunt elemente de interfa cu utilizatorul, folosite pentru a conine alte controale sau alte ferestre. Exist trei categorii de bare de control: Barele de stare - reprezint cel mai simplu tip de bare de control. Barele de control sunt n permanen afiate n partea de jos a unei ferestre cadru. Bare de instrumente - conin butoane folosite drept comenzi rapide de meniu. Bare de dialog - conin butoane i alte categorii de controale, cum ar fi casetele combinate, casetele list sau controalele de desfurare.

4.4.2 Bare de stare


Barele de stare sunt un element standard al interfeei cu utilizatorul. O bar de stare este o bar de control aflat n partea de jos a cadrului unei aplicaii. Barele de stare sunt, de obicei, divizate n mai multe panouri, cunoscute i sub numele de indicatori. De exemplu, aplicaiile create cu AppWizard are panouri destinate afirii strii tastelor Num Lock i Caps Lock. ntr-un program MFC, toate barele de control aparin ferestrei principale. Clasa cadru principal, CMainFrame, conine un obiect CStatusBar denumit m_wndStatusBar care este creat i iniializat n funcia CMainFrame::OnCreate(). if(!m_wndStatusBar.Create(this)|| !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0(Nu s-a reusit crearea unei bare de stare \n) } return 1;

nainte de a crea o bar de stare, trebuie creat o matrice de identificatori de resurs, folosii pentru fiecare panou al barei de stare. Aceast matrice de identificatori este transmis ca parametru funciei SetIndicators(). Identificatorii se folosesc pentru a identifica fiecare panou al barei de stare i irul text prestabilit pentru fiecare panou n parte. Este necesar atribuirea unei resurse ir prestabilite pentru fiecare panou adugat barei de stare. Proprietile unui panou din bara de stare se stabilesc apelnd funcia SetPaneInfo. m_wndStatusbar.SetPaneInfo(4, SBPS_POPOUT, 80); 121 ID_INDICATOR_TIME,

Funcia SetPaneInfo primete ca parametrii: indexul panoului, identificatorul panoului, stilul panoului i limea acestuia. Stilurile de panou disponibile sunt: SBPS_STRECH - arat c acel panou se poate extinde pentru a acoperi spaiul nefolosit. Un singur panou dintr-o bar de stare poate avea acest atribut, App Wizard atribuindu-l primului panou. SBPS_NOBORDER - arat c nu se va desena nici o margine tridimensional n jurul panoului. SBPS_POPOUT - indic trasarea unei margini inverse. SBPS_NORMAL - creeaz o bar de stare fr extindere, margini sau efecte de ieire n relief. SBPS_DISABLED - indic faptul c nu va scrie nici un text.

Un exemplu de bar de stare l reprezint adugarea unui nou panou care s indice ora curent. - Adugarea unui nou panou implic urmtoarele operaii; - Adugarea unui identificator n matricea de identificator; - Adugarea unui articol de text prestabilit n tabelul de iruri; - Adugarea unui instrument de actualizare a comenzii pentru panoul respectiv.

4.4.3 Adugarea unui identificator nou


Exerciiu 1. Pentru a defini un nou simbol de resurs, selectai caseta de dialog Resource Symbols din meniul View. Apsai butonul New i introducei numele unui nou simbol ca fiind ID_INDICATOR_TIME.
n fiierul surs MainFrame.cpp se afl un vector UINT utilizat pentru a defini aspectul barei de stare. Modificai vectorul indicators astfel nct s arate ca n listingul urmtor:

static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, ID_INDICATOR_TIME }; Pentru a aduga o resurs tabel de iruri folosind simbolul ID_INDICATOR_TIME se procedeaz astfel: - n eticheta Resource View din fereastra Project Workspace deschidei resursa String Table; - inserai un nou articol n tabela de iruri cu valoarea ID_INDICATOR_TIME drept identificator.

4.4.4 Definirea cronometrului i a stilurilor de panouri


122

Proprietile unui panou din bara de stare se stabilesc apelnd funcia SetPaneInfo . m_wndStatusBar.SetPaneInfo(4 , ID_INDICATOR_TIME , SBPS_POPOUT , 80); Funcia SetPaneInfo are patru parametrii: indexul panoului, indentificatorul panoului, stilul panoului i limea acestuia. Stilurile de panou disponibile sunt: - SBPS_STRECH - permite extinderea panoului pentru a acoperi spaiul nefolosit; - SBPS_NOBORDER - arat c nu se va desena nici o margine tridimensional n jurul panoului; - SBPS_POPOUT - indic trasarea unei margini inverse; - SBPS_NOMAL - creeaz o bar de stare fr extindere, margini sau efecte de ieire n relief; - SBPS_DISABLED - indic faptul c nu va fi scris nici un text. Definii un stil pentru noul articol din bara de stare i iniializai un cronometru pentru fiecare secund n funcia CMainFrame::OnCreate . m_wndStatusBar.SetPaneInfo(4 , ID_INDICATOR_TIME , SBPS_POPOUT , 80); SetTimer(1,1000,NULL); Tratarea resursei de ceas Utiliznd Class Wizard, adugai o funcie de tratare a mesajelor pentru WM_TIMER n clasa CmainFrame. Aceast funcie este apelat atunci cnd ceasul setat cu ajutorul funciei SetTimer expir. void CMainFrame::OnTimer(UINT nIDEvent) { m_wndStatusBar.InvalidateRect(NULL); } Atunci cnd timpul expir, panoul principal va invalida dreptunghiul barei de state, determinnd redesenarea acesteia. Cnd bara de stare este invalidat, panoul MFC actualizeaz fiecare panou folosind un instrument CCmdUI. Dei se poate folosi ClassWizard pentru a crea asemenea instrumente pentru majoritatea obiectelor de interfa cu utilizatorul, instrumentele pentru manevrarea panourilor unei bare de stare trebuie create manual. Adugai o declaraie pentru funcia de actualizare CCmdUI n declaraia clasei CMainFrame. Este necesar adugarea unei singure linii de cod, i anume declaraia pentru OnUpdateTimer: protected: //{{AFX_MSG(CMainFrame) 123

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnTimer(UINT nIDEvent); //}}AFX_MSG afx_msg void OnUpdateTimer(CCmdUI* pCmdUI); DECLARE_MESSAGE_MAP() n continuare, adugai intrarea n harta de mesaje din MainFrame.cpp, dup cum urmeaz: BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_TIMER() //}}AFX_MSG_MAP ON_UPDATE_COMMAND_UI(ID_INDICATOR_TIME, OnUpdateTimer) END_MESSAGE_MAP() Adugai funcia OnUpdateTimer n fiierul MainFrame.cpp: void CMainFrame::OnUpdateTimer(CCmdUI* pCmdUI){ //Activarea panoului pCmdUI->Enable(); //Obtinerea orei curente CTime theTime=CTime::GetCurrentTime(); CString szTime=theTime.Format("%I:%M:%S %p"); //Completarea panoului cu ora curenta pCmdUI->SetText(szTime); } Compilai i executai exemplul creat. Acum, bara de stare are un nou panou, situat la extremitatea dreapt, care conine ora curent.

4.4.5 Crearea unei bare de dialog - CDialog


Barele de dialog sunt asemntoare casetelor de dialog nemodale, cu deosebire c pot fi fixate pe panoul principal sau pot fi flotante n spaiul de lucru Windows. Aceast proprietate le face s semene cu barele de instrumente, dar pe deasupra mai pot conine orice tip de control. Spre deosebire de clasa CDialog , aici nu este nevoie de derivarea unei clase din CDialogBar. Mesajele primite de la controalele din bara de dialog sunt direcionate ctre posesorul barei CMainFrame. Deoarece Class Wizard nu gestioneaz aceste hri de mesaje, operaiunea trebuie efectuat manual. Crearea unei resurse caset de dialog

124

Exerciiu 2. Utiliznd editorul de casete de dialog Developer Studio, creai o nou resurs caset de dialog, folosind ca identificator IDD_BAR. Adugai la caseta de dialog un buton cu identificatorul IDC_BAR_HELP. Noul obiect CDialogbar este o variabil membru a clasei CMainFrame. Pentru aceasta completai declaraia clasei astfel: CDialogBar m_dlgBar;

4.4.6 Crearea unei bare de dialog ancorabile


Pentru a pregti o bar de dialog n vederea fixrii, este necesar un apel la funcia CControlBar::EnableDocking(). Unicul parametru al funciei EnableDocking specific modul de aliniere al barei. Acesta poate avea una din valorile: - CBRS_ALIGN_TOP - permite fixarea pe marginea de sus a zonei client. - CBRS_ALIGN_BOTTOM - permite fixarea pe marginea de jos a zonei client. - CBRS_ALIGN_LEFT - permite fixarea pe marginea stng a zonei client. - CBRS_ALIGN_RYGHT - permite fixarea pe marginea dreapt a zonei client. - CBRS_ALIGN_ANY - permite fixarea pe orice margine a zonei client. - CBRS_SIZE_DYNAMIC - arat c bara este dinamic. - CBRS_FLOATING - arat c bara este flotant. - CBRS_SIYE_FIXED - arat c bara este fix. - CBRS_SIYE_INPLACE - arat c bara nu este afiat utilizatorului. - CBRS_FLOAT_MULTI - permite ancorarea mai multor bare de instrumente n acelai rnd al ferestrei panou. Cnd este creat o bar de dialog ancorabil, titlul ferestrei trebuie setat folosind funcia SetWindowtext. Aceasta pstreaz titlul barei de dialog atunci cnd bara este deplasat n afara ferestrei cadru. Bara de dialog este creat i iniializat n funcia CMainFrame::OnCreate. m_dlgBar.Create(this, IDD_BAR,CBRS_TOP,IDD_BAR); m_dlgBar.SetWindowText("Bara de dialog"); m_dlgBar.EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_dlgBar); Deoarece mesajele provenite de la controalele situate ntr-o bar de dialog sunt direcionate ctre printele barei de dialog, iar hrile de mesaje nu sunt gestionate de Class Wizard, trebuie completat harta de mesaje din MainFrame.h, prin adugarea liniei: afx_msg void OnBarHelp(); i cea din MainFrame.cpp cu linia urmtoare: ON_BN_CLICKED(IDC_BAR_HELP, OnBarHelp) 125

n clasa CMainFrame se adaug o funcie OnBarHelp de tratare a mesajului IDC_BAR_HELP. void CMainFrame::OnBarHelp() { AfxMessageBox("Heeeelp!!!"); } Compilai i executai proiectul. Observai faptul c bara poate fi deplasat pe suprafaa de lucru sau alipit ferestrei cadru a aplicaiei.

4.4.7 Bare de instrumente - CToolBar


Barele de instrumente conin butoane care se folosesc pentru a transmite comenzi unei aplicaii. De obicei, aceste a sunt folosite pentru a asigura un acces rapid i simplu la comenzi care mai pot fi apelate i prin intermediul unor poriuni de meniu. Barele de instrumente sunt asemntoare barelor de dialog, cu deosebirea c acestea conin numai butoane. Ca i n cazul barelor de dialog, acestea pot fi ancorate de un cadru sau pot fi flotante. Utiliznd editorul de resurse, creai o nou resurs toolbar cu identificatorul IDR_TOOLBAR. Adugai n header-ul clasei CMainFrame o variabil membru protected de tip pointer la clasa CToolBar: protected: CToolBar * m_pColorToolbar; iar n implementarea clasei CMainFrame completai constructorul astfel: CMainFrame::CMainFrame():m_pColorToolbar(0){} Adugai un element de meniu ColorToolbar la apelul cruia bara de instrument devine vizibil/invizibil. Tratai mesajul generat de apsarea butonului n clasa CMainFrame. void CMainFrame::OnViewColorsbar() { if (0 == m_pColorToolbar) { m_pColorToolbar = new CToolBar; if (0 == m_pColorToolbar->Create(this)) { return; } if (0 == m_pColorToolbar>LoadToolBar(IDR_TOOLBAR1)) { return; } m_pColorToolbar>EnableDocking(CBRS_ALIGN_ANY); DockControlBar(m_pColorToolbar); } 126

else // Daca bara este vizibila se ascunde if(m_pColorToolbar->IsWindowVisible() == TRUE) ShowControlBar(m_pColorToolbar, FALSE, FALSE); else // Daca bara este invizibila se afiseaza ShowControlBar(m_pColorToolbar, FALSE); } Pentru a distruge pointerul la clasa CToolBar tratai mesajul WM_DESTROY folosind Class Wizard void CMainFrame::OnDestroy() { CFrameWnd::OnDestroy(); if (0 != m_pColorToolbar) { delete m_pColorToolbar; m_pColorToolbar = 0; } } Adugai butoane barei de instrumente i tratai-le corespunztor. TRUE,

4.4.8 Dialoguri comune CCommunDialog


Din aceasta categorie fac parte CFileDialog, CFontDialog, CColorDialog, CPageSetupDialog, CPrintDialog, CFindReplaceDialog,COleDialog. Operaii ca atribuirea de denumiri fiierelor, selectarea culorilor i fonturilor sunt att de uzuale, nct Microsoft a decis s integreze n Windows 98 casete de dialog pentru a le realiza. n consecin, aceste casete de dialog se numesc casete de dialog comune. Exemplul urmtor prezint metodele de programare pentru casetele de dialog comune n contextul unei aplicaii complete. Cu ajutorul AppWizard-ului creai o aplicaie SDI, Dialog. Adugai un articol de meniu numit Dialogs cu patru sub-articole: Open File Dialog, Save File Dialog, Font Dialog i Color Dialog. Toate casetele de dialog ale aplicaiei sunt controlate n clasa afiare. Adugai funcii de tratare a mesajelor la selectarea unei comenzi din meniul Dialogs: void CDialogView::OnDialogsOpenfiledialog() { // Creaz o matrice de filtre pentru fiiere char filters[] = "Test Files (*.tst)|*.tst|All Files (*.*)|*.*|"; //Creaz un obiect CFileDialog care reprezint caseta de //dialog Open File CFileDialog fileDlg(TRUE, NULL, "*.tst",NULL, filters, NULL); 127

//Afieaz caseta de dialog pentru utilizator int result = fileDlg.DoModal(); if (result == IDOK) { //Extrage fiierul cu denumirea selectat m_openFileName = fileDlg.GetFileName(); //Foreaz refacerea ferestrei Invalidate(); } } void CDialogView::OnDialogsSavefiledialog() { //Creaz un obiect ir pentru nregistrarea denumirii //fiierului curent CString fileName; //Creaz o matrice de iruri pentru filtrele de fiiere char filters[] = "Test Files (*.tst)|*.tst|All Files (*.*)|*.*|"; //Stabilete dac trebuie folosit denumirea prestabilit sau //cea a fiierului selectat if (m_saveFileName == "NO FILE NAME SELECTED") fileName = "default.tst"; else fileName = m_saveFileName; //Creaz un obiect CFileDialog care reprezint caseta de //dialog Save File CFileDialog fileDlg(FALSE, "*.tst", fileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,filters, NULL); //Afieaz caseta de dialog pentru utilizator int result = fileDlg.DoModal(); if (result == IDOK) { //Extrage fiierul cu denumirea selectat m_saveFileName = fileDlg.GetFileName(); Invalidate(); } } void CDialogView::OnDialogsFontdialog() { // Creaz un obiect CFontDialog care reprezint caseta de //dialog Font CFontDialog fontDialog(&m_logFont); int result = fontDialog.DoModal(); if (result == IDOK) { //terge vechiul font i creaz fontul selectat delete m_pFont; m_pFont = new CFont; m_pFont->CreateFontIndirect(&m_logFont); 128

Invalidate(); } } void CDialogView::OnDialogsColordialog() { CColorDialog colorDialog(m_color); int result = colorDialog.DoModal(); if (result == IDOK) { //Extrage culoarea selectat m_color = colorDialog.GetColor(); Invalidate(); } } Toate funciile care afieaz casete de dialog comune apeleaz funcia Invalidate(), care impune programului refacerea ferestrei cu noile valori selectate de utilizator. Funcia OnDraw() a clasei afiare rspunde de operaiile de refacere. Completai funcia cu urmtorul cod: //Afieaz denumirile fiierelor selectate pDC->TextOut(20, 20, m_openFileName); pDC->TextOut(20, 40, m_saveFileName); //Selecteaz fontul n contextul de dispozitiv CString fontName = m_logFont.lfFaceName; CFont* oldFont = (CFont*)pDC->SelectObject(m_pFont); //Afieaz un text cu fontul selectat pDC->TextOut(20, 60, fontName); //Reface fontul iniial n contextul de dispozitiv pDC->SelectObject(oldFont); //Creaz un obiect CBrush din culoarea selectat CBrush brush(m_color); //Selecteaz noua pensul n contextul de dispozitiv CBrush* oldBrush =(CBrush*)pDC->SelectObject(&brush); //Deseneaz un dreptunghi cu culoarea selectat pDC->Rectangle(20, 150, 120, 250); //Reface pensula iniial n contextul de dispozitiv pDC->SelectObject(oldBrush); Completai constructorul i destructorul clasei afiare: CDialogView::CDialogView(){ m_openFileName = "NO FILE NAME SELECTED"; m_saveFileName = "NO FILE NAME SELECTED"; m_logFont.lfHeight = 48; m_logFont.lfWidth = 0; m_logFont.lfEscapement = 0; m_logFont.lfOrientation = 0; 129

m_logFont.lfWeight = FW_NORMAL; m_logFont.lfItalic = 0; m_logFont.lfUnderline = 0; m_logFont.lfStrikeOut = 0; m_logFont.lfCharSet = 16; m_logFont.lfOutPrecision = OUT_DEFAULT_PRECIS; m_logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; m_logFont.lfQuality = PROOF_QUALITY; m_logFont.lfPitchAndFamily = VARIABLE_PITCH FF_ROMAN; strcpy(m_logFont.lfFaceName, "Times New Roman"); m_pFont = new CFont; m_pFont->CreateFontIndirect(&m_logFont); m_color = RGB(255,0,0); } CDialogView::~CDialogView(){ delete m_pFont; } Completai header-ul clasei afiare cu variabilele membre folosite: CFindReplaceDialog* m_pFindDialog; COLORREF m_color; LOGFONT m_logFont; CFont* m_pFont; CString m_saveFileName; CString m_openFileName;

4.4.9 Foi de proprieti - CPropertyPage


Foile de proprieti sunt un tip deosebit de caset de dialog, folosite pentru organizarea mai multor opiuni. O foaie de proprieti ordoneaz opiunile n serii de pagini cu etichete, fiecare pagin (denumit pagin de proprieti) coninnd un set de atribute corelate. Orice pagin din foaia de proprieti este la rndul su o caset de dialog asociat cu clasa MFC CPropertyPage. Foaia de proprieti este, la rndul ei, un obiect al clasei CPropertySheet.
Exerciiu 3. Creai o aplicaie SDI, Property. Adugai dou resurse casete de dialog: una numit Text Options i una Color Options. n pagina cu eticheta Style selectai Child n caseta Style, Thin n caseta Border i dezactivai opiunea System Menu. Acestea sunt stilurile de fereastr cerute de o pagin de proprieti. Configurai casetele de dialog astfel: 1. n caseta de dialog Text Options adugai trei controale tip validare, creai o nou clas pentru caseta de dialog, derivat din clasa de baz CPropertyPage i trei variabile membre de tip BOOL . Procedai similar i cu caseta Color Options

130

adugnd trei controale de editare pentru valorile RGB i asociai-le variabile membre ntregi. 2. Creai o clas foaie de proprieti, CMyPropertySheet derivat din clasa de baz CPropertySheet. 3. Acum, dup definirea resurselor foii de proprieti i dup derivarea claselor paginilor i foii de proprieti din CPropertyPage i CPropertySheet, vei scrie codul surs pentru afiarea i utilizarea foii de proprieti: 3.1.Includei fiierele antet ale paginilor de proprieti n clasa foii de proprieti: #include "TextOptionsPage.h" #include "ColorOptionsPage.h" 3.2. Creai obiectele pagin de proprieti ca variabile membru ale clasei foaie de proprieti: CColorOptionsPage m_colorPage; CTextOptionsPage m_textPage; 3.3. Pentru a v permite s adugai pagini de proprieti, clasa CPropertySheet folosete funcia membru AddPage(). Adugai paginile de proprieti n foaia de proprieti (n constructor): AddPage(&m_textPage); AddPage(&m_colorPage); 3.4. n continuare va trebui s includei header-ul clasei foii de proprieti n fiierul surs care afieaz foaia de proprieti. Adesea, ntr-o aplicaie generat cu AppWizard, aceasta este clasa afiare. #include "MyPropertySheet.h" 3.5. Metoda de afiare a foii de proprieti nu difer de cea a casetelor de dialog. Se definete obiectul foaie de proprieti i se apeleaz funcia membru DoModal(): CMyPropertySheet propertySheet("My Property Sheet"); int result = propertySheet.DoModal(); Cnd creeaz foaia de proprieti, constructorul cere un argument, care este titlul ce trebuie s apar pe bara de titlu a foii de proprieti. Transferul de valori dintre program i foaia de proprieti funcioneaz la fel ca n cazul casetelor de dialog. Pentru a introduce date n controalele foii de proprieti naintea afirii ei, trebuie s iniializai variabilele membru ale claselor paginilor de proprieti. Pentru aceasta adugai clasei afiare trei variabile ntregi i trei de tip bool i iniializai-le corespunztor. n sens invers putei extrage informaii din paginile de proprieti copiind valorile variabilelor membre ale paginilor de proprieti n variabilele definite anterior. 131

Adugai un articol de meniu Test cu sub-articolul PropertySheet i funcia de tratare a mesajului: void CPropertyView::OnTestPropertysheet() { // TODO: Add your command handler code here CMyPropertySheet propertySheet("My Property Sheet"); propertySheet.m_textPage.m_check1 = m_check1; propertySheet.m_textPage.m_check2 = m_check2; propertySheet.m_textPage.m_check3 = m_check3; propertySheet.m_colorPage.m_edit1 = m_edit1; propertySheet.m_colorPage.m_edit2 = m_edit2; propertySheet.m_colorPage.m_edit3 = m_edit3; int result = propertySheet.DoModal(); if (result == IDOK) { m_check1 = propertySheet.m_textPage.m_check1; m_check2 = propertySheet.m_textPage.m_check2; m_check3 = propertySheet.m_textPage.m_check3; m_edit1 = propertySheet.m_colorPage.m_edit1; m_edit2 = propertySheet.m_colorPage.m_edit2; m_edit3 = propertySheet.m_colorPage.m_edit3; Invalidate(); } } Pentru ca modificrile fcute n foaia de proprieti asupra valorilor controalelor s fie afiate dup nchiderea foii, adugai urmtorul cod funciei OnDraw():
pDC->TextOut(20, 20, "TEXT OPTIONS PAGE"); if (m_check1) pDC->TextOut(20, 40, "Check1 is checked"); else pDC->TextOut(20, 40, "Check1 is not checked"); if (m_check2) pDC->TextOut(20, 60, "Check2 is checked"); else pDC->TextOut(20, 60, "Check2 is not checked"); if (m_check3) pDC->TextOut(20, 80, "Check3 is checked"); else pDC->TextOut(20, 80, "Check3 is not checked"); pDC->TextOut(20, 120, "COLOR OPTIONS PAGE"); char str[81]; wsprintf(str, "Red = %d", m_edit1); pDC->TextOut(20, 140, str); wsprintf(str, "Green = %d", m_edit2); pDC->TextOut(20, 160, str); wsprintf(str, "Blue = %d", m_edit3); pDC->TextOut(20, 180, str);

132

4.5 Lucrarea de laborator 5.


Visual C++ MFC Utilizarea controalelor.

4.5.1 Controlul de tip buton CButton


Acest control este folosit pentru realizarea unei aciuni rapide fiind un element de interfa accesibil n special cu mouse-ul dar i prin tastatur. El are trei stri principale liber, selectat i apsat. Pentru a experimenta efectiv cu un buton vom crea un program prin MFC App Wizard alegem ca tip de aplicaie Dialog Based, la pasul 2 i 3 apsm Next, apoi Finish. Va aprea fereastra de creare modificare a interfeei. n aceasta fereastr putnd aduga orice control disponibil. Selectm un buton. l dispunem pe spaiul afiabil al ferestrei. Pentru a modifica proprietile implicite vom face clic cu butonul 2 al mouse-ului pe el. Alegem ultima opiune din meniu Properties.

S-a deschis fereastra de mai sus. La caracteristici generale avem ID-ul butonului care este un nume de identificare recunoscut pe tot parcursul programului i disponibil pentru orice element de interfa. La Caption avem textul ce va fi scris pe buton. Apoi o serie de opiuni ce se pot seta prin casete de validare. Principalul lucru care ne intereseaz este legare butonului de o aciune anume. Pentru aceasta vom avea nevoie de ID-ul butonului. Prin clic pe buton se va deschide o fereastr program n care avem corpul funciei n care vom scrie codul util ce va fi realizat la apsarea butonului: void CS07Dlg::OnButton1() { // Aici adaugati codul ce se executa la apasarea butonului } Unde S07 este numele programului. i funcia OnButton() este aciunea asociat butonului 1. Dac n schimb dorim s facem anumite modificri asupra butonului prin program,stau la dispoziie o serie de funcii membri dintre care s-au selectat cele mai reprezentative: GetIcon,SetIcon pentru citirea,respectiv asocierea unui icon butonului; 133

GetBitmap,SetBitmap pentru citirea,respectiv asocierea unui bitmap pentru suprafaa butonului; GetCursor,SetCursor pentru citirea, respectiv asocierea unui pointer de mouse diferit cnd aceste survoleaz butonul. Pentru a accesa o funcie membr a butonului se scrie urmtoarea secvena de cod: CButton *mybutton=(CButton *)GetDlgItem(IDC_BUTTON1); mybutton->functie_membra; Prin aceasta avem un pointer la resursa de tip buton cu ID-ul IDC_BUTTON1. Prin folosirea aceleai secvene cu specificarea clasei controlului, respectiv a ID-ului asociat acelui control, putem avea acces la oricare din membrii clasei controlului. GetButtonStyle,SetButtonStyle returneaz, respectiv seteaz stilul butonului. GetWindowText,SetWindowText returneaz, respectiv seteaz textul butonului. Exemplu: mybutton->SetWindowText("De acord!"); char s[100]; //pentru a extrage textul de pe buton mybutton->GetWindowText(s,100);//textul este returnat n variabila s Exerciiu 1. Creai un program dup modelul precizat mai sus. Creai un buton care iniial indic Liber, iar dup apsare Apsat!. Numai cu funciile SetWindowText i GetWindowText ncercai s creai un program care s numere pn la cinci la fiecare apsare crescnd cu o unitate numrul i afind numrul pe buton. O alt soluie ar fi urmtoarea: 1. Declarai o variabil contor k n fisierul header xxxdlg.h, n clasa xxxDlg la seciunea protected. 2. Iniializai contorul k la 0 i afiai valoare pe buton n xxxDlg::OnInitDialog: CButton *mybutton=(CButton *)GetDlgItem(IDC_BUTTON1); k=0; char s[100]; sprintf(s,"%d",k); mybutton->SetWindowText(s); 3. In funcia de aciune a butonului vei scrie urmtoarea secven de cod: void CS07Dlg::OnButton1() { CButton *mybutton=(CButton *)GetDlgItem(IDC_BUTTON1); k++; char s[100]; 134

sprintf(s,"%d",k); mybutton->SetWindowText(s); } 4. Compilai i rulai.

4.5.2 Controlul de tip caset de editare CEdit


CEdit este un tip de control ce permite introducerea unei secvene de text pe un singur rnd. Putei seta proprietile casetei de editare din fereastra de editare a controlului la fel cum s-a procedat cu CButton. Dei deine mai multe funcii membre specifice cele mai utile sunt cele ce returneaz textul coninut GetWindowText, respectiv modific textul coninut SetWindowText. Alte funcii membre: GetLimitText,SetLimitText returneaz numrul maxim de caractere ce se pot introduce prin tastare,sau inserare, respectiv stabilete acest numr. GetModify() returneaz 0 dac textul din caseta de editare nu a fost modificat, altfel valoare diferit de 0. SetModify() reseteaz steguleul de modificare al coninutului casetei trecndu-l pe starea nemodificat. SetSel seteaz poziionarea seleciei pe textul din caseta. GetSel returneaz poziia seleciei textului din caseta. Undo aduce textul din caseta la starea precedent. Clear terge selecia curenta. Copy copie selecia curent n clipboard. Cut terge selecia curent nu nainte de a o copia n clipboard. Paste insereaz text din clipboard la poziia curent. SetReadOnly seteaz accesul la textul din caset putnd interzice modificarea lui. ShowCaret,HideCaret arat ,respectiv ascunde cursurul. Exerciiu 2. Creai un program cu o caset text i un buton care la apsarea butonului textul din caset s fie transferat ca text pe buton. Exerciiu 3.Creai un program cu dou casete text i un buton. La apsarea butonului textul selectat din prima caset este nserat pe poziia curent a cursorului n cea de a doua caseta.

135

4.5.3 Controlul de tip caset de validare CCheckListBox


Este folosit pentru a bifa / debifa o opiune ntr-o interfa. Poate fi configurat prin interfa vizual ca i CButton. Dintre funciile membre specifice amintim: GetWindowText, SetWindowText care returneaz sau seteaz textul casetei de validare la fel ca n cazul casetei de editare. GetCheck, SetCheck returneaz, respectiv seteaz starea bifrii. GetCheckStyle, SetCheckStyle returneaz, respectiv seteaz stilul casetei. CCheckListBox *cb=(CCheckListBox *)GetDlgItem(IDC_CHECK1); cb->SetWindowText("Acum"); cb->SetCheckStyle(BS_CHECKBOX); cb->SetCheck(IDC_CHECK1,1); Este un exemplu de folosirea a acestor metode (funcii membre). n privina stilurilor exista urmtoarele constante predefinite:
BS_CHECKBOX stilul precizeaz o caset standard; BS_AUTOCHECKBOX - caseta se bifeaz sau se debifeaz doar prin simpla

selectarea a acesteia;
BS_AUTO3STATE precizeaz o caset cu trei stri care se bifeaz sau

debifeaz prin selectare;


BS_3STATE precizeaz o caset cu trei stri, astfel nct caseta poate fi n

acelai timp i bifat i dezactivat. Enable seteaz starea de activare a casetei. IsEnabled returneaz starea de activare a casetei. Exerciiu 4. Creai un program cu patru casete de validare i o caset de editare. Casetele vor avea ca etichet numerele 1,2,3,4. De fiecare dat cnd o caset va fi bifat sau debifat n caseta de editare vor aprea etichetele casetelor bifate legate ntre ele prin &. De exemplu dac sunt bifate caseta 2 i 4 n caseta de editare va aprea 2&4.

136

4.5.4 Controlul tip buton radio


Butoanele radio permit selectarea doar unei opiuni dintr-un grup de opiuni. Aceste butoane pot fi grupate astfel nct s avem diverse grupuri de opiuni. Se observ ca la selectarea unei opiuni cea anterior selectat se deselecteaz. Pentru a accesa textul unui buton radio vom folosi urmtoarea secven: GetDlgItem(IDC_RADIO1)->SetWindowText("Asteptare!"); De notat c butoanele radio nu au o clas specific definit putnd fi ncrcate cu CCheckListBox, chiar i cu CButton, desigur metodele nu vor fi ntotdeauna valabile. Exerciiu 5. Creai un program cu patru butoane radio grupate avnd etichetele nume de persoane i o caset de editare. n momentul cnd butonul radio va fi selectat n caset va aprea numele persoanei alese.

4.5.5 Controlul de tip lista combo CComboBox


Permite selectarea unui ir de caractere dintr-o list retractabil. n momentul n care este selectat se desfoare lista i poate fi selectat opiunea dorit. Cele mai utile metode ale CComboBox sunt cele de construire a listei: AddString(s) adaug un ir de caractere la sfritul listei sau la poziia indexat alfabetic dac opiunea de auto-sortare a listei este activat; DeleteString(index) terge un element din list de pe poziia specificat de index; InsertString(index,s) insereaz un ir s n list la poziia specificat de index; FindString caut un sub-ir n list i dac l gsete i returneaz indexul; Exemplu: CComboBox *lista=(CComboBox *)GetDlgItem(IDC_COMBO1); lista->AddString("Andrei"); lista->AddString("Adrian"); lista->AddString("Radu"); lista->AddString("Mihai"); Metode pentru lucrul cu indexul: GetCount returneaz numrul de elemente din list; GetCurSel returneaz poziia elementului selectat din list; SetCurSel seteaz elementul curent selectat copiindu-l n caseta de editare, de notat c primul element are indicele 0; Clear,Copy,Cut, Paste terge, copie, decupeaz,respectiv adaug text din caseta de editare n sau din Clipboard; GetLBText obine textul unui element din list de la poziia specificat de un index; 137

Exerciiu 6. Realizai un program cu o list de ri europene cel puin zece. Creai i o caset de editare. n momentul n care ai selectat o ar numele acesteia s fie copiat n caseta de editare.

4.5.6 Controlul de tip text static: CStatic


CStatic este un control care doar afieaz un text la o anumit locaie. Acest text poate fi modificat ca i la celelalte controale prezentate cu ajutorul funciei SetWindowText i poate fi aflat acel text cu GetWindowText. Un exemplu ar fi urmtoarea structur: CStatic *st=(CStatic *)GetDlgItem(IDC_STATIC); st->SetWindowText("Aceasta este un text static."); Exerciiu 7. Modificai programul precedent astfel nct n dreptul casetei de editare s apar tara aleasa, iar n dreptul listei tari disponibile.

4.5.7 Metoda Create


Metoda Create poate fi folosit pentru generarea de butoane din program fr folosirea interfeei vizuale. Pentru a genera un buton se poate folosi codul: CRect r; r.left=10; r.right=10+200; r.top=10; r.bottom=10+20; myb.Create("Buton din program", | BS_PUSHBUTTON,r,this,1112);

WS_CHILD |

WS_VISIBLE

Pentru a declara variabila global myb se procedeaz astfel: se seteaz opiunea tabulat de vizualizare a clasei. Se d clic dreapta pe CxxxDlg se alege opiunea Add Member Variable. Exerciiu 8. Declarai o matrice de 10 pe 10 de butoane.(CButton ). n OnInitDialog al clasei CxxxDlg creai aceste butoane. Butoanele vor fi dispuse pe 10 linii i pe 10 coloane, iar pe butoane vor fi scrise numerele de la 1 la 100.

138

4.6 Lucrarea de laborator 6.


Visual C++ MFC

4.6.1 Utilizarea funciilor grafice.


Pentru a lucra cu funciile grafice oferite n cadrul MFC vom aborda urmtoarea opiune de generare a programului schelet : 1. Selectm MFC App Wizard (.exe) i scriem numele proiectului; 2. Alegem Single Document (SDI) i apsm Next. 3. La pasul 2 apsm Next. 4. La pasul 3 apsm Next. 5. Debifm Docking Toolbar, Initial Status Bar, Printing and print preview, apsm Finish. Va aprea n stnga ecranului clasele disponibile. Alegem CxxxView expandm ramura i apsam pe OnDraw. Cursurul se va poziiona automat n fereastra codului surs: void CSs01View::OnDraw(CDC* pDC) { CSs01Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // aici se insereaz codul care deseneaz }

4.6.2 Desenarea unei linii


Nu exist efectiv o funcie care s traseze o linie, n schimb acest lucru se poate realiza prin conlucrarea a dou funcii MoveTo care stabilete poziia unui capt al liniei i LineTo care stabilete poziia celuilalt capt i traseaz linia. Ele au urmtoarele prototipuri: CPoint MoveTo( int x, int y ); CPoint MoveTo( POINT point ); BOOL LineTo( int x, int y ); BOOL LineTo( POINT point ); Astfel se pot apela fie specificnd coordonatele x, y ale capetelor, fie specificnd punctul captului. n program vom scrie: pDC->MoveTo(10,10); pDC->LineTo(100,100); ,pentru a desena o linie cu setrile implicite ale culorii, grosimii i stilului de desenare. 139

Desenarea unui arc de cerc se poate face cu trei funcii distincte : 1. Arc cu prototipurile : BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 2. ArcTo cu prototipurile: BOOL ArcTo( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); BOOL ArcTo( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 3. AngleArc cu prototipul: BOOL AngleArc( int x, int y, int nRadius, float fStartAngle, float fSweepAngle ); Rezultatul este acelai trasarea unui arc de cerc. Vom face referire la doar un singur prototip cel expandat. Pentru Arc : x1, y1 coordonatele colului stnga sus al zonei rectangulare de ncadrarea ; x2, y2 coordonatele colului dreapta jos al zonei rectangulare de ncadrarea ; x3, y3 punctul de nceput al arcului ; x4, y4 punctul de sfrit al arcului de cerc ; Pentru ArcTo aceleai precizri numai c poziia curent a cursorului este rennoit. Pentr AngleArc : - x, y coordonatele centrului cercului ; - Radius este raza cercului ; - StartAngle reprezint unghiul de start al desenrii arcului ; - SweepAngle reprezint mrimea unghiular a arcului. Exemplu: pDC->Arc(10,10,200,200,10,10,200,200); pDC->ArcTo(10,10,200,200,10,10,200,200); pDC->AngleArc(100,100,100,10,90);

4.6.3 Desenarea unei linii poligonale


Pentru a desena o linie poligonala folosim funciile : PolyDraw, Polyline, PolyPolyline, PolylineTo, PolyBezier, PolyBezierTo care au urmtoarele prototipuri: BOOL PolyDraw( const POINT* lpPoints, const BYTE* lpTypes, int nCount ); BOOL Polyline( LPPOINT lpPoints, int nCount ); BOOL PolyPolyline( const POINT* lpPoints, const DWORD* lpPolyPoints, int nCount ); 140

BOOL PolylineTo( const POINT* lpPoints, int nCount ); BOOL PolyBezier( const POINT* lpPoints, int nCount ); BOOL PolyBezierTo( const POINT* lpPoints, int nCount ); PolyDraw deseneaz o linie poligonal cu un anumit tipic : - lpPoints este un pointer la un vector de puncte. - lpTypes este un pointer la un vector care specific pentru fiecare punct specificul desenrii ; - nCount este numrul de puncte desenate din vector. Polyline deseneaz o linie poligonal deschis fr a modifica poziia cursorului . PolyPolyline deseneaz o serie de linii poligonale acestea fiind specificate una dup alta n lpPoints, iar numrul de puncte al fiecrei linii este specificat n lpPolyPoints. PolylineTo deseneaz o linie poligonal rennoind poziia cursorului. PolyBezier deseneaz o curb Bezier ale crei puncte generative sunt specificate n lpPoints. PolyBezier deseneaz o curb Bezier cu rennoire cursorului. Exemplu : CPoint p[100]; int i; for (i=1;i<=50;i++) { p[i-1].x=i*5; p[i-1].y=100-(i%2)*40; } pDC->Polyline(p,50); Aceast secven va desena o linie n zigzag. Mai sunt funciile de specificare a direciei de desenare : GetArcDirection., SetArcDirection cu urmtoarele prototipuri: int GetArcDirection( ) const; int SetArcDirection( int nArcDirection ); Unde nArcDirection poate lua unu din urmtoarele valori constante : AD_COUNTERCLOCKWISE - specific c sensul va fi cel invers acelor de ceas; AD_CLOCKWISE - specific c sensul va fi cel al acelor de ceas. Acerte funcii influeneaz sensul n care se traseaz urmtoarele primitive grafice: Arc, ArcTo, Chord, Ellipse, Pie, Rectangle, RoundRect.

141

4.6.4 Funcii de desenare de figuri umplute:


Pentru desenarea unei regiuni eliptice mrginite de o dreapt folosim Chord cu urmtoarele prototipuri : BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); Semnificaiile perechilor x,y sunt acelai ca la Arc. Pentru desenarea unui dreptunghi se folosete Rectangle cu urmtoarele prototipuri : BOOL Rectangle( int x1, int y1, int x2, int y2 ); BOOL Rectangle( LPCRECT lpRect ); Unde x1,y1, x2,y2 sunt coordonatele colului stnga-sus, respectiv dreapta-jos ale dreptunghiului. n cel de-al doilea prototip pentru a specifica aceste coordonate se folosete o structur de tipul CRect. Pentru desenarea unui dreptunghi avnd coluri rotunjite se folosete RoundRect cu prototipurile : BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 ); BOOL RoundRect( LPCRECT lpRect, POINT point ); Unde primele patru valori, pentru primul prototip, sunt acelai ca pentru Rectangle, iar ultimele dou valori nu sunt coordonate ci raza pe ox, respectiv pe oy ale elipsei folosite la rotunjirea colurilor. Pentru desenarea unei elipse i eventual cerc, se folosete Ellipse cu urmtoarele prototipuri: BOOL Ellipse( int x1, int y1, int x2, int y2 ); BOOL Ellipse( LPCRECT lpRect ); Unde x1, y1, x2, y2 specific dreptunghiul ce ncadreaz elipsa, la fel fiind i cazul celui de al doilea prototip. Pentru desenarea unei regiuni eliptice delimitate de dou raze se folosete funcia Pie cu urmtoarele prototipuri: 142

BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); n care primele patru coordinate sunt aceleai ca la elips, urmtoarele patru specificnd punctual de nceput i de sfrit al regiunii. Pentru a desena un polygon nchis se folosete Polygon care are prototipul : BOOL Polygon( LPPOINT lpPoints, int nCount ); Se observ ca avem aceeai parametri ca la Polyline, deosebire fiind c punctul de nceput este unit automat cu punctul de sfrit nchiznd astfel conturul poligonal. O variant a acestei funcii este PolyPolygon cu prototipul: BOOL PolyPolygon( LPPOINT lpPoints, LPINT lpPolyCounts, int nCount ); Care se comport la fel ca PolyPolyline n ceea ce privete funcia parametrilor utilizai.

4.6.5 Setarea culorii i a stilului de desenare


Pn acum s-a precizat cum se deseneaz o serie de primitive dar aceste sunt toate n alb i negru desenate cu umplere sau trasare simpl fr a utiliza un stil anume. Pentru a modifica penia cu care se traseaz liniile se va crea o peni proprie prin folosirea clasei CPen. Aceast peni ne permite s schimbm culoarea, grosimea liniei, i stilul liniei (linie ntrerupt). Pentru a modifica culoare de umplere vom crea o pensul proprie ce ne va permite s stabilim culoare de umplere, modelul de umplere, stilul de umplere. Pensula va fi definit prin utilizarea clasei CBrush.

4.6.6 Configurarea peniei


Pentru a crea propria peni se declara un obiect de tip CPen. Se apeleaz funcia Create cu urmtoarele prototipuri : BOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor ); BOOL CreatePen( int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL ); Unde : nPenStyle specific stilul peniei; nWidth grosimea peniei; crColor reprezint culoare peniei specificate n format RGB; Stilul peniei poate fi precizat prin urmtoarele constante: PS_COSMETIC specific c modelul peniei este specificat n lpStyle; 143

PS_GEOMETRIC specific c modelul va fi cu linii ntrerupte a cror lungimi sunt specificate n lpStzle; PS_ALTERNATE alterneaz un punct lips unul desenat n model; PS_USERSTYLE specific un model specific definit de utilizator n lpStyle. Exemplu de utilizare al peniei: CPen mpen; mpen.CreatePen(PS_GEOMETRIC,3,RGB(0,0xFF,0)); CPen *oldpen=pDC->SelectObject(&mpen); CPoint p[100]; int i; for (i=1;i<=50;i++) { p[i-1].x=i*5; p[i-1].y=100-(i%2)*40; } pDC->Polyline(p,50); pDC->SelectObject(oldpen);

Se va desena un zigzag verde de grosime 3. Pentru a nu mai aprea marginea unei figuri desenate ci doar umplere se seteaz grosimea peniei la 0.

4.6.7 Configurarea pensulei


Pentru a configura pensula se folosete clasa CBrush. Pentru a crea o pensul se dispune de un set bogat de metode : - CreateSolidBrush creeaz o pensul cu umplere uniform ; - CreateHatchBrush creeaz o pensul cu umplere haurat; - CreateBrushIndirect creeaz o pensul prin intermediul unei structuri LOGBRUSH; - CreatePatternBrush creeaz o pensul la care modelul de umplere este un bitmap; - CreateDIBPattternBrush creeaz o pensul la care modelul de umplere este un bitmap independent de context; - CreateSysColorBrush creeaz o pensul avnd culoare specificat de sistem, modificnd doar stilul de haurare. CreateSolidBrush are urmtorul prototip: BOOL CreateSolidBrush( COLORREF crColor ); n care doar se specific culoare de umplere, stilul de umplere va fi unul uniform. 144

Exemplu : CPen mpen; mpen.CreatePen(PS_GEOMETRIC,3,RGB(0,0xFF,0)); CPen *oldpen=pDC->SelectObject(&mpen); CBrush mbrush; mbrush.CreateSolidBrush(RGB(0,0xFF,0xFF)); CBrush *oldbrush=pDC->SelectObject(&mbrush); CPoint p[100]; pDC->Ellipse(10,10,100,100); pDC->SelectObject(oldpen); pDC->SelectObject(oldbrush); CreateBrushIndirect are urmtorul prototip: BOOL CreateBrushIndirect( const LOGBRUSH* lpLogBrush ); Este cel mai indicat a fi folosit cnd se dorete un configurare completa a pensulei. Face apel la structura : LOGBRUSH typedef struct tagLOGBRUSH { // lb UINT lbStyle; COLORREF lbColor; LONG lbHatch; } LOGBRUSH; Unde lbStyle poate avea valorile: BS_DIBPATTERN pentru un model de umplere definit n DIB n acest caz lbHatch va fi indica adresa logic a DIB-ului; BS_HATCHED pentru un model cu haur; BS_HOLLOW figura nu va fi umplut; BS_NULL figura nu va fi umplut ; BS_PATTERN modelul este specificat ntr-un bitmap; BS_SOLID modelul de umplere este cel uniform.

Pentru lbHatch avem urmtoarele opiuni : - HS_BDIAGONAL - haur la 45 de grade de la dreapta la stnga ; - HS_CROSS - haur n carouri formate din linii verticale i orizontale egal spaiate; - HS_DIAGCROSS - haur la 45 de grade; - HS_FDIAGONAL - haur la 45 de grade; - HS_HORIZONTAL - haur prin linii orizontale; - HS_VERTICAL - haur prin linii verticale; 145

Exerciiu 1. S se deseneze dou linii verticale paralele, tiate de dou linii orizontale paralele. Liniile vor fi ntrerupte, de grosime 2 i de culoare roie. Exerciiu 2. S se deseneze dou arce de cerc care s fie sub forma a dou jumti de cerc tangente. Exerciiu 3. S se deseneze o linie n zigzag la care limea zigzagului s creasc liniar progresiv. Exerciiu 4. S se deseneze un dreptunghi albastru uniform iar n interiorul lui o elips roie haurat la 45 de grade. Exerciiu 5. S se deseneze o stea n cinci coluri de culoare galben. (Culoarea galben este dat de funcia RGB(0xFF,0xFF,0)).( Pentru a genera punctele poligonului mai uor folosii funciile trigonometrice sin i cos i o alternare n zigzag a distanei acestora fa de centrul stelei.)

146

4.7 Lucrarea de laborator 7.


Visual C++ MFC

4.7.1 Utilizarea intrrilor de la mouse i tastatur


Oricare aciune a utilizatorului prin mouse sau tastatur sau pornind de la mouse i tastatur, sau aciune automat ciclic, care acioneaz asupra ferestrei are corespondent ntr-o structur de gestionare a acestor aciuni un mesaj sau eveniment. Lucrul cu mesaje este o caracteristic a aplicaiilor Windows, aceasta a aprut cu primele variante de Windows 3.1, apoi a devenit un standard n Win32, OWL, respectiv MFC. Astfel progresiv s-a trecut de la o asociere manual acestor mesaje unor funcii aciuni la o asociere semiautomat, respectiv automat. n ceea ce privete aciunile mouse-lui orice aciune unitar care nu mai poate fi redus la alte aciuni are asociat un mesaj sau un eveniment. Astfel unei apsri a mouse-ului ,doar apsare fr eliberare i este asociat un eveniment i dac acesta are o utilitate pentru program i se poate asocia o funcie n care s se gestioneze aceast aciune. La fel i pentru tastatur oricrei apsri de tast i este asociat un eveniment. Pentru a programa un eveniment, adic pentru a-i asocia o funcie utilizm urmtoarea abordare:

Dup cum se vede se apas butonul din dreptul comboului n care este selectat CSs02Dlg. Se apas Add Windows Message Handler cel ncercuit cu rou pentru a aduga o funcie care s gestioneze mesajul.

147

Se deschide urmtoarea fereastr:

n partea stng se afl lista mesajelor disponibile, n partea dreapt list mesajelor crora li s-au asociat funcii. Se observ c denumirea mesajului are urmtorul tipic WM_nume_mesaj. Pentru a asocia o funcie mesajului dorit se selecteaz mesajul din lista din partea stng i se apas pe butonul Add Handler. Se poate aduga astfel unul sau mai multe mesaje pentru a fi tratate de program.(sau niciunul prin apsare butonului Cancel). Se observ c aici se pot aduga mesaje pentru toate obiectele definite prin selectarea corespunztoare a obiectului (lista Class or object to handle). De asemenea se dispune i de un filtru. Cu toate c putem aduga mai multe mesaje doar unuia i se va asocia o funcie n cadrul codului surs. Pentru a specifica crui mesaj i se va asocia o funcie se va face dublu clic pe acel mesaj mediul de programare va deschide automat fereastra codului surs exact la funcia asociat mesajului. Celelalte mesaje crora nu li s-au asociat funcii vor disprea automat din lista mesajelor tratate de program. Avnd acces la funcie putem programa acel eveniment. Observm c n funcie de evenimentul tratat funciei i sunt asociate anumii parametri prin care se transmit informaii de la eveniment. Pentru gestionarea mouse-lui avem definite urmtoarele mesaje:

148

WM_LBUTTONDBLCLK trimis dac s-a fcut dublu-clic cu primul buton al mouselui; WM_LBUTTONDOWN trimis dac s-a apsat primul buton al mouseului; WM_LBUTTONUP trimis dac s-a eliberat al doilea buton al mouselui; WM_MBUTTONDBLCLK trimis dac s-a fcut dublu clic pe butonul din mijloc al mouseului; WM_MBUTTONDOWN trimis dac s-a apsat butonul mijlociu al mouselui; WM_MBUTTONUP trimis dac s-a eliberat butonul mijlociu al mouseului; WM_MOUSEMOVE trimis dac s-a deplasat mouseul; WM_MOUSEWHEEL trimis dac s-a rotit rotia de derulare a mouseuui; WM_RBUTTONDBLCLK trimis dac s-a fcut dublu clic pe butonul doi al mouselui (butonul din dreapta n mod standard); WM_RBUTTONDOWN trimis dac s-a apsat butonul al doilea al mouseului; WM_RBUTTONUP trimis dac s-a eliberat butonul al doilea al mouseului;

Mai sunt i alte mesaje dar cu o folosire mai redus. Se va observa c toate funciile ce in de apsarea unui buton al mouseului sunt funcii identice ca parametri asociai. Astfel pentru mesajul WM_XBUTTONDBLCLK vom avea urmtorul prototip al funciei : afx_msg void OnXButtonDblClk( UINT nFlags, CPoint point ); , unde nFlags sunt o colecie de indicatori, a cror stare poate fi analizat prin constantele :
MK_CONTROL - Setat dac tasta CTRL este apsat; MK_LBUTTON - Setat dac primul buton al mouseului este apsat;

MK_MBUTTON - Setat dac butonul din mijloc al mouseului este apsat; MK_RBUTTON - Setat dac butonul al doilea al mouseului este apsat; MK_SHIFT - Setat dac tasta SHIFT este inut apsat;

point reprezint poziia curent a mouselui coordonata x este dat de point.x, iar y de point.y. Pentru mesajul WM_XBUTTONDOWN avem urmtoarea funcie asociat : afx_msg void OnXButtonDown( UINT nFlags, CPoint point ); Exemplu: void CSs02Dlg::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default 149

CDialog::OnLButtonDown(nFlags, point); if (nFlags & MK_CONTROL){ CClientDC dc(this); dc.Rectangle(point.x-5,point.y-5,point.x+5,point.y+5); } } Aceast secven de cod deseneaz un dreptunghi la poziia curent a mouse-ului de fiecare dat cnd se apas butonul stng al mouselui, inndu-se n acelai timp i tasta CTRL apsat.
Pentru WM_XBUTTONUP vom avea o funcie asociat cu un prototip

asemntor: afx_msg void OnXButtonUp( UINT nFlags, CPoint point ); WM_MOUSEMOVE are o funcie asociat cu urmtorul prototip: afx_msg void OnMouseMove( UINT nFlags, CPoint point ); WM_MOUSEWHEEL are o funcie asociat cu urmtorul prototip: afx_msg BOOL OnMouseWheel( UINT nFlags, short zDelta, CPoint pt ); ,unde zDelta specific unghiul de rotaie al rotiei mouselui poate avea valori positive sau negative n funcie de direcia de rotaie; i pt reprezint poziia actual a pointerului de mouse. Exerciiu 1. Creai un program care la clic pe primul buton al mouselui s deseneze la poziia cursorului un dreptunghi, la clic pe al doilea buton o elips, la clic pe butonul din mijloc un x din linii centrat pe poziia cursorului. Exerciiu 2. Creai un program care s deseneze linii cu mouse-ul la primul clic se stabilete primul capt al liniei la al doilea cellalt capt. Linia se traseaz la al doilea clic. Exerciiu 3. Creai un program pentru desenarea de dreptunghiuri (rectangle) la primul clic se stabilete coordonatele primului col la cel de-al doilea coordonatele celui de al doilea col. La cel de-al doilea clic se traseaz dreptunghiul.

4.7.2 Gestionarea intrrilor de la tastatur


Intrrile de la tastatur sunt gestionate prin mesaje care gestioneaz separat intrrile de taste alfa numerice, respectiv simboluri (%,#,&,/.a.m.d.) i intrrile de taste funcionale ( tastele sgei, tab, F1F12, Esc, PageUp, Page Down, Insert, Delete etc.). 150

Pentru a utiliza aceste mesaje creai o aplicaie gen SDI sau MDI, deoarece Dialog Based nu preia corect aceste mesaje. Aceste mesaje sunt: WM_CHAR trateaz primul tip de intrri de tastatur fiind generat la apsarea unei taste de acest tip; WM_KEYDOWN generat la apsarea i inerea apsat a unei taste funcionale; WM_KEYUP generat la eliberarea unei taste funcionale; Ele au asociate funciile cu urmtoarele prototipuri : afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ); afx_msg void OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ); afx_msg void OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags ); La OnChar nChar specific codul ASCII asociat caracterului generat de tasta respectiv ; La OnKeyDown,OnKeyUp nChar specific codul virtual al tastei funcionale ; nRepCnt numrul de repetri ale tastei ca urmare a inerii apsate a unei taste; nFlags sunt indicatori ale tipului de tasta (pentru OnKeyDown, OnKeyUp) : - biii de la 0-7 specific codul tastei specificat prin standardul OEM ; - bitul 8 dac este setat specific o tast extins, n cazul tastelor funcionale ; - bitul 13 indic dac tasta ALT este apsat ; - bitul 14 indic o stare anterioar a tastei 1 dac tasta era apsat naintea apelrii i 0 dac tast era liber ; - bitul 15 indic o stare de tranziie -1 dac tasta este eliberat, 0 dac este apsat ; Pentru OnChar nFlags are urmtoarea semnificaie : - biii 0-15 - specific numrul de repetiii ale tastei prin inerea ei apsat; - biii 16-23 - specific codul de scanare al tastei definit de OEM ; - bitul 24 specific o tast extins ; - ultimii trei bii (29,30,31) au aceeai semnificaie ca n cazul anterior ;

151

4.7.3 Folosirea acceleratorilor


O alt cale de a avea acces la tastatur este prin folosirea acceleratorilor. Pentru a aduga o resurs de tip accelerator vom accesa urmtorul meniu :

152

Deci din modul de vizualizare resurs vom face clic dreapta pe nodul rdcin i va apare un meniu, din aceste meniu vom alege Insert pe care vom face dublu-clic. Va apare urmtoarea fereastr :

Vom alege Accelerator i vom apsa butonul New. Va aprea fereastra :

153

Vom face dublu clic pe linie necompletat selectat. Aprnd un meniu n care efectiv vom specifica tasta, sau combinaia de taste:

Odat ce am definit aceast tast pe baz de ID vom defini o funcie asociat prin utilizarea meniului de adugare de mesaje.

154

5 NDRUMAR DE PROIECT
5.1 Laborator de proiect 1. 5.1.1 Introducere n proiectarea unei aplicaii
n cadrul acestui laborator se va urmri crearea unei aplicaii software complete folosind mediul vizual Visual C++. Pentru a face proiectul mai atractiv vom propune realizare de jocuri cu un cod relativ simplu. Acestea vor fi de patru tipuri: - Joc de tenis, de spart crmizi gen Arkanoid; - Joc de tetris, de realizat linii complete din blocuri de diferite forme; - Joc gen Dyna, de explorare a unui labirint i distrugerea acestuia prin bombe; - Joc gen Arcade Shooter, de distrugerea unor nave sau meteorii de ctre o nav cu micare pe orizontal. Studenii se pot grupa n echipe, astfel nct s-i coordoneze reciproc aciunile, s-i stabileasc sarcinile, s-i dezvolte astfel aptitudini de lucru n echip. La final vor prezenta o lucrare colectiv. Eventual se va prezenta aportul fiecruia la realizarea aplicaiei parte grafic, parte de codare, parte de algoritmi, parte de efecte sonore, grafice ale jocului, partea de scenariu etc. n aceast etap se vor stabili urmtoarele puncte: comportarea minimal a jocului adic cum trebuie s se desfoare un joc, ce opiuni de configurare i de stil de joc s fie disponibile; direcii de dezvoltare ale jocului adic la care anume element din joc s i se creasc complexitatea sau nivelul de interaciune cu utilizatorul; cutarea i analizarea unor jocuri deja fcute de tipul respectiv care s constituie o ludografie (echivalentul unei bibliografii dar n care n loc de cri ne vom referi la jocuri) i care s fie prezentate pe scurt (cele reprezentative), punnd accentul pe deosebiri i stabilind astfel un nucleu comun prin care s se defineasc acest tip de jocuri. se stabilesc care trsturi pot fi implementate n cadrul proiectului i la care trebuie s se renune, fie datorit complexitii, fie datorit volumului prea mare al muncii de implementare;

5.1.2 Comportarea minimal a jocului


155

Se are n vedere ca jocul s accepte intrri de la tastatura i/sau mouse. S prezinte o interfa grafic care s poat fi scalat ntr-o fereastr de tip Windows i s accepte modurile grafice disponibile n Windows.(nu se va lucru cu BGI). Se va avea n vedere producerea unei animaii de calitate fr plpiri ale ecranului i care s respecte legile bunului sim. Se vor folosi bitmapuri care vor fi integrate n resursele aplicaiei vizuale, eventual este permis folosirea unor biblioteci specializate de ncrcare a imaginilor. Se vor integra un minim de efecte sonore prin utilizarea wav- urilor disponibile n Windows sau a unora disponibile gratis pe internet. Parametrii de configurare i datele referitoare la scorurile record obinute vor fi pstrate i rencrcate din fiiere. Fiecare joc va avea un meniu standard n care va fi inclus un fiier de ajutor i o opiune despre. Se va avea n vedere un engine de joc care s consume ct mai puine resurse pentru ca jocul s poat fi jucat n configuraii ct mai minimale, eventual se vor stabili prin meniuri diferite opiuni de grafic, sau configurare care s reduc resursele alocate.

5.1.3 Direcii de dezvoltare a jocului:


Se va avea n vedere n primul rnd cretere play-abilitii jocului, anume comenzile s fie executate rapid i fidel. n al doilea rnd, ca direcie de dezvoltare, se va urmri adugarea de noi funcionaliti elementelor de joc, de exemplu nivele suplimentare, bonusuri noi, aciuni noi ale utilizatorului odat cu trecere la noi nivele sau achiziionarea de bonusuri. n al treilea rnd se va urmri creterea calitii i a esteticii elementelor grafice i dac se poate i a celor audio. n al patrulea rnd se vor crea scenarii ct mai atractive, pentru c se tie c un scenariu bun d mai mult sens jocului, chiar dac acesta nu are o grafic prea grozav sau se repet aceeai i aceeai pai. n al cincilea rnd mbuntirea strategiilor jocului prin creare unor IA mai evoluate.

5.1.4 Studiul unei ludografii i stabilirea complexitii


Se va cuta, sau se vor cerceta din jocurile de gen propuse, pentru a se vedea ce elemente vehiculeaz acestea, ce este nou la unele jocuri. Dac studentul nu are cunotin despre aceste jocuri le va ncerca, jucnd cel puin 10 minute jocul vizat, sau dac are experien va expune n ludografie jocurile de gen experimentate, srind peste altele mai obscure. n final dup ce i-a fcut o opinie despre elementele din ludografie va expune diferenele, respectiv nucleul comun al acestor jocuri i ce anume poate fi implementat n cadrul proiectului sau este capabil s implementeze n cadrul proiectului. Eventual va sugera elemente noi, inovative n concepie jocurilor de genul respectiv. 156

5.2 Laborator de proiect 2. 5.2.1 Structurile de date i obiectele jocului


n acest laborator echipele de studeni vor lucra la crearea structurilor primare ale jocurilor, dup ce i-au fcut o idee despre ce trebuie inclus neaprat. Astfel sa va defini o clas global,adic care s conin toate elementele jocului. Fiecare sub-element al jocului va fi declarat ca obiect al clasei globale. Acest sub-element poate fi n funcie de joc unul din urmtoarele: - la jocul de tenis mingea, paleta, crmida, bonusul, suprafaa de joc, caseta de afiat scorul; - la jocul de tetris blocul de construcie care cade, suprafaa de joc, tabela de scor, tabela ce anun piesa urmtoare; - la jocul gen dyna omuleul care exploreaz labirintul , bomba, explozia, bonusul, montrii, peretele din labirint, tabela de scor, tabela de stare a bonusului; - la jocul genul Arcade Shooter - nava, proiectilul, explozia, navele inamice sau meteoriii, bonusurile, tabela de scor, tabela de stare de nivel. La toate jocurile va fi o structur n care se vor pstra datele de configurare specific fiecrui joc n parte, o structur general n care se va pstra numele juctorului, scorul obinut, durata jocului i data cnd s-a nceput jocul. Dac este permis salvarea jocului n mijlocul acestuia se va specifica i o structur prin care s se salveze i s se reia jocul dorit, din starea n care s-a rmas. Structura va fi demonstrativ, de abia n starea final se va putea declar o structur general valabila. Toate structurile definite vor fi flexibile ele putnd fi modificate n funcie de cum evolueaz crearea jocului. n acest laborator se va pune la punct declararea, structurilor i a claselor, lucrul cu fiierele, declararea funciilor membre. Se va lucra cu Visual Studio crendu-se o aplicaie gen SDI (Single Document Interface) se va configura meniul jocului, se vor declara variabilele, funciile membre.

5.2.2 Creare de tipuri proprii din tipuri vechi


Atunci cnd se dorete o personalizare a unor tipuri de date deja definite pentru a fi mai sugestiv programarea se folosete cuvntul cheie typedef cu urmtoarea sintax: typedef tip_vechi nume_tip_nou; exemplu: 157

typedef int numar; numar n1,k,a;

5.2.3 Crearea de tipuri noi struct


O alt modalitate de creere de tipuri personale este crearea unei grupri de tipuri, de date simple ntr-o structur. Vom folosi pentru aceasta cuvntul cheie struct cu urmtoarea sintax: struct numestructura{ tip1 var1; tip2 var2; tipn varn,varnn; }; exemplu: struct persoana{ char nume[50]; int varsta; char cnp[20]; char adresa[100]; float salariu; };

5.2.4 Creare unei enumerri enum


Atunci cnd dorim s avem o mulime de elemente a crei constitueni s le dm un nume vom folosi enumerrile care au urmtoare sintax: Enum numeenumerare{element1,element2,element3,elementn}; Putem folosi enumerarea astfel> numeenumerare p; p=elementk; if (p= = elementm) {}

5.2.5 Crearea de clase class


Definirea unei clase se face astfel: class nume_clasa{ 158

tip1 data1; tip2 data1[10]; tipn datan; specificator1: nume_clasa(); ~nume_clasa(); tip1 functie1(); specificator2: tip2 functie2(); tipn functien(): } [obiect1],[obiect2]; Aceasta este structura general de definire a unei clase. Se observ cuvntul cheie class de la nceput, acesta se va regsi n toate definiiile de clase. Specificator1n sunt specificatori de acces care stabilesc accesul la membrii clasei cei care se gsesc dup el fiind afectai, pn ce apare un nou specificator de acces. nume_clasa() este o funcie constructor a clasei, se apeleaz automat cnd se declar un obiect de clasa respectiv. ~nume_clasa() este o funcie destructor a clasei, se apeleaz cnd s-a terminat lucrul cu obiectul definit, pentru a elibera memoria. Tipk functiek() este o funcie membru al clasei. Dup ce s-a definit clasa trebuie definite i funciile membre. n general pentru a accesa orice membru al unei clase pentru definire se folosete operatorul de specificare a domeniului :: . Exemplu: tipk nume_clasa::functiek() { // scriem continutul functiei return tipk; }

5.2.6 Lucrul cu fiierele


Pentru a lucra cu fiierele vom folosi intrrile ieirile standard pe baz de streamuri din C++. Vom folosi fiiere text pentru a salva configurrile i fiiere de tip dat cu acces aleatoriu pentru a salva ncrca starea jocului. Mai putem folosi biblioteci pentru ncrcarea de imagini ns acestea n general i gestioneaz singurele accesul la fiiere.

Avem urmtoarele tipuri de tipuri de streamuri fiier: 159

ifstream pentru scriere n fiier; ofstream - pentru citire din fiier; fstream pentru scriere i citire din fiier;

Deschidem streamul asociat fiierului cu funcia open() ce are urmtorul prototip: void open(const char *numefisier,int mod,int acces); n general vom avea nevoie doar de numele fiierului putnd scrie doar: ofstream iesire; iesire.open(test.txt ); Pentru a scrie/citi date din fiier vom folosi operatorii de extracie inserie cunoscui de la lucrul cu cin, cout numai c n locul acestora vom avea numele streamurilor fiier. Pentru a deschide n mod binar un stream de fiier vom utiliza specificatorul ios::binary. Exemplu: ofstream iesire; iesire.open(aut.txt,ios::out|ios::binary); iesire.put(a); iesire.close(); Pentru a scrie date dintr-o locatie de memorie folosim: istream &read(unsigned char *buf,int ncitit); ostream &write(const unsigned char *buf,int nscrisi); Pentru a ne poziiona n cadrul fiierelor deschise binar folosim: istream &seekg(streamoff offset,seek_dir origine); ostream &seekp(streamoff offset,seek_dir origine); Prin combinarea acestor funcii se poate scrie sau citi orice dat dorit din i n fiier.

160

5.3 Laborator de proiect 3. 5.3.1 Desenarea obiectelor, lucrul cu funciile grafice


Ne propunem s desenm obiectele care vor constitui elementele jocului. Unele imagini vom cuta s le generm, altele le vom desena cu uneltele oferite de editorul resurse,anume editorul de bitmapuri disponibil n Visual C++. Altele le vom crea prin mbinarea primitivelor grafice puse la dispoziie de Visual C++. Deci avem trei modaliti de abordare: - generarea imaginilor din puncte i primitive cu salvarea lor sub forma de bitmapuri; - crearea sau importarea de imagini prin editorul de resurse Visual C++. - cearea de imagini i interfee prin primitivele grafice puse la dispoziie de Visual C++. Cea mai eficient soluie i care cere cel mai puin de lucru este crearea imaginilor n afara mediului Visual C++, folosind editoare i unelte specializate de generare ale imaginilor. Alta ar fi lucrul cu Visual C++ pentru generarea unor imagini care vor fi salvate sub form de bitmapuri i reutilizate. Alta ar fi crearea de imagini prin editorul de resurse o soluie nu prea strlucit dar disponibil. Pentru a defini o resurs proprie de tip bitmap folosim urmtoarea secven de pai: 1. Avnd deja creat fiierul program vom seta modul de vizualizare pe resource view, n partea stng a ecranului; 2. Vom aduga un bitmap la resurse prin clic dreapta pe nodul rdcin, respectiv accesnd meniul insert; 3. Va apare o fereastr din care vom selecta Bitmap i vom apsa New; 4. Va fi creat o imagine bitmap fr coninut; 5. Vom face apel la sub-meniul Open din meniul File din meniul bar principal al mediului vizual de programare; 6. Setm tipul fiierelor ce vor fi deschise ca fiind - Image Files -. 7. Cutm i ncrcm imaginea dorit avnd grij s fie setat bitmapul fr coninut din arborele de resurse. 8. n locul imaginii necompletate va aprea imaginea dorit. Aceast imagine poate fi modificat sau se poate crea o imagine pornind de la zero folosind meniul de desenare:

161

Abordnd sistematic meniul de desenare fiecare rnd de la stnga la dreapta de sus n jos avem: - opiunea de decupare a unui dreptunghi; - opiunea de decupare dup un contur oarecare; - opiunea de copiere a unei culori din imagine; - opiunea de selectare a pointerului de tergere; - opiunea de umplere a unui contur folosind culoarea selectat; - opiunea de mrire a imaginii; - opiunea de selectare a pointerului creion deseneaz cte un punct odat; - opiunea de selectare a pointerului pensul deseneaz un grup de puncte de o anumit configuraie odat; - opiunea de selectare a pointerului spray; - opiunea de trasare a liniei; - opiunea de trasare a unei curbe; - opiunea de desenare a unui text; - opiunea de desenare a unui dreptunghi gol, plin cu margine, plin fr margine; - opiunea de desenare a unui dreptunghi rotunjit gol, plin cu margine, plin fr margine; - opiunea de desenare a unei elipse gol, plin cu margine, plin fr margine;

162

Mai jos este o caset de sub-opiune pentru alege grosimea liniei, forma pensulei, extinderea spray-ului, transparena fundalului textului etc. Iar sub aceasta este caseta din care se pot alege culorile. Pentru mai multe culori accesai meniul Image, apoi Adjust Colors. unde se poate seta n detaliu culoarea curent. Cealalt opiune ar fi desenare folosind funciile: primitive tip linie: o MoveTo/ LineTo trasarea unei linii; o Arc/ ArcTo/ Angle Arc trasarea unui arc de cerc; o PolyDraw/ Polyline /PolyPolyline / PolylineTo trasare unei linii poligonale; o PolyBezier / PolyBezierTo trasarea unei curbe Bezier; primitive tip figur umplut: o Chord pentru o regiune eliptic; o DrawFocusRect pentru un dreptunghi cu aspect focalizat; o Ellipse deseneaz o elips; o Pie deseneaz o regiune eliptic mrginit de dou raze; o Polygon / PolyPolygon deseneaz un polygon plin sau un set de poligoane; o Rectangle deseneaz un dreptunghi plin; o RoundRect deseneaz un dreptunghi avnd coluri rotunjite; de afiare a textului: o TextOut / ExTextOut pentru afiarea unui text; o TabbedTextOut afieaz un text identat cu taburi; o DrawText deseneaz un text ncadrat ntr-o regiune dreptunghiular; o GetTextExtent / GetOutputTextExtent /GetTabbedTextExtent returneaz dimensiunile textului afiat; o GetTextAlign / SetTextAlign stabilete alinierea textului; o GetBkColor / SetBackColor se refer la culoarea de fundal a textului; o GetTextColor / SetTextColor se refer la culoarea efectiv a textului; o GetBkMode / SetBKMode se refer la stilul n care este afiat fundalul; de afiare a bitmapurilor: o PatBlt / BitBlt / StretchBlt pentru a afia un bitmap din memorie; o GetPixel / SetPixel pentru a afia , respectiv citi un pixel de pe ecran; o Floodfill / ExtFloodFill pentru a umple un contur cu o anumit culoare; o MaskBlt / PlgBlt alte metode de afiare a unui bitmap; n combinaie cu aceste sunt clasele: CPen pentru specificarea peniei; CBrush pentru specificarea pensulei; CRect pentru specificarea unei regiuni rectangulare; CPoint pentru specificarea coordonatelor unui punct; CFont pentru a specifica parametrii unui font; CBitmap pentru a lucru cu o imagine de tip bitmap; 163

CRgn pentru a specifica o regiune din fereastr; CPalette pentru a specifica o palet de culori; CDC pentru specificare general a unui dispozitiv de context; CPaintDC dispozitivul principal de context de desenare; CClientDC dispozitiv secundar de desenare apelabil din oricare metoda a clasei principale; CWindowDC dispozitiv de context asociat unei ferestre; CMetaFileDC dispozitiv de context asociat unui metafiier;

164

5.4 Laborator de proiect 4. 5.4.1 Animarea elementelor de joc


n acest laborator se va aborda problema unei animaii folosind obiecte statice, folosirea unor fiiere video tip .avi., introducerea i integrarea de suport audio n aplicaie.

5.4.2 Animaia unor obiecte statice:


n laboratorul trecut s-a abordat generarea unor imagini statice. Pentru a le afia i pentru a da senzaia de micare trebuie folosit o metod care la intervale regulate de timp, extrem de scurte, dar ndeajuns de lungi ca ochiul s observe diferena, s afim o nou imagine, sau aceeai imagine dar la coordonate diferite. n acest sens avem nevoie de o funcie care s fie apelat la intervale constante de timp. Acest lucru se poate realiza folosind timere care genereaz la intervale de timp specificate un mesaj WM_TIMER cruia i pot fi asociate funcii. Precizia unui timer este de o milisecund. Dac de exemplu vrem o animaie cu 100 de cadre timerul va avea asociat o durata de 10 milisecunde. Pe ct de mare este numrul de cadre pe secund cu att se face apel la mai multe resurse, mai mult timp de procesare. Rezonabil ar fi cam 30 de cadre pe secund, deci o constant de timp de aprox. 30 de milisecunde. Declararea unui timer: UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) ); ,unde : - nIDEvent este ID-ul asociat timerului ; - nElapse este intervalul de timp n milisecunde la care este apelat timerul ; - urmtorul parametru se poate seta cu 0 ; Exemplu de folosire a unui timer :
void CMainFrame::OnStartTimer() { m_nTimer = SetTimer(1, 2000, 0);//creaz timerul } void CMainFrame::OnStopTimer() { KillTimer(m_nTimer); // distruge timerul } void CMainFrame::OnTimer(UINT nIDEvent) //corpul funciei associate //timerului { MessageBeep(0xFFFFFFFF); //functia asociat timerului va emite un //beep // Call base class handler.

165

CMDIFrameWnd::OnTimer(nIDEvent)//timerul va fi recirculat

Se poate crea un singur timer, toate elementele avnd normalizare temporal n limita constantei de timp a timerului. n funcia de timer se vor introduce bucile de cod ce vor fi animate , avnd specificate un contor de evoluie temporar care va putea genera fie poziii succesive pe o traiectorie, fie urmtorul cadru al animaiei. Se va constata pe parcurs c intrrile de la utilizator nu specific fiecare pas al animaiei ci doar iniiaz o secven de animaie. Astfel n cazul mingii la tenis utilizatorul nu poate aciona dect asupra paletei mingea fiind animat n mod continuu, paleta va fi micat nu direct de utilizator,ci cu anumite efecte ineriale. La micarea omuleului utilizatorul va preciza doar nceputul i sfritul deplasrii acestuia nu i cum se mic efectiv. La fel ca n cazul mingii montrii vor fi animai n mod continuu. La fel i cu meteoriii la Shooter. Un caz mai interesant este o micare semiautomat a crmizilor din tetris, cderea va fi automat dar rotirea va fi controlat de utilizator.

5.4.3 Evitarea plpirii imaginii


Pentru a face s dispar acest fenomen este indicat ca tot ce se deseneaz i se animeaz la un moment dat s fie desenat ntr-un bitmap, cnd desenarea obiectelor s-a ncheiat, bitmapul va fi afiat pe ecran. Preferabil ca ntreaga suprafa de joc s fi afiat printr-un bitmap. Aceast tehnic se numete double buffering n englez, i nu are o traducere echivalent, simpl n romn, dar semnificaia lui n mare este cea de mai sus.

5.4.4 Animaia pe baz de avi-uri


Visual C++ are o bibliotec care face apel la funcii multimedia. Un set de astfel de funcii i structuri este destinat pentru lucrul cu fiierele AVI. Pentru a lucra cu un fiier avi putem folosi urmtoare secven de cod:
// LoadAVIFile incarca si deschide fisiere AVI // // szfile numele fisierului // hwnd pointer gen indice al ferestrei // VOID LoadAVIFile(LPCSTR szFile, HWND hwnd) { LONG hr; PAVIFILE pfile; AVIFileInit(); // initializeaza biblioteca AVI

hr = AVIFileOpen(&pfile, szFile, OF_SHARE_DENY_WRITE, 0L); //deschide AVI if (hr != 0){ ErrMsg("Nu am putut deschide %s", szFile);

166

return;

// // Aici se pun functiile care interactioneaz cu structura AVI // AVIFileRelease(pfile); AVIFileExit(); // se inchide fisierul AVI // se elibereaz biblioteca AVI

} Pentru a deschide nite streamuri de prelucrare AVI folosim codul:


void InsertAVIFile(PAVIFILE pfile, HWND hwnd, LPSTR lpszFile) { int i; gcpavi = 0; //se deschid toate streamurile disponibile for (i = gcpavi; i < MAXNUMSTREAMS; i++) { gapavi[i] = NULL; if (AVIFileGetStream(pfile, &gapavi[i], 0L, i - gcpavi) != AVIERR_OK) break; if (gapavi[i] == NULL) break; } // Display error message-stream not found. if (gcpavi == i) { ErrMsg("Fisierul %s nu a fost gasit!", lpszFile); if (pfile) // daca fisierul a fost deschis acesta este inchis AVIFileRelease(pfile); return; } else { gcpavi = i - 1; }

Pentru procesarea streamurilor n continuare se folosete urmtoarea secven:


void StreamTypes(HWND hwnd) { AVISTREAMINFO avis; LONG r, lHeight = 0; WORD w; int i; RECT rc; // Parcurgem toate streamurile for (i = 0; i < gcpavi; i++) { AVIStreamInfo(gapavi[i], &avis, sizeof(avis));

167

if (avis.fccType == streamtypeVIDEO) { // Aici se fac prelucrarile secventelor video } else if (avis.fccType == streamtypeAUDIO) { // Aici se fac prelucrarile secventelor audio } else if (avis.fccType == streamtypeTEXT) { // Aici se fac prelucrarile secventelor text } }

Sunt disponibile urmtoarele funcii de lucru cu AVI-uri : AVIBuildFilter AVIClearClipboard AVIFileAddRef AVIFileCreateStream AVIFileEndRecord AVIFileExit AVIFileGetStream AVIFileInfo AVIFileInit AVIFileOpen AVIFileReadData AVIFileRelease AVIFileWriteData AVIGetFromClipboard AVIMakeCompressedStream AVIMakeFileFromStreams AVIMakeStreamFromClipboard AVIPutFileOnClipboard AVISave AVISaveOptions AVISaveOptionsFree AVISaveV AVIStreamAddRef AVIStreamBeginStreaming AVIStreamCreate AVIStreamEndStreaming AVIStreamFindSample AVIStreamGetFrame AVIStreamGetFrameClose AVIStreamGetFrameOpen 168

AVIStreamInfo AVIStreamLength AVIStreamOpenFromFile AVIStreamRead AVIStreamReadData AVIStreamReadFormat AVIStreamRelease AVIStreamSampleToTime AVIStreamSetFormat AVIStreamStart AVIStreamTimeToSample AVIStreamWrite AVIStreamWriteData CreateEditableStream EditStreamClone EditStreamCopy EditStreamCut EditStreamPaste EditStreamSetInfo EditStreamSetName

5.4.5 Lucrul cu fiiere audio


Apelarea funciilor audio va fi realizat tot n interiorul funcii temporizate. Cea mai simpl abordare este folosirea funciei avnd prototipul: BOOL PlaySound( LPCSTR numefisier, DWORD indicatori_de_redare ); HMODULE modul_deschidere,

,unde: - modul_deschidere este un pointer spre o resurs executabil care red fiierul n mod obinuit este NULL; - indicatori de redare specific modul cum va fi redat fiierul audio de tip WAV opiunea cea mai utilizat este : SND _ASYNC || SND_FILENAME. De exemplu pentru a reda fiierul explozie.wav fr a atepta terminarea acestuia (opiunea asincron) se utilizeaz urmtoarea apelare a funciei: PlaySound(explozie.wav , NULL, SND _ASYNC || SND_FILENAME); Mai sunt i alte opiuni de redare a fiierelor audio: o abordare fiind controlul direct al redrii prin mprirea pe buci a fiierului audio, cealalt metod este doar specificarea parametrilor de redare, ncredinarea gestionrii fluxului fiind acordat unui driver de redare.(Biblioteca MCI). Abordarea MCI pentru fiiere audio lungi este cea mai uor de implementat. 169

Un exemplu de abordare MCI este urmtorul :


DWORD playWAVEFile(HWND hWndNotify, LPSTR lpszWAVEFileName) { UINT wDeviceID; DWORD dwReturn; MCI_OPEN_PARMS mciOpenParms; MCI_PLAY_PARMS mciPlayParms; // Se deschide dispozitivul MCI prin specificarea numelui //fisierului si a dispozitivului multimedia mciOpenParms.lpstrDeviceType = "waveaudio"; mciOpenParms.lpstrElementName = lpszWAVEFileName; if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &mciOpenParms)) { //s-a produs o eroare la deschiderea fisierului return (dwReturn); } // Dispozitivul s-a deschis fara erori extragem ID-ul wDeviceID = mciOpenParms.wDeviceID; // Redam fisierul prin intermediul dispozitivului multimedia mciPlayParms.dwCallback = (DWORD) hWndNotify; if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms)) { mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL); return (dwReturn); } return (0L);

170

5.5 Laborator de proiect 5. 5.5.1 Gestionarea interfeei cu utilizatorul tastatur i mouse


Pentru a interaciona cu jocul utilizatorul trebuie s foloseasc un dispozitiv de intrare. Cel mai utilizat este mouse-ul, iar pentru comenzi suplimentare tastatura. n unele jocuri avansate se mai folosesc joystickul cu sau fr feedback sau gamepad-ul sau volane cu feedback. n cazul jocurilor pe care le creem vom apela mai des la tastatur dect la mouse. Lucrul cu mouse-ul i tastatura presupune gestionarea unor mesaje i asocierea lor cu nite funcii rspuns. Pentru mouse avem urmtoarele mesaje: WM_LBUTTONDBLCLK trimis dac s-a fcut dublu-clic cu primul buton al mouselui; WM_LBUTTONDOWN trimis dac s-a apsat primul buton al mouseului; WM_LBUTTONUP trimis dac s-a eliberat al doilea buton al mouselui; WM_MBUTTONDBLCLK trimis dac s-a fcut dublu clic pe butonul din mijloc al mouseului; WM_MBUTTONDOWN trimis dac s-a apsat butonul mijlociu al mouselui; WM_MBUTTONUP trimis dac s-a eliberat butonul mijlociu al mouseului; WM_MOUSEMOVE trimis dac s-a deplasat mouseul; WM_MOUSEWHEEL trimis dac s-a rotit rotia de derulare a mouseuui; WM_RBUTTONDBLCLK trimis dac s-a fcut dublu clic pe butonul doi al mouselui (butonul din dreapta n mod standard); WM_RBUTTONDOWN trimis dac s-a apsat butonul al doilea al mouseului; WM_RBUTTONUP trimis dac s-a eliberat butonul al doilea al mouseului;

Asocierea unui mesaj cu o funcie se face prin adugarea unui gestionar (handler) de evenimente. Aceasta se poate face prin clic dreapta n clasa fereastr pe clasa cu numele CxxxView i alegerea opiunii Add Windows Message Handler de aici doar transferm mesajul dorit din lista din stnga n cea din dreapta i apoi facem dublu clic pe el, mediul de programare ne va poziiona n dreptul funciei asociate unde vom scrie aciunea dorit. Pentru aplicaii simple se pot trata separat fiecare eveniment generat de mouse, dar vom observ c atunci cnd lucrurile se complic este necesar c fiecare din funciile asociate s formateze ntr-un mod comod datele ce parvin de la mouse i s le transmit mai departe unei funcii unice de gestionare a mouse-ului de exemplu MouseWork(int mb,int mx,int my,int aa,int kf) n care mb semnific starea butoanelor de mouse, mx,my coordonatele pointerului, aa deplasarea rotiei de scroll, kf starea butoanelor funcionale CTRL, SHIFT, ALT. Motivul abordrii mouselui n acest fel este c nu toi parametrii sunt n general actualizai de aceea starea lor trebuie reinut, i procesat atunci cnd apare o circumstan semnificativ pentru aplicaie. Acestor mesaje le sunt asociate urmtoarele funcii de gestionare: afx_msg void OnXButtonDblClk( UINT nFlags, CPoint point ); afx_msg void OnXButtonDown( UINT nFlags, CPoint point ); 171

afx_msg void OnXButtonUp( UINT nFlags, CPoint point ); afx_msg void OnMouseMove( UINT nFlags, CPoint point ); afx_msg BOOL OnMouseWheel( UINT nFlags, short zDelta, CPoint pt ); Unde X poate fi L,M sau R, nFlags reprezint nite indicatori de stare analizabili prin constantele:
MK_CONTROL - Setat dac tasta CTRL este apsat; MK_LBUTTON - Setat dac primul buton al mouseului este apsat;

MK_MBUTTON - Setat dac butonul din mijloc al mouseului este apsat; MK_RBUTTON - Setat dac butonul al doilea al mouseului este apsat; MK_SHIFT - Setat dac tasta SHIFT este inut apsat;

Point reprezint poziia pointerului mouseului; zDelta reprezint deplasarea unghiular a rotiei de mouse.

5.5.2 Gestionarea mesajelor de tastatur


Pentru gestionarea mesajelor de tastatur se face apel la urmtoarele mesaje: WM_CHAR trateaz primul tip de intrri de tastatur fiind generat la apsarea unei taste de acest tip; WM_KEYDOWN generat la apsarea i inerea apsat a unei taste funcionale; WM_KEYUP generat la eliberarea unei taste funcionale;

Se observ c se face o diferen ntre taste tastele care returneaz un caracter ASCII genereaz n special mesajul WM_CHAR, pe cnd tastele funcionale numai mesajele WM_KEYDOWN i WM_KEYUP. Aceste mesaje au asociate funciile: afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ); afx_msg void OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ); afx_msg void OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags ); La OnChar nChar specific codul ASCII asociat caracterului generat de tasta respectiv ; La OnKeyDown,OnKeyUp nChar specific codul virtual al tastei funcionale ; nRepCnt numrul de repetri ale tastei ca urmare a inerii apsate a unei taste; nFlags sunt indicatori ale tipului de tasta (pentru OnKeyDown, OnKeyUp) : - biii de la 0-7 specific codul tastei specificat prin standardul OEM ; - bitul 8 dac este setat specific o tast extins, n cazul tastelor funcionale ; - bitul 13 indic dac tasta ALT este apsat ; 172

bitul 14 indic o stare anterioar a tastei 1 dac tasta era apsat naintea apelrii i 0 dac tast era liber ; bitul 15 indic o stare de tranziie -1 dac tasta este eliberat, 0 dac este apsat ; Pentru OnChar nFlags are urmtoarea semnificaie : biii 0-15 - specific numrul de repetiii ale tastei prin inerea ei apsat; biii 16-23 - specific codul de scanare al tastei definit de OEM ; bitul 24 specific o tast extins ; ultimii trei bii (29,30,31) au aceeai semnificaie ca n cazul anterior ;

Se mai poate lucra i cu acceleratorii care sunt una din resursele puse la dispoziie de Visual C++. Pe lng aceste mijloace mai sunt o serie de funcii de gestionare a tastaturii n biblioteca Win32. Pentru o gestionare complet a tastaturii este recomandabil ca tuturor tastelor s li se asocieze un vector n care printr-o valoare 1 s se specifice c tasta a fost apsat i este inut apsat i cu 0 c tasta a fost eliberat. n urmtoarea secven de cod se prezint o gestionare elementar a tastaturii cu posibilitatea afirii tastelor curent apsate pe ecran. void CSs05View::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default char s[100]; keys[nChar]=1; //tasta este apasata int i,j=0; CClientDC dc(this); //stergem zona de afisare a starii tastaturii dc.Rectangle(0,0,100,500); //afisam tastele care sunt apasate in momentul de fata for (i=1;i<=255;i++) if (keys[i]==1) { sprintf(s,"%d",i); dc.TextOut(10,10+(j%20)*15,s); j++; } CView::OnKeyDown(nChar, nRepCnt, nFlags); } void CSs05View::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default char s[100]; //tasta este eliberata keys[nChar]=0; int i,j=0; CClientDC dc(this); //stergem suprafata de afisare dc.Rectangle(0,0,100,500); 173

// afisam codul tastelor ce raman afisate for (i=1;i<=255;i++) if (keys[i]==1) { sprintf(s,"%d",i); dc.TextOut(10,10+(j % 20)*15,s); j++; } CView::OnKeyUp(nChar, nRepCnt, nFlags); } Vectorul de care vorbeam este keys[]. Se observ c se accepta apsare a mai mult de dou taste n acelai timp putndu-se ajunge pn la 6 - 7 taste apsate simultan, acest numr variaz n funcie de productorii de tastaturi. Vei vedea n jocuri c este necesar s se poat da mai multe comenzi simultan de la tastatur i atunci cnd se joac n mod Single Player(un singur juctor), i atunci cnd joac dou persoane una mpotriva alteia, astfel nct comenzile s nu se bruieze reciproc. Este important de tiut numele codurilor virtuale ale tastelor. n lista de mai jos sunt codurile cele mai des utilizate : VK_BACK 08 VK_TAB 09 VK_CLEAR 0C VK_RETURN VK_SHIFT 10 VK_CONTROL VK_MENU 12 VK_PAUSE 13 VK_CAPITAL VK_ESCAPE 1B VK_SPACE 20 VK_PRIOR 21 VK_NEXT 22 VK_END 23 VK_HOME 24 VK_LEFT 25 VK_UP 26 VK_RIGHT 27 VK_DOWN 28 VK_SELECT 29 VK_SNAPSHOT VK_INSERT 2D VK_DELETE 2E VK_HELP 2F VK_0 30 0 tasta VK_1 31 1 tasta BACKSPACE tasta TAB tasta CLEAR tasta 0D ENTER tasta SHIFT tasta 11 CTRL tasta ALT tasta PAUSE tasta 14 CAPS LOCK tasta ESC tasta SPACEBAR PAGE UP tasta PAGE DOWN tasta END tasta HOME tasta LEFT ARROW tasta UP ARROW tasta RIGHT ARROW tasta DOWN ARROW tasta SELECT tasta 2C PRINT SCREEN tasta for Windows 3.0 and later INS tasta DEL tasta HELP tasta

174

VK_2 32 2 tasta VK_3 33 3 tasta VK_4 34 4 tasta VK_5 35 5 tasta VK_6 36 6 tasta VK_7 37 7 tasta VK_8 38 8 tasta VK_9 39 9 tasta VK_A 41 A tasta VK_B 42 B tasta VK_C 43 C tasta VK_D 44 D tasta VK_E 45 E tasta VK_F 46 F tasta VK_G 47 G tasta VK_H 48 H tasta VK_I 49 I tasta VK_J 4A J tasta VK_K 4B K tasta VK_L 4C L tasta VK_M 4D M tasta VK_N 4E N tasta VK_O 4F O tasta VK_P 50 P tasta VK_Q 51 Q tasta VK_R 52 R tasta VK_S 53 S tasta VK_T 54 T tasta VK_U 55 U tasta VK_V 56 V tasta VK_W57 W tasta VK_X 58 X tasta VK_Y 59 Y tasta VK_Z 5A Z tasta VK_NUMPAD0 60 Numeric keypad 0 key VK_NUMPAD1 61 Numeric keypad 1 key VK_NUMPAD2 62 Numeric keypad 2 key VK_NUMPAD3 63 Numeric keypad 3 key VK_NUMPAD4 64 Numeric keypad 4 key VK_NUMPAD5 65 Numeric keypad 5 key VK_NUMPAD6 66 Numeric keypad 6 key VK_NUMPAD7 67 Numeric keypad 7 key VK_NUMPAD8 68 Numeric keypad 8 key VK_NUMPAD9 69 Numeric keypad 9 key VK_MULTIPLY 6A Multiply key VK_ADD 6B Add key VK_SEPARATOR 6C Separator key 175

VK_SUBTRACT 6D Subtract key VK_DECIMAL 6E Decimal key VK_DIVIDE 6F Divide tasta VK_F1 70 F1 tasta VK_F2 71 F2 tasta VK_F3 72 F3 tasta VK_F4 73 F4 tasta VK_F5 74 F5 tasta VK_F6 75 F6 tasta VK_F7 76 F7 tasta VK_F8 77 F8 tasta VK_F9 78 F9 tasta VK_F10 79 F10 tasta VK_F11 7A F11 tasta VK_F12 7B F12 tasta VK_F13 7C F13 tasta VK_F14 7D F14 tasta VK_F15 7E F15 tasta VK_F16 7F F16 tasta VK_F17 80H F17 tasta VK_F18 81H F18 tasta VK_F19 82H F19 tasta VK_F20 83H F20 tasta VK_F21 84H F21 tasta VK_F22 85H F22 tasta VK_F23 86H F23 tasta VK_F24 87H F24 tasta VK_NUMLOCK 90 NUM LOCK tasta VK_SCROLL 91 SCROLL LOCK tasta Acum avei acces la marea parte a funciilor tastaturii i mouselui. n program nu vei conecta direct o aciune a elementului de joc manevrabil la tast ci vei construi o list gen FIFO n care vei pune comenzile urmnd ca acestea s fie tratate ori n funcia Timerului ori ntr-o funcie tampon de gestionare a aciunilor care s transmit timerului doar comenzi de animaie.

176

5.6 Laborator de proiect 6. 5.6.1 Integrarea elementelor precedente


n etapele precedente practic am realizat toate elementele eseniale ale unui joc dar nu le-am pus s lucreze mpreun. Esenialul ntr-un joc este ca un element s interacioneze cu altul iar prin aceasta juctorul s interacioneze cu mediul virtual al jocului. Vom aborda problema exemplificnd pentru fiecare joc n parte. La jocul de tenis mingea trebuie s interacioneze cu paleta i cu crmizile, att paleta ct i crmizile vor genera o ciocnire perfect elastic respingnd mingea. De asemenea minge mai interacioneaz i cu pereii laterali producndu-se de asemenea ciocniri elastice. Mingea nu trebuie s treac prin palet sau prin crmizi dect dac se dorete expres acest lucru. n timp ce paleta rmne intact, n urma ciocnirilor crmizile se sparg sau trec n alt stare. De asemenea bonusurile trebuie absorbite de palet dac aceasta st n calea lor. La jocul de tetris la fiecare micare a elementului de construcie se va verifica dac elementul are libertate de micare. Dac la cderea elementului se constat c acesta nu mai are loc unde s cad, se va mai lsa un interval de timp scurt pentru translaii pe orizontal apoi obiectul va fi cimentat n zid i altul va ncepe s cad. La jocul gen Dyna la fiecare micare o omuleului se va verifica dac calea este liber (nu este zid,nu este monstru,nu este bomb pus). Dac valul exploziei d peste omule sau micarea monstrului se intersecteaz cu cea a omuleului se d mesajul c omul a murit i n acel moment se declaneaz procedura de pierdere a unei viei sau de ncheiere a jocului. i montrii au interdicii de a trece prin ziduri sau peste bombe, n afar de cazul n care abilitile lor le permit acest lucru. La jocul gen Arcade Shooter proiectilele lansate de nava vor interaciona cu meteoriii. Meteoriii vor interaciona, dac nu sunt distrui i se ciocnesc cu nava, cu nava. Proiectilele lansate de nave inamice, inclusiv navele inamice, n eventualitatea unor ciocniri vor interaciona cu nava.

5.6.2 IA-ul jocului


Inteligena artificial asociat jocului n cazul de fa este doar una elementar sau redus la minim. La tenis va trebui doar s examinm nite ciocnire i unghiuri de deviaie. La tetris doar o suprapunere a unei matrici peste alta. La Shooter doar o intersectare dintre proiectile, nav, nave i meteorii. n schimb la Dyna, programarea micrii montrilor poate constitui o tem inepuizabil de dezvoltare a IA-ului, dar pentru proiectul de fa ne vom propune s realizm nite montri nu prea istei, care nu fug dup omule, ci doar i iau o via dac traiectoria lor se intersecteaz cu cea o omuleului. Aceasta s-ar putea ntmpla fie c omuleul este prins la col, fie c monstrul este mai rapid i nu a putut fi evitat, fie din neatenia sau nesbuina juctorului. Un algoritm simplu de micare haotic a monstrului ar fi ca acesta s parcurg n linie dreapt un culoar pn ntlnete un obstacol, apoi s o ia pe urmtorul drum neexplorat, disponibil, altfel doar s se ntoarc napoi. 177

Deci n mare parte vor aprea probleme de implementare a unor comportamente i efecte grafice corelate ntre ele i nu probleme efective de programare a IA-ului.

5.6.3 Construcia unui meniu despre


Se observ c Visual C++ deja a construit o fereastr despre. Aceasta poate fi accesat prin modul de gestionare a resurselor din ramura Dialog apoi fcnd clic pe IDD_ABOUTBOX.

Vom modifica iconul nlocuindu-l cu unul propriu, titlul ferestrei, cine a realizat jocul, copyright ul jocului, ocazia ce a dus la creare jocului.

5.6.4 Construcia unui meniu de ajutor


Vom crea un meniu de ajutor pentru a da detalii despre joc, neaprat vom descrie scopul jocului, strategii de mbuntire a performanei juctorului, tastele asociate comenzilor i semnificaia lor, tipurile de bonusuri, de montri, de nave inamice, de crmizi. Vom crea o nou fereastr de dialog prin clic dreapta pe ramura dialog din fereastr de resurse. Vom apsa meniul Insert Dialog. Va aprea un dialog standard la care vom aduga un control CRichEditCtrl pentru a afia un fiier RTF care va conine toate informaiile de ajutor. Fiierul RTF va fi creat cu WordPad sau alte editoare de RTF-uri i va fi ncrcat cu urmtoarea secven:
static DWORD CALLBACK MyStreamInCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) { CFile* pFile = (CFile*) dwCookie; *pcb = pFile->Read(pbBuff, cb); } return 0; //pointer spre controlul de tip RichEdit extern CRichEditCtrl* pmyRichEditCtrl;

178

// fisierul din care vom ncrca coninutul pt RichEdit CFile cFile(TEXT("ajutor.rtf"), CFile::modeRead); EDITSTREAM es; es.dwCookie = (DWORD) &cFile; es.pfnCallback = MyStreamInCallback; pmyRichEditCtrl->StreamIn(SF_RTF, es);

Aceast secven va fi introdus la iniializare programului. La apelare meniului de ajutor doar se va deschide fereastr, fiierul ajutor.rtf fiind deja ncrca.

5.6.5 Meniuri n limba romn


Vom accesa ramura Meniu iar de acolo IDR_MAINFRAME vom face clic pe fiecare element de meniu i-l vom redenumi.

5.6.6 Meniul scor record


Se va crea o opiune de meniu de vizualizare scoruri record i un dialog care va aprea doar atunci cnd juctorul a obinut un scor record n care acesta i va introduce numele. n fereastra de introducere a numelui va fi specificat scorul i locul ocupat n clasament alturi de caseta de editare n care i va introduce numele. Dup ce fereastra de nregistrare a scorului record va fi nchis, va aprea tabela cu scoruri record. Scorurile record vor fi citite din fiier la intrarea n joc, vor fi modificate n timpul rulrii jocului i vor fi salvate la ieirea din joc.

5.6.7 nghearea, salvarea sau ncrcarea unui joc


Odat ce toate celelalte detalii importante au fost puse la punct i jocul este funcional se va ncerca crearea unei opiuni de meniu de oprire temporar a jocului, fr a se iei din joc, ca mai apoi jocul s poat fi reluat. De aceea tot ce este n funcia timerului va fi executat doar dac pauza nu este activ. Pentru a salva un joc vom lua n considerare toate variabilele de stare pe baza crora putem reconstitui jocul de unde acesta a fost salvat, fr totui a crea un fiier de salvare supradimensionat. La ncrcarea acestuia doar setm variabilele de stare la cele specificate n fiierul de salvare i resetm engine-ul jocului. 179

Programare C++ pe obiecte

5.7 Laborator de proiect 7. 5.7.1 Testarea programelor. Beta-testing.


Jocul pare a fi pus la punct n momentul de fa, i totui treaba nu este terminat trebuie s l testm, ceea ce n englez se cheam beta - testing. nainte de a supune jocul acestei testri nu aveam dect o variant beta. Vom vedea dac putem face fa standardelor cerute de jocul pe care l jucm, vom observ c sunt momente n care jocul dei funcioneaz corect este foarte greu de parcurs n lipsa unui antrenament susinut. Totui proiectul nu-i propune ca cei care lau creat s fie i buni - juctori ai jocului creat, de aceea vom recurge la triare prin introducere n codul jocului de bonusuri, viei infinite, invulnerabilitate, ncetinirea micrilor mingii, sau montrilor toate disponibile la tastarea unui cuvnt cheie. Astfel putem parcurge cap coad toate nivelele (nivelul) jocului depistnd defectele (bug-urile) care s-au strecurat n programarea jocului. Niciodat nu este prea trziu s se corecteze un defect, dar se urmrete ca prin beta-testing acestea s fie ct mai reduse. Cea mai frecvent eroare fatal este c s-a uitat s se aloce memorie pentru un pointer, sau acestui pointer nu i s-a specificat o zon de memorie alocat. O alt eroare este c n explorarea unui vector indexul s-a deplasat nafara zonei alocate acestuia. Alt eroare ar fi c s-a uitat un fiier deschis, sau c s-a apelat un fiier ce nu a fost deschis. Pot apare i erori specifice claselor cum ar fi accesul la membrii unei clase, dar aceste sunt de obicei semnalate de compilator. Alte erori de funcionare ar fi c varibilele nu au fost iniializate corect, sau au fost dar doar la o singur apelare a secvenei, la urmtoare fiind luate valorile precedente. Lista de erori ar putea continua, i aici vorbesc de erori care las programul s mearg pn n momentul n care seciunea incorect sau corect este apelat cu nite parametri coreci sau incoreci i se iese forat din joc sau mai mult se produce o cdere a sistemului i este nevoie resetarea calculatorului.

5.7.2 Direcii de dezvoltare


Dac un joc are succes la public sau pentru a avea mai mult succes la public atunci se dorete mbuntirea lui, nu att a engine-ului ct a elementelor de joc. Se caut o diversificare a elementelor de joc,o mbogire a scenariilor, o grafic mai bun, un IA mai performant i mai eficient. De obicei se pune mai puin accent pe grafic sau pe sunet i mai mult pe ideile vehiculate i atmosfera creat de joc, dac acestea sunt bune atunci se merit s se mbunteasc grafic, dac din start sunt perimate sau nefuncionale cel puin nu se lucreaz degeaba la creaia artistic. Uneori se practic i o grafic mai bun pentru jocuri btrne ceea ce uneori are succes. Cele mai multe jocuri de astzi permit jocul n echip, ceea ce a nceput s fie o trstur de baz pentru jocurile care se respect. Pentru jocurile din cadrul proiectului se pot sugera multe direcii de dezvoltare dac s-a luat n serios studierea ludografiei pentru acel joc. O serie de idei ar fi: 180

Pentru jocul de tenis crmizile s fie de mai multe tipuri, s apar bonusuri la spargerea unei crmizi, un bonus s permit micare mai repede a paletei,un bonus s permit ca paleta s poat mpuca crmizile,altul se permit generarea mai multor mingi, altul s genereze mingi care sa aib alte tipuri de efecte distructive, n funcie de tipul mingii crmizile s fie distruse ntr-un anumit fel. Pentru jocul de tetris se poate mbunti aspectul grafic al blocurilor de la simple conglomerate rectangulare la diferite aspecte stilizate, dispariia unui rnd complet de crmizi s fie nsoit de un efect grafic special. Pentru jocul de Dyna s fie introduse bonusurile, s fie mai multe tipuri bombe, unele bonusuri s pun la dispoziie i pistoale omuleului cu care doar s imobilizeze, s rneasc montri, sau s-i distrug, s se creeze specii de montri mai inteligeni. Pentru Shooter s se introduc nave inamice care s atace nava juctorului, s se introduc bonusurile, pentru mbuntirea armelor navei, a sistemelor de propulsie, a scutului.

5.7.3 Concluzii. Utilitatea proiectului.


S-a dorit ca crearea unei aplicaii de tip joc s fac mai atractiv proiectul. Dei proiectul a fost un joc, creare jocului nu a fost o joac. S-a pus accentul pe lucrul n echip, dar i pe studiul individual. Cu ocazia aceasta s-a creat un stil de lucru, un mod de abordare a unui limbaj de programare din perspectiva unei finaliti practice. Lucrrile de laborator au urmrit s ghideze studentul nu s-i ofere o soluie complet sau definitiv. Studentului i s-au sugerat anumite soluii i s-au trasat anumite etape obligatorii pe care trebuie s le parcurg ca n final s obin o aplicaie funcional dar i cu aspect comercial i chiar profesional. S-a dorit ca aceasta s fie un punct de pornire pentru viitori programatori profesioniti sau doar o mbuntire a stilului de programare sau un simplu exerciiu pentru cine stpnete arta programrii unei aplicaii serioase.

181

6 BIBLIOGRAFIE
1. Dr.Kris Jamsa & Lars Klander, Totul despre C i C++, Teora, Bucureti, 2003; 2. Herbert Schildt,C++ manual complet , Herbert Schildt, Teora, 2002; 3. Ivor Horton,Begining Visual C++ 2005, Wiley Publishing,Inc. , 2006 4. Jon Bates & Tim Tompkins, Utilizare Visual C++ 6 , Teora, Bucureti, 2001; 5. Mircea Dorin Popovici & Mircea Ioan Popovici, C++ Tehnologia orientat spre obiecte Aplicaii, Teora, Bucureti, 2002; 6. Stephen Prata, Manual de programare n C++, Teora, Bucureti, 2001; 7. www.cplusplus.com 8. http://msdn2.microsoft.com/en-us/visualc/default.aspx 9. http://gcc.gnu.org/ 10. www.parashift.com/c++-faq-lite 11. www.faqs.org/faqs/C++-faq/ 12 . www.codeguru.com/forum/ 13. www.freeprogrammingresources.com/cforum.html 14. www.codeproject.com/cpp/cppforumfaq.asp

182

1 2

CONCEPTE GENERALE 3
1.1 Introducere...................................................................................... 3 1.2 Caracteristicile unui limbaj orientat pe obiect.................................. 7

PROGRAMARE ORIENTAT PE OBIECTE N C++ 8


2.1 Clase i obiecte............................................................................... 8 2.2 Clase derivate ............................................................................... 11 2.3 Utilizarea variabilelor globale sau a funciilor globale ................... 12 n definirea funciilor membre a unor clase......................................... 12 2.4 Funcii inline .................................................................................. 14 2.5 Functii de tipul prieten friend........................................................ 15 2.6 Constructori i destructori ............................................................. 16 2.7 Referine ....................................................................................... 20 2.8 Membrii statici ai unei clase .......................................................... 21 2.9 Sistemul de I/E din C++ ................................................................ 21 2.10 Utilizarea funciilor width(), precision() i fill().............................. 25 2.11 Suprancrcarea funciilor i operatorilor .................................... 26 2.12 Funcie operator .......................................................................... 26 2.13 Suprancrcarea operatorilor << i >> ........................................ 31 2.14 Definirea de manipulatori personalizai ....................................... 33 2.15 Lucrul cu fiierele n C++ ............................................................ 35 2.16 Prelucrare binar a fiierelor ....................................................... 36 2.17 Lucrul aleatoriu cu fiierele ......................................................... 37 2.18 Cuvntul cheie this...................................................................... 38 2.19 Prevenirea redeclarrii claselor................................................... 39 2.20 Tehnici de creare i iniializare a obiectelor ............................... 40 2.21 Elemente despre preprocesare................................................... 41 2.22 Directive de compilare condiionat ............................................ 42 2.23 Prevenirea redeclarrii claselor................................................... 43

PROGRAMAREA N VISUAL C++

44

3.1 Crearea unui proiect ..................................................................... 44 3.2 Fereastra interfeei cu utilizatorul.................................................. 44 3.3 Efectuarea compilrii i a editrii de legturi ................................ 48 3.4 Modificarea interfeei aplicaiei...................................................... 50 3.5 Asocierea de cod cu interfaa ....................................................... 54 3.6 Salvarea i nchiderea proiectului ................................................. 58 3.7 Utilizarea mediului Deweloper Studio ........................................... 59 3.8 Personalizarea mediului Developer Studio ................................... 59 3.9 Deschiderea unui proiect existent................................................. 59 3.10 Fereastra spaiului de lucru ai proiectului.................................... 61 3.11 Lucrul cu reprezentarea claselor................................................. 61 3.12 Resurse Visual C++ .................................................................... 68 3.13 Tipuri de resurse ......................................................................... 69 3.14 Utilizarea controalelor ................................................................. 73

183

3.15 Lucrul cu imagini n Visual C++................................................... 77 3.16 Lucrul cu fiiere n Visual C++ .................................................... 81 3.17 Elemente de grafic n Visual C++.............................................. 86

LUCRRI DE LABORATOR

101

4.1 Lucrarea de laborator 1............................................................... 101 4.2 Lucrarea de laborator 2............................................................... 108 4.3 Lucrarea de laborator 3............................................................... 114 4.4 Lucrarea de laborator 4............................................................... 121 4.5 Lucrarea de laborator 5............................................................... 133 4.6 Lucrarea de laborator 6............................................................... 139 4.7 Lucrarea de laborator 7............................................................... 147

NDRUMAR DE PROIECT 155


5.1 Laborator de proiect 1................................................................. 155 5.2 Laborator de proiect 2................................................................. 157 5.3 Laborator de proiect 3................................................................. 161 5.4 Laborator de proiect 4................................................................. 165 5.6 Laborator de proiect 6................................................................. 177 5.7 Laborator de proiect 7................................................................. 180

BIBLIOGRAFIE

182

184

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