+ All Categories
Home > Documents > Medii de proiectare si programare

Medii de proiectare si programare

Date post: 08-Jun-2015
Category:
Upload: claud4you
View: 1,102 times
Download: 8 times
Share this document with a friend
53
MPP – CURS 1 1.Elemente de baza ale POO (Programare orientata pe obiecte) 2.Interfata GUI WIN 32 API (Graphical User Interface) 3.Microsoft Fondation Classes 4.Appwizard 5.Butoane, etichete, casete de editare 6.Controale de tip lista 7.Casete de dialog modale si nemodale 8.Utilizarea claselor de fisiere secventiale 9.Programarea aplicatiilor SDI (Single Document Interface) 10.Date persistente 11.Procese si fire de executie in SO (sistemul de operare) 12.Accesul la BD (baza de date) 1.Elemente de baza ale POO Evolutia in timp a calculatoarelor si a problemelor de programare a permis trecerea de la tehnica programarii structurale la tehnica programarii obiect. De asemenea, odata cu acceptarea beneficiilor aduse de Interfata Grafica (GUI) a S.O. Microsoft Windows, programarea pentru acest mediu a devenit foarte importanta. Programarea pentru Windows este diferita de cea orientata pe tranzactii. O diferenta esentiala intre cele doua este ca un program rulat sub Windows proceseaza informatiile utilizatorului cu ajutorul mesajului de la S.O., pe cand un program MS-DOS foloseste S.O. pentru a furniza informatiile. Limbajul de programare Visual C++ produs de firma Microsoft este un limbaj textual, ce foloseste un program de construit interfete grafice pentru a usura munca programatorului in scopul crearii de interfete coerente. Utilizarea acestui mediu de programare prezinta o serie de avantaje , cum ar fi: - posibilitatea de creare de programe in diferite limbaje, care sa interactioneze intre ele 1
Transcript
Page 1: Medii de proiectare si programare

MPP – CURS 1

1.Elemente de baza ale POO (Programare orientata pe obiecte) 2.Interfata GUI WIN 32 API (Graphical User Interface)3.Microsoft Fondation Classes4.Appwizard5.Butoane, etichete, casete de editare6.Controale de tip lista7.Casete de dialog modale si nemodale8.Utilizarea claselor de fisiere secventiale9.Programarea aplicatiilor SDI (Single Document Interface)10.Date persistente11.Procese si fire de executie in SO (sistemul de operare)12.Accesul la BD (baza de date)

1.Elemente de baza ale POO

Evolutia in timp a calculatoarelor si a problemelor de programare a permis trecerea de la tehnica programarii structurale la tehnica programarii obiect. De asemenea, odata cu acceptarea beneficiilor aduse de Interfata Grafica (GUI) a S.O. Microsoft Windows, programarea pentru acest mediu a devenit foarte importanta. Programarea pentru Windows este diferita de cea orientata pe tranzactii. O diferenta esentiala intre cele doua este ca un program rulat sub Windows proceseaza informatiile utilizatorului cu ajutorul mesajului de la S.O., pe cand un program MS-DOS foloseste S.O. pentru a furniza informatiile. Limbajul de programare Visual C++ produs de firma Microsoft este un limbaj textual, ce foloseste un program de construit interfete grafice pentru a usura munca programatorului in scopul crearii de interfete coerente. Utilizarea acestui mediu de programare prezinta o serie de avantaje, cum ar fi:

- posibilitatea de creare de programe in diferite limbaje, care sa interactioneze intre ele - utilizarea unor obiecte native Windows, ceea ce duce la crearea unor programe executabile de dimensiuni relativ mici - posibilitatea utilizarii de biblioteci complexe ce pun la dispozitia programatorului metode de rezolvare a marii majoritati a programelor - posibilitatea utilizarii de programe „vrajitor” (wizard) care ghideaza programatorul in realizarea programelor.

Visual C++ include o colectie mare si elaborata de unelte de dezvoltare software, toate folosite printr-o interfata de ferestre. -- Microsoft Fondation Classes -MFC- este o biblioteca de clase C++ ce usureaza crearea de aplicatii Windows. -- Appwizard este un generator de cod ce creaza un schelet optional de aplicatii Windows cu trasaturi nume de clase si nume de surse de cod; ajuta la programarea rapida a unei aplicatii.

1

Page 2: Medii de proiectare si programare

ClassWizard este un program ce genereaza cod pentru o noua clasa sau functie. Scrie prototipurile, corpurile functiilor si codul pentru a conecta mesajul de scheletul aplicatiei. HppStudio este un editor de meniuri si cutii de dialog in format „what you see is what you get!”. In Visual C++, orice program executabil rezulta in urma compilarii si editarii legaturilor in cadrul unui proiect. Un proiect este o entitate constituita din mai multe fisiere header, sursa de resurse etc. care contin toate informatiile necesare generarii programului executabil. Acesta va rezulta ca un fisier cu acelasi nume ca numele proiectului.

O alta notiune nou introdusa de meniul de programe este spatiul de lucru (work space). Acesta este constituit din totalitatea fisierelor, dispozitivelor etc, puse la dispozitia programatorului in cadrul ferestrei Visual C++ , pentru a-l ajuta la crearea programului. Spatiul de lucru este salvat intr-un fisier cu extensia .dsw, iar informatiile din acesta reconstituie in mod identic spatiul de lucru la orice noua accesare. In mod normal, fiecare spatiu de lucru are in interiorul lui un singur proiect , dar pot fi adaugate mai multe proiecte la acelasi spatiu de lucru. Referitor la P.O.O apare ideea introducerii unui nou tip, care incapsuleaza o structura de date si un set de functii de interfata care actioneaza asupra datelor din structura. In plus, noul tip trebuie sa asigure diferitele niveluri de acces la date, astfel incat anumite date sa nu poate fi accesate decat prin intermediul unor functii de interfata, si nu in mod direct. Acest nou tip este denumit clasa. In limbajul C++, clasele se obtin prin completarea structurilor uzuale din limbajul C cu setul de functii necesare implementarii interfetei obiectului. Aceste functii poarta denumirea de metode. Pentru realizarea izolarii reprezentarii interne de restul programului, fiecarui membru i se asociaza nivelul de incapsulare PUBLIC sau PRIVATE. Un membru PUBLIC corespunde, din punct de vedere al nivelului de accesibilitate, membrilor structurilor din limbajul C. El poate fi accesat din orice punct al programului fara sa se impuna o restrictie asupra lui. Membrii PRIVATE sunt accesibili doar in domeniul clasei, adica in clasa propriu-zisa si in toate functiile membre. Un membru privat al unei clase poate fi accesat si din afara clasei prin intermediul unei functii „prietene” – se va folosi cuvantul cheie FRIEND. Sintaxa folosita pentru declararea unei clase este:

class NumeClasa{[[private] lista_membri_1;][[public] lista_membri_2;]

}; Cuvantul cheie clasa indica faptul ca urmeaza descrierea unei clase avand numele NumeClasa. Numele clasei poate fi orice identificator, dar trebuie sa fie unic in cadrul domeniului de existenta respectiv. Declaratia clasei consta din cele doua liste de membri, prefixate eventual de cuvintele cheie PRIVATE si PUBLIC. Daca in declaratia unei clase apare o lista de membri fara nici un specificator de acces, acestia vor fi implicit PRIVATE. O variabila de tipul clasei poarta denumirea de obiect, iar declararea ei constituie o instantiere (concretizare) a clasei respective. Desi o clasa este un tip de date care descrie un ansamblu de obiecte cu aceeasi structura si acelasi comportament, atunci cand intr-un program se face un apel de functie, mecanismul de funtionare este urmatorul:

2

Page 3: Medii de proiectare si programare

- la intalnirea unui apel de functie se salveaza in stiva, adresa din memorie a urmatoarei instructiuni executabile, precum si valorile parametrilor functiei - se sare din secventa normala de instructiuni si se executa prima instructiune din functia aflata la o adresa cunoscuta din memorie - se executa toate instructiunile functiei, iar la sfarsit se extrage din stiva adresa urmatoarei instructiuni executabile din programul apelant, apoi se continua executia normala a programului. Acest mecanism asigura o dimensiune redusa a codului executabil pentru ca toate codurile executabile asociate functiilor vor aparea o singura data in cadrul programului, dar fiecare apel de functie presupune respectarea mecanismului descris. Fiecare operatie dureaza un interval de timp, timp care poate fi chiar mai mare decat timpul de executie al codului functiei apelate daca acesta este scurt. De aceea, in cadrul functiilor cu putine instructiuni, acestea pot fi declarate inline. In acest caz, nu se mai genereaza un apel normal al functiei cu tot mecanismul aferent, ci pur si simplu codul functiei este inserat in locul in care aceasta a fost apelata. Se obtine astfel un cod executabil mai lung, dar timpul de executie al programului este scurtat. Decizia declararii unei functii inline apartine utilizatorului. Aceasta decizie depinde de scopul urmarit , fie un cod executabil mai redus ca dimensiune, fie un timp de executie mai scurt. In momentul definirii unei functii, pe langa numele ei ar trebui precizat compilatorului si clasa din care aceasta face parte. Astfel, functii cu acelasi nume dar apartinand unor clase diferite vor putea fi identificate corect de catre compilator. Prin adaugarea numelui clasei la multe functii, se obtine numele complet sau numele calificat al functiei. Adaugarea numelui clasei se face cu ajutorul operatorului : : , numit si operator de domeniu. Prin folosirea cuvantului cheie STATIC se poate declara o variabila statica. Aceasta este un atribut propriu clasei si nu fiecarui obiect in parte. Daca pentru o variabila obisnuita , in cadrul declararii fiecarui obiect se rezerva cate o zona de memorie de dimensiune SIZEOF(...), o variabila statica are o unica zona de rezervare. Ea apare ca o zona de memorie comuna tuturor obiectelor si exista chiar daca nu a fost declarat nici un obiect din clasa respectiva. Variabila statica trebuie initializata si nu este vizibila decat in interiorul fisierului in care a fost declarata. Asa cum la declararea unei variabile de un anumit tip se rezerva in memorie o zona de dimensiune sizeof(tip) pentru sortarea valorilor variabilei, si in cazul obiectelor trebuie rezervata o zona de memorie pentru stocarea valorii structurii de date ce compune clasa. Aceasta rezervare este facuta de o functie speciala, numita constructor. Constructorul unei clase este generat implicit de compilator, dar poate fi redefinit de catre programator. Un constructor este o functie care are acelasi nume ca si clasa din care face parte . Spre deosebire de o functie obisnuita, un constructor nu returneaza nici o valoare. Rolul lui este de a initializa un obiect. O clasa poate avea mai multi constructori care difera intre ei prin semnatura (lista parametri formali). Ca si in cazul unei functii obisnuite, unii parametri pot fi specificati implicit. Un constructor trebuie sa fie intotdeauna public, deoarece, in caz contrar, la declararea unui obiect in afara clasei, el nu va fi accesibil. O problema importanta apare in cazul claselor care contin membri de tip pointer, pentru care trebuie alocata dinamic memoria. Aceasta operatie este efectuata de obicei in constructorul clasei. Alocarea dinamica a memoriei se poate face folosind functia malloc() sau operatorul new. Eliberarea zonei de memorie

3

Page 4: Medii de proiectare si programare

alocata dinamic se poate face prin intermediul unei functii speciale, numite destructor. O clasa poate declara destructor care este apelat automat de compilator in momentul distrugerii obiectului din acea clasa. Functia destructor nu returneaza nici o valoare, iar numele ei este alcatuit cu constructia: ~nume_clasa. Destructorul nu primeste nici un parametru. O clasa poate avea un singur destructor. De obicei, rolul destructorului este de a dealoca memoria alocata dinamic in constructor. Pentru eliberarea memoriei alocate se poate folosi functia free() sau operatorul delete. Constructorul de copiere este o functie cu acelasi nume cu cel al clasei care primeste ca argument o referinta la un obiect de tipul clasei. Constructorul de copiere nu face altceva decat sa rezerve memorie pentru structura de date a celui de-al doilea obiect si apoi sa copieze bit cu bit valorile din primul obiect in cel de-al doilea obiect. Daca structura de date a clasei contine pointeri ce aloca dinamic memorie, atunci constructorul de copiere trebuie declarat explicit. O facilitate extrem de puternica a limbajului C++ este dreptul programatorului de a adauga operatorilor limbajului si alte sensuri decat cele predefinite. Este vorba, deci, de o redefinire a operatorilor limbajului C++ fara a se pierde vechile sensuri. Termenul consacrat in literatura de specialitate pentru aceasta operatiune este de overloading operators. Predefinirea operatorilor sau supraincarcarea lor se poate face in doua moduri: fie sub forma de functii membre, fie ca si functii privat. Redefinirea unui operator presupune declararea unei functii al carei nume este alcatuit din cuvantul cheie operator, un spatiu si simbolul operator redefinit.

Unii dintre operatori (new, delete, [], (), =) necesita precautii suplimentare in cazul redefinirii lor. Dintre acestia cel mai des intalnit este operatorul ‘=’. Daca o clasa nu redefineste operatorul ‘=’ compilatorul ataseaza clasei respective un operator ‘=’ implicit care efectueaza o copie bit cu bit a operandului din dreapta in operandul din stanga. Situatia este identica cu cea in care se genereaza un constructor de copiere implicit. Daca clasa contine membrii de tip pointer se ajunge la situatia in care doi pointeri se incarca cu adresa aceleiasi zone de memorie, care poate avea efecte foarte neplacute daca se elibereaza unul din pointeri si apoi se acceseaza memoria prin cel de-al doilea pointer. De aceea se recomanda redefinirea operatorului ‘=’ doar in cazul claselor care nu au membri de tip pointer.

MOSTENIRE

In C++ se poate stabili o ierarhie de clase astfel incat acestea sa se afle intr-o relatie de mostenire. O clasa poate fi derivata din alta clasa mestenindu-i atributele si metodele, putand adauga in plus altele noi. Clasa de la care se mosteneste se numeste clasa de baza sau superclasa, iar clasa care deriva se numeste clasa derivata sau subclasa.. O subclasa poate fi derivata din clasa de baza in mod public sau privat (in functie de specificatorul de acces folosit-public sau private). Sintaxa in declararea unei clase derivate:

4

Page 5: Medii de proiectare si programare

Class nume_clasa[:private/public Nume_cls_de_baza] { [private: lista_param_privati] [public: lista_param_publici] }; Un membru protejat al clasei de baza este accesibil ca si un membru public dintr-o clasa derivata. Deosebirea dintre mostenirea publica si privata consta in:

1.un obiect al unei clase derivate public pastreaza tipul de acces al membrilor mosteniti din clasa de baza in mod identic

2.un obiect al unei clase derivate privat transforma toti membrii mosteniti din clasa de baza in membri privati. Regulile privind modalitatile de apel si ordinea constructorilor si destructorilor in cadrul mostenirii sunt:

-in cazul constructorilor se apeleaza mai intai constructorul clasei de baza si apoi constructorul clasei derivate; apelarea constructorului clasei de baza se face in mod implicit daca este posibil si daca constructorul clasei de baza nu este apelat explicit in clasa derivata.

-in cazul destructorului se apeleaza mai intai destructorul clasei derivate si apoi destructorul clasei de baza Orice conversie de la superclasa la subclasa trebuie facuta in mod explicit. In cazul conversiei de la subclasa la superclasa avem cazurile:

1. implicit, daca mostenirea e publica2. explicit, daca mostenirea e de tip ‘private’.

O alta observatie e aceea ca un pointer la o clasa de baza poate pastra adresa oricarei instantieri a unei clase derivate ‘public’. Astfel avand un sir de pointeri la obiecte ale clasei de baza inseamna ca unii dintre acesti pointeri pot referi de fapt obiecte de clase derivate public din aceasta, adica tabloul de pointeri este neomogen. Un astfel de tablou neomogen se numeste tablou eterogen. Limbajul C++ aduce un mecanism extrem de puternic de tratare intr-o maniera uniforma a tablourilor eterogene si anume functii virtuale. O functie virtuala e o functie prefixata de cuvantul cheie ‘virtual’ atunci cand e declarata in clasa de baza. Aceasta functie e redeclarata in clasa derivata (cu aceeasi semnatura= aceeasi lista de parametri formali, acelasi nume )si prefixata de ‘virtual’. Comportamentul diferit al unei functii cu acelasi nume pentru obiecte din superclasa respectiv din clasa derivata se numeste polimorfism. In C++ polimorfismul este implementat prin functii virtuale. O functie o data declarata trebuie sa fie si redefinita , in caz contrar compilatorul da eroare. Exista situatii in crearea unei ierarhii de clase in care este util sa se declare ca si superclase, clase generice care nu implementeaza anumite operatiuni ci doar le declara urmand a fi implementate in clasele derivate. Aceasta se realizeaza folosind functii virtuale pure. Aceasta nu reprezinta o initializare ci denota caracterul virtual pur al functiei. O clasa care contine cel putin o functie virtuala pura se numeste clasa abstracta.

5

Page 6: Medii de proiectare si programare

Clase abstracte. Funcţii virtuale pure

Am învăţat până acuma că o funcţie o dată declarată va trebui să fie şi definită, în caz contrar compilatorul generează o eroare. Există uneori situaţii în crearea unei ierarhii de clase, în care este util să declarăm ca şi superclase clase generice, care nu implementează anumite operaţiuni, ci doar le declară (descriu), urmând a fi implementate în clasele derivate. Aceasta se realizează folosind funcţiile virtuale pure, care este un alt concept specific limbajului C++. Pentru o funcţie virtuală pură, declaraţia este urmată de =0; Aceasta nu înseamnă o iniţializare, ci specifică caracterul virtual pur al funcţiei.

O clasă care conţine cel puţin o funcţie virtuală pură se numeşte clasă abstractă . Ea nu poate fi instanţiată, deci nu se pot declara obiecte de această clasă, datorită faptului că ea nu furnizează implementarea metodei virtuale pure!

Posibile intrebari:1. in ce situatii e utila declararea unei functii inline?2. in ce conditii poate fi apelat din afara clasei un membru private?3. cand trebuie utilizat numele calificat pentru definirea unei functii membru al unei

clase?4. ce deosebire e intre o variabila statica si una nestatica in declararea unei clase?5. in ce situatii functiile trebuie declarate virutale?

Cand o functie virtuala poate fi declarata dar nu si implementata?

2. INTERFATA WIN32 API

Acronimul API e o abreviere pentru Application Programming Interface. WINDOWS API e un set de functii oferit de sistemul de operare Windows pentru manipularea resurselor calculatorului. Orice sistem de operare ofera sau exporta un set de astfel de functii pentru a fi utilizate de programatori in dezvoltarea de aplicatii specifice acelui sistem de operare. Denumirea de WIN32 API se refera la sistemele de operare pe 32 de biti. Functiile din interfata WIN32 API sunt impartite in mai multe sectiuni. Cele mai importante sunt:-User Interface Services-Windows Base Services

2.1. Câteva deosebiri între programele DOS şi programele Windows Un program DOS si un program Windows sunt usor de deosebit in timpul

executiei. Un program Windows va genera interfata de intrare/iesire intr-o fereastra prin intermediul unor controale adecvate pe cand un program DOS va genera o interfata intrare/iesire standard.

6

Page 7: Medii de proiectare si programare

Cu toate ca fundamental programarea in C++ sub Windows si sub DOS e aceeasi, diferentele dintre programele implementate sub cele 2 sisteme de operare sunt mai multe:

- in DOS pointerii erau marimi reprezentate pe 16 biti, adica prin intermediul unui pointer se putea accesa un spatiu de memorie de max 16 biti; datorita faptului ca sistemul de operare DOS imparte memoria calculatorului in segmente de cate 64 (de biti cred). In Windows nu mai exista segmentarea memoriei. Adresele sunt implicit pe 32 de biti , deci si pointerii sunt reprezentati pe 32 biti.

- DOS e un sistem de operare monotasking adica la un moment dat poate rula un singur program; Windows e multitask, adica mai multe programe se afla in executie simultan; deci in memoria calculatorului sunt incarcate simultan mai multe programe, fiecare avand binedefinit spatiul propriu de adrese.

- Windows e un sistem de operare bazat pe interfete grafice.- In DOS intrarile si iesirile din program sunt sincrone cu desfasurarea

lor, adica se pot introduce date doar atunci cand programul executa instructiuni de citire, respectiv se pot afisa date doar atunci cand programul executa operatii de afisare.

- In Windows pe langa intrarile/iesirile sincrone un program poate prelua si respectiv afisa date si asincron, in momentul producerii unui eveniment; prin eveniment se intelege orice modificare in starea programului(actiuni ale utilizatorului, comenzi ale sistemului de operare, scurgerea unui interval de timp, modificarea unor valori, unor marimi fanion)

2.2 Tipuri de date noi folosite de funcţiile Win32 API Datorita diferentelor dintre sistemul de operare Windows si DOS, WIN32 API utilizeaza o serie de tipuri de date noi, cum ar fi:

- Handle- tip generic utilizat pentru manipularea obiectelor folosite in program(fisier, ferestre, etc)

- Hwnd (Handle Window)- definit ca typedef Handle Hwnd si e folosit pentru manipularea ferestrelor

- Dword (Double Word)- este un intreg fara semn pe 32 de biti- Lpvoid(Long pointer void)- se defineste typedef void* Lpvoid fiind un

pointer void reprezentat pe 32 de biti- Lpcstr(Long pointer constant string)- reprezinta un pointer pe 32 de

biti spre un sir de caractere constant- Lpctstr(Long pointer constant to String) –pointer pe 32 biti spre un sir

de caractere constant de tip unicode(=cod de caractere pe 16 biti capabil sa reprezinte caracterele tuturor liniilor)

- Lptstr(Long pointer string)- pointer pe 32 de biti in format ASCII- Wparam, Lparam- cuvinte cu lungimea de 32 de biti utilizate pentru a

transmite parametri asociati unui mesaj Windows.- Lresult- valoare pe 32 biti returnata de o functie

7

Page 8: Medii de proiectare si programare

2.3 Ferestre

O fereastra este elementul fundamental pe baza caruia se construieste orice interfata grafica utilizator. Interfata sistemul de operare Windows e bazata pe ferestre. Majoritatea aplicatiilor Windows au o fereastra principala in care ruleaza. O fereastra tipica are 7 elemente de baza:

1. cadrul fereastra(Windows Frame, Main Frame)- zona activa care margineste fereastra si permite redimensionarea

2. bara de titlu(Title Bar)- afiseaza tipul aplicatiei si eventual denumirea decumentului descris pentru prelucrare e o zona activa care permite mutarea ferestrei pe ecran, contine butoanele minimize, maximize si close

3. butoanele de minimizare, maximizare si inchidere apar in bara de titlu4. bara de meniu(Menu Bar)- continuta de bara de titlu in partea stanga; contine

1-n meniuri pe baza carora se implementeaza diferite functii ale prg.5. bara de defilare(Scroll Bar)- permite utilizatorului defilarea sus-jos, dreapta-

stanga in cadrul ferestrei6. bara de stare(Status Bar)- ofera utilizatorului informatii specifice din prg.7. zona client a ferestrei(client Area)- zona pusa la dispozitie pentru aplicatia ce

ruleaza in fereastra respective.

La un moment dat o singura fereastra poate fi activa. O fereastra care e activa primeste focusul, adica poate receptiona evenimentele produse la tastatura. Se disting doua tipuri de ferestre: - top-level sau

- child Ferestrele top-level sunt ferestrele principale in care ruleaza o aplicatie. Ferestrele child: ex: butoanele si alte elemente de control dintr-o caseta de dialog sunt ferestre copil ale casetei de dialog.

8

Page 9: Medii de proiectare si programare

O fereastra e unic identificata in sistem printr-un identificator (variabila de tipul Hwnd). Acest identificator se obtine in urma apelarii functiei API CreateWindow().

2.4 Mesaje Windows. Tratarea evenimentelor asincrone

Orice eveniment asincron (scurgerea unui interval de timp, apasarea unei taste, mutarea mouse-ului etc.) este receptionat de catre sistemul de operare Windows si este transferat intr-un mesaj. Acest mesaj este transmis apoi fie catre sistemul de operare, fie catre programul caruia ii este destinat pentru a se executa o actiune in concordanta cu evenimentul produs.

In momentul primirii unui mesaj Windows programul caruia ii este destinat trebuie sa identifice mesajul si sa execute secvente de instructiuni corespunzatoare. Deci, o functie foarte importanta intr-un program este aceea care accepta si prelucreaza mesajele transmise de sistemul de operare.

Pentru ferestrele clasice aceasta functie este o functie speciala numita procedura fereastra. In functie de mesajul primit functia va executa prelucrarile corespunzatoare de obicei prin intermediul unui selector switch. Fereastra pe care o asociaza unui program nu este in general unica. Ea este creata pe baza unor sabloane la fel, cu mai multe ferestre care pot avea aceleasi caracteristici (dimensiune, stare initiala, daca se pot redimensiona sau nu etc.). Se spune ca un grup de astfel de ferestre formeaza o clasa de ferestre. O clasa de ferestre poate fi considerata un sablon pe baza caruia se creaza apoi ferestre.

Pentru a putea folosi o clasa de ferestre este necesara inregistrarea ei cu ajutorul functiei API RegisterClass(). La inregistrarea unei clase de ferestre se specifica printre alte caracteristici si procedura fereastra care se va folosi de catre ferestrele din clasa respectiva.

Pentru a executa un program sub Windows trebuie mai intai creata o fereastra. Crearea unei ferestre se face cu ajutorul functiei CreateWindow(). Daca crearea ferestrei este reusita functia returneaza un identificator la fereastra respectiva. Identificatorul va fi utilizat apoi de catre orice alta operatie asupra ferestrei pentru a o identifica. Afisarea unei ferestre se face cu ajutorul functiei ShowWindow().

Evenimentele la care trebuie sa raspunda un program sub Windows, deci implicit mesajele receptionate de acesta pot apare intr-un ritm mult mai rapid decat este programul capabil sa prelucreze. Totusi, nici un mesaj nu se pierde deoarece fiecare mesaj este stocat intr-o coada de mesaje. Programul va extrage apoi mesajele din coada de mesaje si le va prelucra in mod corespunzator prin intermediul procedurii fereastra. Pentru prelucrarea mesajelor din coada de mesaje orice program Windows va trebui sa contina o bucla de mesaje care sa preia si sa proceseze mesajul.

Ca o concluzie rezulta ca pentru scrierea unui program Windows trebuie parcursi urmatorii pasi:

- declararea unei functii callback intr-un fisier header: callback(header)- declararea si definirea clasei de ferestre utilizata in fisierul sursa- crearea unei instante a acestei clase utilizand functia CreateWindow()- stabilirea starii de vizibilitate a ferestrei cu functia ShowWindow()- implementarea buclei de mesaje si implementarea procedurii ferestre

9

Page 10: Medii de proiectare si programare

2.5 Fisiere de resurse

Un program Windows pe langa fereastra principala poate contine si alte elemente (bare de instrumente, bare de stare, meniuri, diferite casete de dialog etc.). Aceste resurse nu se modifica in general in timpul executiei programului. De obicei ele sunt descrise in fisiere text speciale numite fisiere de resurse. Aceste fisiere sunt cele care au extensia rc.

Windows manipuleaza doua tipuri de meniuri:- meniuri principale (top-level menu)- meniuri derulante (pop-up menu)Meniul principal e constituit dintr-un set de comenzi vizibile permanent in bara de

meniu a ferestrei principale. In marea majoritate a cazurilor acestea reprezinta doar puncte de intrare pentru meniurile derulante. Aceste meniuri sunt desfasurate la alegerea unei optiuni din meniul principal.

2.6 Casete de dialog

Casetele de dialog sunt un alt tip de ferestre foarte des utilizate de programele Windows pentru implementarea interfetelor. Aceste casete sunt utilizate de obicei pentru a prezenta intr-o maniera unitara diferite contoare necesare introducerii si afisarii datelor.

Spre deosebire de celelalte tipuri de ferestre casetele de dialog folosesc o functie implicita de prelucrare a mesajelor de la tastatura facand mai usoara prelucrarea intrarilor furnizate de utilizator.

Casetele de dialog pot fi afisate ca si ferestrele principale a programului dar in foarte multe programe sunt folosite ca si ferestre copil lansate la alegerea unei optiuni de meniu in fereastra principala a programului. Casetele de dialog pot fi afisate in doua moduri:

- sub forma de casete modale- sub forma de casete nemodaleO caseta modala acapareaza in totalitate controlul mesajelor astfel incat

utilizatorul nu va putea face activa o alta fereastra a programului care a lansat caseta pana la deschiderea casetei modale. Utilizatorul poate insa comuta in orice alta fereastra apartinand altui program. Casetele nemodale pot primi sau pierde focusuri fara nici o problema. Spre deosebire de casetele modale ele pot fi inchise atat din interiorul lor cat si din orice alta fereastra a programului din care fac parte.

Intrebari:1.Cum se transmite o acţiune a utilizatorului către un program aflat

în execuţie? 2. Ce este un identificator? De ce tip este identificatorul unei

ferestre?

10

Page 11: Medii de proiectare si programare

3. Introducere in MFC(Microsoft Foundation Classes)

MFC este o biblioteca de clase dezvoltata de firma Microsoft in vederea usurarii programarii aplicatiilor Windows. Multe dintre clasele MFC incapsuleaza functii API dar permite utilizarea mai prietenoasa a acestora. Folosind clase din biblioteca MFC aplicatiile Windows se pot programa obiectual de o maniera mult mai simpla decat permite API. Acest fapt prezinta urmatoarele avantaje:

- creste semnificativ lizibilitatea codului, o aplicatie putand fi descifrata mult mai usor

- se simplifica programarea aplicatiei prin folosirea clasei deja implementate de MFC

- se micsoreaza semnificativ timpul de dezvoltare al unei aplicatii Windows- programatorul are posibilitatea de a se concentra numai asupra aspectelor

particulare ale aplicatiei lasand aspectele standard (clase de ferestre, proceduri fereastra etc.) in seama claselor MFC

- se pot imparti in procese de programe, programele vrajitor care usureaza munca utilizatorului:

o AppWizardo ClassWizard

Clasele introduse in biblioteca MFC sunt dispuse in mai multe categorii. Unele dintre acestea sunt:1. clase de uz general:

- pentru manipularea fisierelor: CFile- pentru manipularea sirurilor de caractere: CString- clase exceptii: CException- pentru prezentarea unor zone de pe ecran: CRet, CPoint

2. clase de obiecte vizuale- manevreaza aproape tot ce este vizibil intr-un program Windows- ex: clase de ferestre: CWind, CFrameWind meniuri: CMenu

controale: CButton, CEdit, CListBox (derivate din CWind) obiecte de desenare: CPen, CBrush

3. clase de aplicatii- in aceasta categorie intra clasele care gestioneaza obiectele de executie

(CWindThread, CWindApp) precum si clasele care implementeaza arhitectura de tip document - reprezentare (CDocument, CView)

- arhitectura Document – Reprezentare este folosita de majoritatea programelor Windows4. clase de tip colectie

11

Page 12: Medii de proiectare si programare

- se folosesc pentru stocarea obiectelor in structuri de date de tip tablou (CArray), lista (CList) sau harta (CMap)

5. clase suport OLE2- simplifica scrierea aplicatiilor care beneficiaza de OLE2 (Object Linking and

Embedding)6. clase pentru baze de date

- faciliteaza manipularea bazelor de date: CDataBase, CRecordSet, CDaoDatabase, CDaoRecordset; DAO = Data Access Object7. clase pentru dezvoltarea aplicatiilor distribuite in retea

- CAsyncSocket, CSocket (pentru deschiderea unui canal de comunicatie intre doua calculatoare)

- CFTPConnection, CHTTPConnection (pentru deschiderea unei sesiuni de lucru FTP, respectiv HTTP)

Clasele implementate in biblioteca MFC folosesc mostenirea simpla. Majoritatea claselor MFC sunt derivate direct sau indirect din clasa CObject. De asemenea, toate clasele care reprezinta ferestre sau controale de diferite tipuri sunt derivate din clasa CWind. Clasele CObject si CWind utilizeaza functii virtuale pentru implementarea polimorfismului in clase derivate. Aceasta permite obiectelor din program sa acceseze functii de uz general prin intermediul unui pointer la clasa de baza.

3.1 Scrierea unei aplicaţii simple cu MFC

De obicei la srierea unui program MFC se foloseste AppWizard, un program vrajitor care genereaza automat scheletul programului particularizat pentru aplicatia respectiva. Totusi un program MFC se poate scrie si fara a beneficia de asistenta programului vrajitor. Chiar si in acest caz este mai usor sa se scrie un program utilizand biblioteca MFC decat direct folosind functiile Windows API.

Pentru a scrie un program MFC fara a folosi un program vrajitor trebuie parcursi urmatorii pasi:

- se deschide un nou proiect de tip Win32 Application care nu contine nici un fisier (An empty project)

- din meniul Project > Settings se selecteaza Settings for all configurations, iar la tabloul General se selecteaza in caseta combinata MFC (Using MFC in a shared library)

- se introduce codul programului, se compileaza, se editeaza legaturile si se lanseaza programul in executie

3.2 Manipularea mesajelor in MFC

12

Page 13: Medii de proiectare si programare

Pentru a putea trata mesajele adresate unei ferestre este necesara definirea unei harti de mesaje. Harta de mesaje este utilizata pentru a stabili legatura intre mesajele transmise unei ferestre si functiile destinate procesarii acestor mesaje.

Declararea unei harti de mesaje se face in interiorul unei clase derivate din clasa CWind de obicei in fisierul header. Declararea hartii de mesaje se face in clasa derivata din clasa fereastra deoarece Windows trimite toate mesajele catre fereastra asociata programului aplicatie. Declararea hartii de mesaje si a functiilor de tratare a mesajelor se face in cadrul unei sectiuni protejate a claselor fereastra.

Functiile de tratare a mesajelor au semnaturi predefinite si declararea lor incepe intotdeauna cu cuvantul afx_msg. Acest cuvant semnalizeaza compilatorului faptul ca este vorba despre o functie care trateaza mesaje.

Ceea ce urmeaza dupa acest cuvant cheie este specificarea fiecarui mesaj tratat. Nu e necesara invatarea semnaturii tuturor functiilor de tratare a mesajelor. Visual C++ poseda un program vrajitor ClassWizard care permite inserarea automata a functiilor de tratare a mesajelor in cadrul unei ferestre.

Pentru folosirea ClassWizard-ului proiectele trebuie sa fi fost create/generate cu ajutorul lui AppWizard.

In general proiectele MFC se genereaza folosind AppWizard tocmai in ideea de a beneficia de suportul oferit de ClassWizard si de alte utilitare.

MFC lucreaza cu doua tipuri de functii:- functii obisnuite care pot fi functii membre ale unei clase sau functii din afara

clasei; pentru aceste functii sunt necesare urmatoarele operatii:o declararea lor de obicei in fisierul headero definirea lor de obicei in fisierul sursao apelarea functiei in cadrul programului

- functii care raspund la mesaje care se executa la transmiterea unui mesaj de catre sistemul de operare catre program.

Pentru aceste functii sunt necesare urmatoarele operatii:- declararea lor (in fisierul header) si obligatoriu ca si functie afx_msg- inserarea in harta de mesaje a macroului ON-numefunctie corespunzator

pentru a specifica programului ce mesaje sunt interceptate- definirea lor (in fisierul sursa)

Intrebare:Care este deosebirea între modul în care tratează mesajele API şi

MFC?

4.AppWizard

Am văzut în capitolele anterioare cum putem realiza interfeţele Windows pentru programele noastre. În general, această muncă este destul de laborioasă, putând uneori depăşi în complexitate chiar programul implementat. Pentru a rezolva această problemă, mediului de programare Visual C++ oferă programatorilor un program “vrăjitor”, numit AppWizard, care permite obţinerea unor programe executabile în format Windows, fără a

13

Page 14: Medii de proiectare si programare

scrie practic nici o linie de program. AppWizard oferă posibilitatea creării de interfeţe Windows fie de tip fereastră “clasică”, fie de tipul casetelor de dialog. Rolul AppWizard este de a oferi un schelet de program, pe osatura căruia să se poată construi cu ajutorul cu mouse-lui o interfaţă intrare-ieşire conform standardelor Windows. Apoi, bazat pe această interfaţă, se poate implementa codul programului de aplicaţie.

Ca o observaţie, AppWizard scuteşte de o programare laborioasă în sensul realizării interfeţelor, dar partea algoritmică a programelor trebuie scrisă în continuare de programator.

4.2 Fereastra ProjectWorkspace

- fereastra de lucru a proiectului ofera posibiliatatea vizualizarii si lucrului cu diferitele componente ale proiectului.La deschiderea unui proiect in partea de jos a ferestrei de lucru sunt disponibile 3 optiuni :

~ Class View , Recource View si File View , fiecare prezentand o structura arborescenta de componente ale proiectului ,respectiv clasele utilizate de aplicatia cuprinsa in proiect ,resursele acesteia si fisierele utilizate de proiect.

4.2.1 Reprezentarea claselor (ClassView)

In cazul selectarii etichetei Class View in fereastra de lucru a proiectului va apare structura de clase utilizate in cadrul acesteia (vectorului).Aceste clase au fost create in AppWizard in faza de initializare a proiectului ,ulterior fiind adaugate acestor clase componente in functie de actiunile intreprinse de programator.Meniul contextual asociat unei clase permite adaugarea de functii si variabile membre ale clasei respective .

Class View mai ofera si alte informatii si activitati prin intermediul meniului contextual.

4.2.2 Reprezentarea resurselor (Resource View)

In cazul selectarii etichetei Resource View vor fi afisate resursele proiectului,adica toate elementele vizuale ale acestuia.

Acestea sunt casetele,meniurile,pictogramele etc.In cadrul unui proiect pot fi inserate urmatoarele tipuri de resurse:

- tabele de acceleratori –sunt tabele ce contin asocieri intre combinatii de taste si comenzi din program ,comenzi selectabile in mod normal intr-un meniu.

- resurse bitmap: imag de dimensiune oarecare ,compuse din puncte ce pot fi colorate diferit.In general desenele din barele de unelte sunt bitmap-uri.Aceste resurse pot fi desenate sau incarcate din fisiere cu extensia .bmp.AppWizard stie sa afiseze doar resurse bitmap cu maxim 256 de culori;

- pictograme: resurse grafice dar cu dimensiuni standard sunt asociate in general anumitor componente din program;

- resurse dialog : sunt diferite tipuri de casete dialog care pot contine diferite controale;

- resurse meniuri: -meniuri obisnuite sau contextuale care permit alegerea anumitor optiuni pentru executia anumitor actiuni in program;

14

Page 15: Medii de proiectare si programare

- resurse tabele de siruri: contin siruri de caractere folosite intr-o aplicatie .Fiecare element are asociat un identificator unic,utilizat pentru a referi sirul in cadrul codului sursa.Se utililzeaza pentru traducerea usoara a tuturor mesajelor din program in alte limbi;

- bare cu instrumente: -sunt bare continand butoane asociate unor comenzi din meniu.Pot fi specificate prin informatii grafice sau alfanumerice;

- resurse versiune : -contin informatii cu privire la produsul program;

Odata cu inserarea unei noi resurse in proiect ,AppWizard ii va asocia un identificator implicit caracteristic tipului din care face parte resursa.Acest identificator poate fi utilizat implicit sau dupa dorinta programatorului.

4.2.3. Reprezentarea fişierelor In cadrul FileView ,fereastra de lucru va afisa fisierele care compun proiectul.

Fisierele sunt organizate pe cataloage in functie de tipul lor.Pentru accesarea unui

15

Page 16: Medii de proiectare si programare

fisier este suficient sa se faca dublu click .Cateva tipuri uzuale de fisiere sunt:

Extensie

Tip Descriere

.dsw Workspace conţine informaţiile conţinute pentru restaurarea spaţiu de lucru

.dsp Proiect reţine informaţiile despre proiect

.clw Class Wizard reţine informaţiile despre clasele utilizate de ClassWizard

.ncb Navigare fără compilare

conţine informaţii de navigare, utilizate de ClassView

.opt Opţiuni conţine opţiuni de personalizare a spaţiului de lucru

.cpp Sursă C++ conţine coduri sursă

.h Antet C++ conţine cod de declaraţii de clase

.rc Resource Script conţine informaţii despre resurse, cum ar fi casetele dialog, meniurile, etc.

.rc2 Resource Script conţine informaţii pentru includerea de resurse multe proiecte

.bmp Bitmap imagini bitmap

.ico Pictogramă imagini pictogramă

5. Butoane.Etichete.Casete dialog

16

Page 17: Medii de proiectare si programare

Deoarece permite utilizarea controalelor oferite de MFC , caseta de dialog e adesea utilizata ca interfata pentru programe.Crearea casetelor de dialog implica 2 etape:

- crearea machetei pentru caseta de dialog si adaugarea de controale- stabilirea legaturilor intre caseta de dialog si controalele sale si respectiv

clasele si functiile din codul C++

Pentru inserarea de controale in caseta de dialog se utilizeaza bara cu instrumente de control. Controalele dintr-o caseta pot fi accesate in serie.Aceasta serie e cunoscuta sub numele de ordine de selectare , reprezentand de fapt ordinea in care controalele primesc input focus-ul.Un control care a primit focus-ul este de obicei marcat diferit.Etichetele statice nu pot primi focusuri.

Taste de accesO tasta de acces sau un accelerator pentru un control se specifica prin inserarea

simbolului & in eticheta controlului , inainte de caracterul care va avea rol de mnemonica Mnemonica e un caracter subliniat,care poate fi utilizat ca o scurtatura pentru activarea controlului respectiv.

Exista posibilitatea ca mai multe etichete sa aiba aceeasi mnemonica.In acest caz , la apasarea mnemonicei va fi activat primul control considerand ordinea de selectare.Cel mai frecvent , tastele de acces sunt utilizate pentru facilitarea accesului la intrarile meniurilor.

Scopul in care sunt inserate controalele in caseta de dialog este de a realiza o anumita functionalitate a interfetei.Orice control inserat intr-o anumita fereastra parinte , fie ca aceasta este de clasa „CWind” sau „CDialog” este de fapt un obiect de o anumita clasa. Marea majoritate a claselor incapsulate MFC sunt derivate public direct sau indirect din clasa CObject.Oricarui control din caseta de dialog ii poate fi asociat un obiect de tipul clasei din care face parte controlul.Prin intermediul acestui obiect vor putea fi apelate toate metodele puse la dispozitie de clasa si vor fi aplicate asupra controlului . Obiectul va fi asociat ca si o variabila care e declarata in cadrul unei clase din proiect . Asocierea unui obiect cu un control se face in Class Wizard.

17

Page 18: Medii de proiectare si programare

Şi acum, să recapitulăm:

MFC manipuleaza 2 categorii de functii:- functii obisnuite ,adaugate claselor cu ajutorul meniului contextual - functii „afx_msg” care raspund la mesaje ,adaugate proiectului cu ajutorul lui

ClassWizard sau prin alte metodeMFC manipuleaza 2 categorii de variabile si anume:

- variabile obisnuite de un anumit tip sau clasa ,adaugate clasei in care exista cu ajutorul meniului contextual

- variabile mapate controalelor ,care se mapeaza cu ClassWizardAcestea pot fi la randul lor de 2 categorii:

-var de categorie : value ,care preiau valoarea continuta in control pt a putea fi manipulata de program si pt care transportul datelor e controlat de functia UpdateData

-var de categorie : control care sunt obiecte de tipul clasei controlului si prin intermediul carora se pot apela metodele clasei referinta la controlul respectiv.

ButoaneMFC pune la dispozitie programatorului 3 tipuri de butoane:- butoane de comanda- butoane radio- casete de validare

Cu toate ca cele 3 tipuri de butoane sunt obiecte din aceeasi clasa : CButton ,ele difera prin aspect si functionalitate. Butoanele de comanda sunt acele butoane la a caror apasare se executa o singura comanda -implement- in cadrul programului prin intermediul unei functii. Orice sablon caseta de dialog contine in forma initiala 2 butoane de comanda : OK si CANCEL. Butoanele radio sunt utilizate in general pentru a marca in program actiuni mutual exclusive . Casetele de validare marcheaza una sau mai multe optiuni.Spre deosebire de butonul radio , aceste optiuni nu sunt mutual exclusive , putand fi validate simultan mai multe dintre ele.

Caseta de editare Interfata de intrare cel mai des utilizata de AppWin este caseta de editare. Controalele de tip caseta de editare sunt utilizate ca controale de intrare pentru receptionarea textului de introdus , precum si ca controale de iesire pentru afisarea

18

Page 19: Medii de proiectare si programare

informatiilor .Prin efectuarea unui click cu mouse-ul in interiorul casetei aceasta va prelua implicit focus-ul putand fi introdus textul. La definirea unei casete de dialog sunt accesibile mai multe optiuni cum ar fi:

Password: maschează textul introdus, prin înlocuirea caracterelor cu *; Uppercase, Lowercase: transformă automat textul introdus în majuscule, respectiv

minuscule; Number: permite introducerea doar a caracterelor numerice; Read-only: utilizează caseta de editare doar pentru afişare. Ea este colorată la

culoarea de fond a casetei de dialog în care apare;

Ca si in cazul butoanelor ,in cazul castei de editare pot fi asociate functii de tratare a mesajelor caracteristice .Casetele contin texte,iar acestea sunt manipulate in program de clasa CString. Metodele puse la dispozitie de aceasta clasa sunt:

- operatori utilizati: „=” atribuie o valoare sau text sirului „+” returneaza un nou obiect Cstring in care sunt concatenati cei 2 operanzi Cstring implicati „+=” concateneaza sirul din dreapta operatorului la sfarsitul sirului din stanga operatorului

6. Controale de tip listă

O mare parte din mesajele afişate de interfaţa programului este reprezentată de mesajele tip listă. Astfel, pot apare liste de obiecte de inventar, liste de posibilităţi de transport, directoare sau fişiere. Modalitatea de afişare a elementelor unei liste depinde de semnificaţia acestora. MFC oferă mai multe tipuri de controale de tip listă, cu propriile caracteristici şi propriile stiluri.

Controalele de tip listă sunt oferite în 4 forme: casete combinate, casete cu listă, arbori şi respectiv controale listă. La adăugarea controalelor de tip listă, este foarte importantă selectarea proprietăţilor de stil adecvate, o alegere nefericită a acestora putând altera semnificativ aspectul listei.

6.1 Casete combinate (ComboBox)

Un control de tip casetă combinată conţine 3 controale: o casetă de editare, o casetă cu listă şi un buton. Casetele combinate realizează afişarea unei liste de opţiuni, permiţând selectarea unei singure opţiuni. Elementul selectat va fi întotdeauna vizibil, fiind afişat în partea superioară a controlului. Există trei tipuri de casete combinate:

19

Page 20: Medii de proiectare si programare

• simple – îmbină o casetă de editare şi o casetă listă. Lista este întotdeauna vizibilă şi elementul selectat este afişat în caseta de editare;

• derulante – îmbină o casetă de editare cu buton şi o casetă cu listă. Caseta cu listă este vizibilă numai la efectuarea unui click pe buton;

• liste derulante – îmbină o etichetă statică cu un buton şi o casetă cu listă. Este aproximativ similară cu caseta derulantă, dar utilizatorul nu poate introduce date în cadrul controlului;

Tipul casetei se selectează la opţiunea Styles a casetei de dialog Combo Box Properties.

6.2 Popularea casetelor combinate O casetă combinată poate fi populată manual, selectând pagina Data

de la Properties. Aici se introduc textele, iar trecerea la linie nouă se face tastând CTRL-Enter. Din păcate, această metodă nu este prea indicată. În general, caseta combinată se populează prin program, în interiorul unor funcţii asociate clasei de dialog. Funcţia care realizează popularea iniţială a casetei, este apelată în marea majoritate a cazurilor în funcţia OnInitDialog(). MFC apelează această funcţie la deschiderea casetei de dialog, înainte de afişarea ei.

Clasa CComboBox conţine mai multe metode pentru manipularea casetelor combinate, dintre care cele mai uzuale sunt prezentate mai jos:

Regăsirea fiecărui element în lista asociată casetei combinate se face pe baza unui indice asociat, asemănător tablourilor unidimensionale, primul element având indicele 0. • int GetCurSel() – returnează indicele (bazat pe 0) din lista asociată

casetei a elementului selectat cu bara luminoasă; • int GetCount() – returnează numărul de elemente din lista asociată

casetei combinate; • void GetLBText(int nIndex, CString& rString) – încarcă în şirul rString textul de

la indicele nIndex din lista asociată casetei combinate; • int AddString(LPCTSTR lpszString) – funcţia adaugă şirul de caractere

lpszString în lista asociată casetei combinate şi returnează poziţia pe care a fost inserat şirul. Dacă proprietatea Sort este validată, şirul este inserat pe poziţia corespunzătoare alfabetic, altfel este inserat la coada listei;

• int DeleteString(UINT nIndex) – şterge şirul de pe poziţia nIndex din lista asociată casetei combinate. Returnează numărul de şiruri rămase în listă;

• void ResetContent() – şterge toate şirurile de caractere din lista asociată casetei combinate;

• int SelectString(int nStartAfter, LPCTSTR lpszString) - caută şirul lpszString în lista asociată casetei combinate. Dacă îl găseşte, returnează indicele

20

Page 21: Medii de proiectare si programare

acestuia şi îl afişează în casetă. Dacă nu îl găseşte, returnează CB_ERR. nStartAfter reprezintă indicele de la care începe căutarea şirului. Dacă dorim căutarea în întreaga listă asociată casetei combinate, nStartAfter

va avea valoarea –1;

6.3 Controale de tip arbore (TreeCtrl)

Controlul arbore este utilizat pentru afişarea şi selectarea informaţiilor într-un mod ierarhic. Clasa care descrie aceste controale este CTreeCtrl.

6.4 Controale de tip casetă cu listă (ListBox)

Casetele cu liste sunt controale care conţin liste de elemente. Spre deosebire de casetele combinate şi de controalele tip arbore, care permit numai selecţia singulară, casetele cu liste permit următoarele tipuri de selecţii:

Selecţie

Descriere

Singulară (Single)

selecţia elementelor este mutual exclusivă. Poate fi selectat la un moment dat un singur element, iar selecţia lui duce la anularea selecţiei anterioare;

Multiplă (Multiple)

pot fi selectate mai multe elemente, utilizând mouse-ul în combinaţie cu Ctrl şi Shift;

Extinsă (Extended)

similar selecţiei multiple, pot fi selectate mai multe elemente, dar selecţia lor se poate face şi prin selectare cu mouse-ul, ţinând butonul stâng apăsat;

Dezactivată (None)

nu poate fi selectat nici un element;

La fel ca şi în cazul casetelor combinate, ordinea alfabetică de afişare a elementelor este selectată implicit. Pentru anularea acestei opţiuni, în pagina Styles se deselectează opţiunea Sort.

7.Controale orientate pe intervale de valori

Există numeroase situaţii când într-un program trebuie să fie permis utilizatorului să specifice o valoare cuprinsă într-un anumit interval, să definească extremităţile unui interval, sau să afişeze un indicator de evoluţie a unui proces. În cadrul MFC, există o serie de controale capabile să ofere mecanisme rapide pentru rezolvarea acestor probleme. Vom prezenta doar câteva dintre ele, în cele ce urmează.

21

Page 22: Medii de proiectare si programare

7.1 Controlul Spin (SpinControl) Controlul spin este utilizat pentru a modifica valori numerice afişate într-un alt

control, în majoritatea cazurilor acesta fiind o casetă de editare.

7.2 Controale indicator de evoluţie (Progress) Controalele indicator de evoluţie sunt utilizate uzual pentru a evidenţia stadiul de

desfăşurare a unei acţiuni de durată. Controalele de tip indicator de evoluţie apar în general sub forma unui cursor, care se deplasează sau umple interiorul unei casete.

22

Page 23: Medii de proiectare si programare

7.3 Control glisor (Slider) Controlul glisor permite utilizatorului să stabilească o valoare, prin deplasarea unui

cursor. Deplasarea se poate realiza sub controlul mouse-lui, sau prin intermediul tastelor săgeată, dacă este selectat controlul glisor.

7.4 Controale de selecţie a datei şi orei Visual C++ ofera 2 controale pentru manipularea datei si timpului care pot fi in

diferite aplicatii Microsoft cum ar fi Microsoft Outlook.Aceste controale sunt calendarul si controlul selector data-ora.

Acesta din urma atunci cand este folosit pentru alegerea unei date , apare sub forma unei casete combinate care afiseaza data in format lung sau scurt.

Un click pe butonul cu sageata va afisa un control de tip calendar.La afisarea orei se poate modifica in sus su in jos valoarea timpului.

23

Page 24: Medii de proiectare si programare

7.4.1 Controale selector dată/oră Acest tip de control permite afisarea datei si timpului in diferite formate.

Short date- seteaza controlul sa afiseze data intr-o forma prescuratata in format american, apasarea butonului sageata realizand afisarea unui calendar care permite selectarea mai exacta a dateiLong date –seteaza controlul sa afiseze data calendaristica intr-o forma detaliata , apasarea butonului sageata realizand afisarea unui calendar care pemite selectarea mai exacta a dateiTime- determina afisarea orei si a unui control de modificare incrementala in ambele sensuri care permite ajustarea orelor,min,sec sau a sufixului AM sau PM din caseta orara.

7.4.2 Control de tip calendar Pentru controlul calendar sunt accesibile urmatoarele stiluri:

Day States – validarea acestei optiuni de stil perminte specificarea din program a datei ce va fi afisata in culori inverseMulti Select – prin validarea acestei optiuni utilizatorul va avea posibiliatatea selectarii unui inteval de timp din interiorul calendarului in caz contrar,implicit poate fi selectata o singura dataNo Today Circle – daca aceasta optiune este validata fonda rosie ce apare in jurul datei curente nu mai este afisata.No Today – daca aceasta optiune este selectata,data curenta nu mai este afisata explicit in partea de jos a calendarului.Week Numbers – la validarea acestei optiuni,in stanga saptamanii afisate va apare si numarul ei in an

24

Page 25: Medii de proiectare si programare

8. Casete de dialog modale si nemodale

În marea majoritate a aplicaţiilor, o acţiune asupra butoanelor implică apariţia unor noi casete de dialog, numite casete copil, care la rândul lor vor conţine o serie de obiecte de interfaţă. Aceste casete, pot lansa apoi alte casete şi aşa mai departe.

Pentru fiecare casetă suplimentară inserată în proiect, trebuie adăugată o resursă de tip casetă de dialog şi o clasă asociată, derivată din clasa CDialog. Caseta de dialog poate fi creată prin intermediul editorului de resurse (ClassView), iar clasa derivată este creată de către ClassWizard. Noua clasă poate fi dezvoltată pentru a asigura gestiunea controalelor aflate în spaţiul noii machete.

Marea majoritate a casetelor de dialog copil sunt lansate în execuţie ca şi casete de dialog modale. La afişarea unei astfel de casete(modale), restul interfeţei cu utilizatorul devine inaccesibil, fiind necesară închiderea casetei înainte de a relua lucrul obişnuit. Casetele de dialog pot fi cascadate, astfel încât o casetă să o apeleze pe alta, determinând în acest fel transmiterea controlului către caseta de dialog cel mai recent deschisă, care este de altfel şi caseta activă. După închiderea acesteia, se redă controlul casetei de dialog apelante.

Există şi posibilitatea lansării casetelor de dialog ca şi casete de dialog nemodale, ca alternativă la casetele de dialog modale. Aceste casete permit accesul şi la restul interfeţei în timpul în care sunt afişate. În fapt, o serie de controale sunt implementate ca şi casete de dialog nemodale.

8.1 Schimbul şi validarea datelor Atunci când se mapează variabile controalelor, ClassWizard generează automat

cod pentru efectuarea schimbului de date între controale şi variabilele asociate, prin intermediul funcţiei DoDataExchange() a clasei de dialog. Orice clasă de dialog va conţine o astfel de funcţie. Ea răspunde de transferul datelor în ambele direcţii, înspre şi dinspre controalele casetei de dialog.

Procesul de transfer se numeşte schimb de date şi este iniţiat printr-un apel al funcţiei UpdateData().

Există două tipuri de funcţii pentru efectuarea transferului de date:- Funcţii pentru schimbul de date DDX (DoDataExchange()) - Funcţii pentru validare de date DDV (DoDataValidate())

8.2 Casete de dialog nemodale O casetă de dialog nemodală nu acaparează interfaţa aplicaţiei, aşa cum o face

caseta de dialog modală. Ea este afişată de obicei pentru a completa funcţionalitatea tipică a aplicaţiei prin transmiterea de mesaje către aplicaţia apelantă. Casetele de dialog nemodale sunt folosite de obicei ca bare de instrumente neflotante, permiţând utilizatorului să efectueze click pe butoanele casetei de dialog pentru a indica opţiuni privind modul de lucru sau a exprima o alegere.

25

Page 26: Medii de proiectare si programare

O casetă de dialog nemodală foloseşte ca interfaţă o casetă de dialog obişnuită, dar pentru acest tip de casetă butoanele OK şi Cancel nu mai au un rol important. Şi acest tip de casete sunt încapsulate de clase derivate din CDialog.

Diferenţele esenţiale între casetele de dialog modale şi cele nemodale se regăsesc în modul de creare şi afişare şi respectiv modul de închidere.

O casetă de dialog nemodală este creată (vă reamintiţi de la API?) prin intermediul funcţiei Create() a clasei CDialog. Această funcţie poate fi apelată fie în constructorul clasei ce încapsulează caseta de dialog părinte, astfel încât să se creeze o instanţă a casetei nemodale o dată cu instanţierea unei casete de dialog părinte, fie într-o altă funcţie, caseta nemodală fiind creată numai la apelul acestei funcţii. Funcţia Create() primeşte doi parametri: primul este identificatorul machetei care se creează, iar al doilea este un pointer (implicit NULL) către caseta de dialog părinte. Cum caseta de dialog nemodală nu acaparează controlul, vom putea folosi acest pointer pentru a comunica cu caseta de dialog părinte. Create() returnează valoarea TRUE în cazul reuşitei, respectiv FALSE în cazul eşecului. În cazul succesului, când Create() returnează valoarea TRUE, fereastra există dar nu este vizibilă. Pentru a o face vizibilă, este nevoie de un apel al funcţiei ShowWindow() cu parametrul TRUE.

Casetele de dialog modale pot fi în general încapsulate fără probleme în interiorul unei funcţii, deoarece ele preiau controlul absolut al programului în momentul în care sunt lansate în execuţie.

Casetele nemodale, datorită faptului că nu preiau controlul programului, vor trebui să poată fi accesate în orice punct al acestuia. Din această cauză, este bine ca să creăm dinamic caseta nemodală, prin intermediul operatorului new, reţinând adresa ei într-o variabilă pointer globală sau membră a clasei ce încapsulează caseta de dialog părinte. Caseta de dialog nemodală poate fi închisă la nevoie, distrugând-o prin intermediul operatorului delete. Destructorul clasei de bază, CDialog, se va ocupa apoi de distrugerea casetei de dialog nemodale.

Transmiterea de valori din caseta de dialog părinte către controale sau variabile ale casetei de dialog nemodale, sau apelurile funcţiilor membru ale unei casete de dialog nemodale se pot efectua pe toată durata de viaţă a acesteia, prin intermediul pointerului de acces corespunzător. La transferul de date între controale şi variabilele membru mapate, prin UpdateData() şi DoDataExchange() se aplică regulile deja cunoscute. Este posibil de asemenea să fie apelate funcţii sau să fie fixate variabile membru ale altor obiecte ale aplicaţiei în cadrul casetei de dialog modale, ca răspuns la interacţiunea utilizatorului cu controalele. În acest scop, trebuie transmişi casetei de dialog pointeri la obiectele respective ale aplicaţiei. Constructorul casetei de dialog nemodale este un loc bun pentru transmiterea acestor pointeri. Pentru aceasta, se modifică constructorul clasei asociate, astfel încât la crearea casetei de dialog să fie transmişi pointeri la obiectele respective ale aplicaţiei. Apoi aceşti pointeri pot fi reţinuţi de către caseta de dialog sub formă de variabile membru, astfel încât oricare dintre funcţiile componente va putea accesa obiectele în cauză.

26

Page 27: Medii de proiectare si programare

9. Utilizarea claselor de fişiere secvenţiale

Marea majoritate a aplicaţiilor trebuie să păstreze un timp îndelungat, de obicei pe un suport magnetic, datele de intrare, sau rezultatul execuţiei lor, sub forma unor fişiere. Cunoaştem că ANSI C pune la dispoziţia utilizatorilor diferite funcţii pentru manipularea fişierelor, furnizate de biblioteca <stdio.h>, cum ar fi: fopen(), fcolse(), fprintf(), fscanf(), fflush(), etc. Aceste funcţii construiesc sau utilizează un identificator ataşat fişierului cu care se lucrează, toate operaţiile asupra fişierului făcându-se pe baza acestui identificator. De asemenea, apariţia unor erori în manipularea fişierelor, este semnalizată tot de către acest identificator, fiind din păcate, mai dificil de determinat cauza care a produs eroarea.

Aceste funcţii pot fi utilizate şi în programele a căror interfaţă este construită cu MFC, dar acest lucru nu este de dorit. MFC pune la dispoziţie o ierarhie de clase pentru lucrul cu fişiere, mult mai uşor de utilizat şi mult mai clare în detectarea şi identificarea erorilor.

Înainte de a prezenta care sunt aceste clase şi cum se lucrează cu ele, să mai studiem o tehnică de interceptare a erorilor, deosebit de des utilizată în limbajele moderne, cum ar fi C++ sau Java.

9.1 Excepţii Complexitatea actuală a aplicaţiilor software, inclusiv a celor

orientate pe obiecte, presupune o modularizare pe nivele ierarhice. Această situaţie impune tratarea deosebit de riguroasă a erorilor şi a situaţiilor deosebite care pot să apară la nivelul diferitelor componente ale unui proiect.

În cele ce urmează, vom înţelege prin excepţie o situaţie deosebită care poate să apară pe parcursul execuţiei unei componente soft parte a unei aplicaţii. Erorile pot fi privite ca şi un caz particular de excepţii, dar în general nu toate excepţiile sunt erori.

Excepţiile se împart în două categorii: excepţii sincrone şi excepţii asincrone. Excep ţ iile sincrone sunt excepţii a căror apariţie poate fi prevăzută de programator (de exemplu, un fişier care se doreşte a fi prelucrat nu se află în directorul aşteptat).

Excep ţ iile asincrone sunt excepţii a căror apariţie nu poate fi prevăzută în momentul implementării programului (de exemplu, defectarea accidentală a hard-disk-ului). Mecanismul de tratare a excepţiilor ia în considerare numai situaţia excepţiilor sincrone.

27

Page 28: Medii de proiectare si programare

Problema se pune astfel: în faza de programare, se poate presupune că un modul de program va detecta în anumite situaţii o excepţie, dar nu va putea oferi o soluţie generală de tratare a acesteia, în timp ce un alt modul al aplicaţiei poate oferi o soluţie de tratare a excepţiei, dar nu poate detecta singur apariţia excepţiilor. Un exemplu concret al unui astfel de caz este următorul: presupunem că avem o aplicaţie care lucrează cu fişiere. Un modul al aplicaţiei (numit în cele ce urmează sursă) declară o clasă CFile care poate detecta o excepţie din clasa fişier inexistent. Această clasă însă nu poate să întreprindă o acţiune generală de tratare a excepţiei prinse. Tratarea excepţiei se face în funcţie de modulul (numit destinaţie) care foloseşte clasa CFile. Un modul ar putea, de exemplu, să invoce funcţia exit() şi să termine aplicaţia, în timp ce un alt modul ar putea doar să afişeze o casetă de dialog şi să solicite utilizatorului selectarea unui alt fişier. Soluţia obiectuală a acestei probleme este bazată pe următoarea idee fundamentală: modulul care detectează excepţia pe care nu o poate rezolva o pasează (throw) modulului client, în speranţa că o componentă a acestuia o va prinde (catch) şi o va trata.

9.1.1 Metode neobiectuale de tratare a excepţiilor

Următoarele metode sunt folosite în mod tradiţional pentru tratarea excepţiilor: • terminarea aplicaţiei - este o soluţie folosită în special de sistemul de operare, în cazul în

care o excepţie aruncată nu este prinsă; • returnarea unui cod de eroare; • poziţionarea unui indicator global; • ignorarea excepţiei - este o soluţie periculoasă. În cazul în care excepţia nu este o

eroare, aplicaţia poate să mai ruleze până când se produce o eroare. Din păcate, este foarte greu de depanat şi de găsit eroarea în astfel de situaţii, deoarece nu se poate detecta momentul producerii ei.

• invocarea unei funcţii specializate de tratare a excepţiei, numită handler;

9.1.2 Mecanismul C++ de tratare a excepţiilor

Alternativa oferită de limbajul C++ pentru tratarea excepţiilor furnizează o soluţie îmbunătăţită, simplificând cooperarea între componente scrise de mai mulţi programatori, dar integrate în aceeaşi aplicaţie.

Implementarea C++ a mecanismului de tratare a excepţiilor are la bază următoarele trei cuvinte cheie: • try – care delimitează la nivelul modulului destinaţie codul care ar

putea să emită (raise) o excepţie; • throw - care se execută în cazul în care modulul sursă a detectat o

condiţie de excepţie; • catch – delimitează o secvenţă de cod la nivelul modulului destinaţie

care va trata o situaţie excepţională în cazul detectării ei;

Aşadar, tratarea excepţiilor printr-un mecanism C++ se face în următoarele trei etape:

28

Page 29: Medii de proiectare si programare

• se emite excepţia prin throw; • se detectează excepţia prin try; • se tratează excepţia prin catch;

9.2 Clasele MFC pentru lucrul cu fişiere

MFC furnizează două clase pentru lucrul cu fişiere standard. Clasa CFile permite accesul la fişiere binare stocate pe disc. Clasa încapsulează un

identificator pentru accesul la fişiere şi oferă metode de deschidere, citire, scriere şi închidere a fişierelor. Clasa CFile realizează un acces direct la fişier, fără stocarea prealabilă într-o zonă tampon (buffer) a datelor.

Clasa CStdioFile, derivată din clasa CFile, implementează operaţii cu fişiere în flux. În acest caz, datele sunt în prealabil stocate în buffere.

Tot derivate din clasa CFile sunt şi clasa CMemFile care asigură suport pentru fişierele stocate în memoria RAM, cum ar fi cele salvate pe RAM-disk-uri, utilizate pentru creşterea vitezei de acces la date, sau clasa CSharedFile, care asigură suport pentru accesul la fişiere partajate, aflate în memorie.

9.2.1 Deschiderea fişierelor Clasa CFile permite deschiderea unui fişier pe mai multe căi. Câteva

din acestea sunt prezentate mai jos: • clasa CFile furnizează un constructor care permite specificarea

fişierului de pe disc care urmează a fi deschis. Acest constructor permite declararea unui obiect CFile şi îl asociază cu un fişier existent. Cum deschiderea fişierului se face în constructorul clasei, o situaţie de incident, cum ar fi inexistenţa fişierului specificat, poate duce la erori fatale;

• o cale mai normală presupune deschiderea fişierului în doi paşi. Întâi se creează un obiect CFile, apoi acestui obiect i se asociază un fişier de pe disc. Pentru deschiderea fişierului, se utilizează funcţia open().

Există o mulţime de cauze de apariţie a erorilor la deschiderea unui fişier, cea mai des întâlnită fiind o încercare de deschidere a unui fişier inexistent, sau a unui fişier deschis exclusiv de un alt proces. Funcţia Open() returnează valoarea TRUE dacă deschiderea este reuşită, sau FALSE

în caz contrar, putându-se detecta succesul sau insuccesul operaţiei de deschidere. Din păcate, acest mod de testare a operaţiei, nu dă informaţii, în caz de eşec, asupra cauzei care a produs eşecul.

Pentru determinarea cauzei, MFC oferă clasa CFileException, care încapsulează erorile de lucru cu fişierele. Clasa CFile furnizează şi un constructor de deschidere a fişierelor, care utilizat, va arunca o excepţie CFileException dacă deschiderea eşuează. Aceasta poate fi interceptată într-un bloc try-catch tipic .

9.2.2 Închiderea fişierelor

29

Page 30: Medii de proiectare si programare

Închiderea fişierelor se face prin intermediul funcţiei CFile::Close(). Nu întotdeauna este absolut necesară utilizarea acestei funcţii, pentru că destructorul clasei CFile apelează automat această funcţie când obiectul CFile curent iese din domeniul de definiţie. Dar, este totuşi recomandat ca orice apel al funcţiei CFile::Open() să fie pereche cu un apel al funcţiei CFile::Close().

Citirea şi scrierea directă din fişiere se pot face cu funcţiile clasei CFile

Read() şi Write(), funcţii care apelează funcţiile ReadFile() şi WriteFile() ale Windows API. Să ne reamintim că prin intermediul clasei CFile, scrierea şi citirea se fac direct pe disc, lucru destul de riscant. De aceea, este preferabil să se utilizeze funcţii care lucrează cu fluxuri de date I/O. În C++, clasa care implementează aceste funcţii este iostream, punând la dispoziţie funcţii cum ar fi fopen(), fseek(), fread(), fwrite(), etc.

Într-un proiect MFC apelul acestor funcţii este anacronic. În MFC, operaţiile cu fişiere în flux, sunt implementate de clasa CStdioFile. Funcţiile Read() şi Write() din această clasă, spre deosebire de cele ale clasei CFile, oferă acces la fişiere prin intermediul unor fluxuri I/O şi nu prin acces direct la disc.

Fişierele asociate unui obiect CStdioFile pot fi deschise în mod text sau în mod binar. Fişierele deschise în mod text realizează interpretarea caracterelor de control speciale, cum ar fi CR, LF, etc. Pentru deschiderea unui fişier în mod text, se va utiliza opţiunea CFile::typeText.

Pentru deschiderea fişierului în mod binar, se va utiliza opţiunea CFile::typeBinary. În acest mod, toţi octeţii fişierului sunt interpretaţi în mod identic, fără a exista coduri de control.

Citirea datelor se poate face prin intermediul a două funcţii: - read()- readString()

Ambele funcţii primesc ca şi argumente un pointer la un buffer tampon în care se vor citi datele, respectiv la un şir de caractere, precum şi dimensiunea maximă a acestora. În a doua variantă a funcţiei ReadString()

se specifică un şir în care se stochează datele citite din fişier. Funcţia returnează valoarea TRUE dacă citirea e reuşită, respectiv FALSE dacă citirea eşuează. Pentru toate funcţiile, în caz de eşec, se va arunca o excepţie de clasă CFileException.

Scrierea datelor se face cu funcţiile:- write()- writeString()

30

Page 31: Medii de proiectare si programare

10. Programarea aplicaţiilor SDI(Single Document Interface)

10.1 Introducere Probabil una dintre cele mai utilizate aplicaţii realizate de firma

Microsoft este la ora actuală pachetul de programe MsOffice, iar din cadrul acestuia, cu siguranţă editorul MsWord. Acest editor este în fapt o aplicaţie Windows tipică, oferind utilizatorului o interfaţă specifică, constând într-o bară de titlu, un meniu derulant, una sau mai multe bare de instrumente, o zonă de lucru şi în fine, la baza ferestrei, o zonă de afişare. O interfaţă de acest tip poate fi foarte uşor programată utilizând biblioteca MFC. AppWizard poate crea foarte uşor un schelet de interfaţă conţinând elementele enumerate mai sus, care ulterior pot fi dezvoltate sau modificate după dorinţa programatorului. Clasele utilizate de AppWizard sunt asamblate formând o structură omogenă numită arhitectură Document/Reprezentare (Document/View). Arhitectura Document/Reprezentare oferă o independenţă a modului de reprezentare a datelor de datele propriu-zise, reprezentarea fiind realizată de metodele oferite de o clasă reprezentare (View), iar datele fiind stocate de o clasă document.

Structura de clase creată de AppWizard pentru o aplicaţie SDI (Single Document Interface) diferă de cea creată pentru o aplicaţie de tip Dialog. Şi în acest caz clasele vor deriva printr-un mecanism de moştenire simplă din clasa CObject, dar vor fi utilizate clase noi, care nu apar într-o aplicaţie de tip Dialog.

10.2 Crearea machetei programului Ca si pana acum , initializarea interfetei se face in functia

InitInstance apelata de constructorul clasei aplicatie.Prin intermediul functiei se poate crea un obiect de clasa CsingleDocumentTemplate.Acesta este inregistrat in cadrul clasei CwinApp cu functia AddDocTemplate().

MFC furnizează o serie de căi pentru accesarea obiectului document din cadrul aplicaţiei. Cea mai simplă cale de accesare a documentului este prin intermediul funcţiei CView::GetDocument().

10.3 Lucrul în comun Document/Reprezentare. Meniuri şi butoane

AppWizard inserează automat clasele document şi reprezentare în proiect. În mod ideal, toate datele ar trebui să aparţină instanţelor claselor document, iar caracteristicile de afişare instanţelor claselor reprezentare. În mod real, acest lucru nu este posibil, efectuându-se în general operaţii asupra datelor şi din funcţii ale clasei reprezentare, iar modificări ale modului de afişare pot fi făcute şi din funcţii ale claselor document.

Clasa document este o clasă ca oricare alta, deci variabilele membru ale acesteia pot fi adăugate prin Add Member Variable din meniul contextual asociat clasei în

31

Page 32: Medii de proiectare si programare

ClassView. În general, pentru asigurarea securităţii variabilelor document, acestea trebuie să fie protejate. Cum totuşi anumite date vor trebui accesate şi din funcţii ale clasei reprezentare, clasa document va trebui să ofere metode de acces la variabilele private. Aceste metode sunt publice, fiind inserate în general cu Add Member Function.

10.4 Modelarea interfeţei meniu MFC furnizează o serie de funcţii pentru modelarea aspectului, stilului şi

comportamentului elementelor meniului. Funcţiile care modifică atributele elementelor de meniu acţionează în general asupra unui obiect CCmdUI, primind ca argument un pointer spre un astfel de obiect.

Obiectul CCmdUI pointat în orice moment se va referi la componenta de meniu sau submeniu activă în acel moment. Funcţiile de tratare UI pentru un element de meniu se adaugă în ClassWizard, prin selectarea la Messages a opţiunii UPDATE_COMMAND_UI. O funcţie UPDATE_COMMAND_UI este lansată în execuţie de fiecare dată când elementul de meniul devine activ, iar modul lui de afişare va fi făcut în concordanţă cu setările conţinute în corpul funcţiei.

Marcaje de validare

Este util de multe ori ca starea unui anumit element de meniu să poată fi comutată. O implementare simplă a acestei acţiuni este realizată prin utilizarea unui comutator de stare, care să basculeze într-o funcţie COMMAND, iar starea elementului de meniu să fie modificată în funcţia UPDATE_COMMAND_UI.

10.5.1 Crearea meniurilor contextuale asistată de AppWizard Implementarea meniurilor contextuale se face prin interceptarea mesajului

WM_CONTEXTMENU şi asocierea unei funcţii corespunzătoare. Acest mesaj este trimis spre tratare procedurii fereastră în momentul apăsării butonului drept al mouse-lui, oriunde în zona client a reprezentării.

Pentru implementarea funcţiei, este absolut necesar ca în prealabil să fie inserată în aplicaţie o nouă resursă meniu, care să fie afişată la apăsarea butonului drept al mouse-lui.

Pentru afişarea meniului contextual se creează întâi un obiect CMenu. Clasa CMenu este derivată direct din clasa CObject şi încapsulează toate metodele de creare, urmărire, actualizare şi distrugere a unui obiect meniu.

Iniţializarea noului obiect meniu cu resursa meniu corespunzătoare se face prin intermediul funcţiei LoadMenu, care primeşte ca parametru identificatorul resursei meniu asociate şi ataşează resursa de obiectul nou creat.

Urmează implementarea funcţiilor asociate elementelor de submeniu.

10.5.2 Crearea şi accesarea prin program a obiectelor meniu În multe cazuri nu este practică crearea prin Wizard a meniului, acesta trebuind să fie

creat, actualizat sau şters dinamic, în cursul execuţiei programului. În acest sens, va trebui să reconstituim prin cod acţiunile efectuate de AppWizard pentru interceptarea mesajului lui ContextMenu.

Crearea unui meniu se face cu funcţia CreateMenu(). Această funcţie creează meniul şi îl ataşează obiectului CMenu corespunzător. Resursa meniu creată este goală, urmând ca

32

Page 33: Medii de proiectare si programare

în ea să fie adăugate elemente. O alternativă este funcţia CreatePopupMenu(), având acelaşi rol, dar care creează un meniu derulant. Ambele funcţii returnează o valoare diferită de 0 în caz de succes, respectiv 0 în caz de eşec. Adăugarea elementelor de meniu se poate face cu InsertMenu() sau AppendMenu().

10.6 Bare cu instrumente Barele cu instrumente reprezintă o modalitate rapidă de furnizare a comenzilor pentru

program. AppWizard generează o bară cu instrumente standard pentru aplicaţiile SDI. Această bară este un obiect de clasă CToolbar, definit în cadrul clasei CMainFrame, clasă care răspunde de gestionarea ferestrei cadru.

Pentru afişarea barei cu instrumente standard, AppWizard implementează un mecanism destul de complex.

Crearea barei de instrumente se face prin intermediul funcţiei CreateEx() cu parametrii:- pointer spre fereastra părinte. - un stil adiţional pentru crearea barelor de instrumente înglobate. - stilul de afişare a barei de instrumente, ca o combinaţie de indicatori - coordonatele obiectului CRect care mareste bara- identificatorul barei cu instrumente afişate

10.6.1 Adăugarea unei bare cu instrumente utilizator în fereastra cadru În general, pentru aplicaţiile mai complexe, nu este suficient să se personalizeze bara de stare standard oferită de scheletul AppWizard. Marea majoritate a aplicaţiilor utilizează şi alte bare de unelte. Deci, este util să se poată insera în cadrul programului noi bare de instrumente.

10.7 Bare de dialog Barele de dialog sunt bare de instrumente care au în componenţă obiecte

caracteristice casetelor de dialog. Ele sunt încapsulate de clasa CDialogBar, care, fiind derivată direct din clasa CControlBar va moşteni complet funcţionalitatea acesteia.

10.8 Bare de stare Bara de stare este afişată în general în partea inferioară a ferestrei cadru, dând diferite

informaţii despre starea programului. Implementarea standard a barei de stare furnizează indicatori pentru starea tastelor CAPS LOCK, NUM LOCK şi SCRL LOCK.

Crearea şi afişarea barei de stare este făcută de către AppWizard tot în funcţia OnCreate() a clasei CMainFrame. În bara de stare se pot adăuga noi indicatori, cu funcţii specificate de utilizator. Afişarea efectivă a indicatorului o dată creat, se va face prin interceptarea mesajului UPDATE_COMMAND_UI asociat şi prin transmiterea valorii TRUE pentru funcţia Enable().

10.9 Apelarea unei casete de dialog din meniu De foarte multe ori, ca răspuns la selectarea unei intrări de meniu, se afişează o

casetă de dialog, care permite modificarea unor parametri ai programului. În marea

33

Page 34: Medii de proiectare si programare

majoritate a cazurilor, caseta de dialog este lansată modal, casetele de dialog nemodale fiind utilizate mai mult ca şi bare de instrumente.

11.Procese si fire de executie in SO (sistemul de operare)

1)Activitati dependente sau conduse de timp trebuie efectuate la fiecare x intervale de timp2)Activitatile conduse de evenimente :semnale sau contexte in alte fire de executie3)Activitati distribuite : implica lucrul pe mai multe calculatoare4)Activitati care implica ierarhizari prioritare: fiecarui fir de executie i se poate asocia o prioritate

In Visual C++ , firele de executie ale aplicatiei sunt reprezentate ca obiecte ale clasei CwindThread.Spre deosebire de restul firelor ,firul principal apare ca o clasa derivata din CwinApp ,care e derivata din CwindThread.

Firele de executie pot di declarate direct ca si doua CwindThread sau pot fi create direct prin utililzarea functiilor globale AfxBeginThread().Startarea unui nou fir se face prin intermediul metodei CwinThread::CreateThread() iar suspendarea respectiv reluarea executiei unui fir sunt manipulate de metodele:- CWinThread::SuspendThread()

- CWinThread::ResumeThread()

Spre deosebire de WinAPI ,MFC lucreaza cu 2 tipuri de fire de excutie:1) fire de executie de lucru2) fire de executie de tip interfata utilizatorFire de executie de lucru

- lucreaza in fundal- nu necesita intrari de la echipamentele de intrareex tipic :back-up-write realizate periodic de diferite programe- pentru crearea unui fir de executie de lucru trebuie implementata o functie de

control care executa sarcina asociata firului iar adresa functiei globale AfxBeginThread .Functia de control va fi astfel :UINT NumeFctieControl(LPVOID Parametru) iar acest parametru reprezinta o valoare pozitiva pe 32 de biti ,mai precis o adresa ,un pointer spre o structura care contine un set de parametrii

Fire de executie de tip interfata utilizator- pot manipula metode de intrare de la echipamentele de intrare implementand o

bucla de mesaje ce raspund la evenimentele si mesajele generate de interactiune utilizatorului de aplicatie

- firele de executie secundare vor trebui sa permita inserarea de date in program fara sa se degradeze performantele in executia celorlalte fatete ale programului

34

Page 35: Medii de proiectare si programare

- in cazul firelor de executie utilizator ,un fir secundar se lanseaza cu functia AfxBeginThread() ,de fapt aceasta e o supraincarcare a versiunii AfxBeginThread() in cazul firelor de executie de lucru.

11.1 Sincronizarea firelor de executie...

11.2 Prioritatile firelor de executieFirele de executie au implicit o prioritate normala.Aceasta prioritate poate fi insa

modificata la lansarea in executie folosind urmatorii parametrii:- THREAD_PRIORITY_LOWEST indica o prioritate cu 2 valori sub prioritatea normala- THREAD_PRIORITY_BELOW_NORMAL indica o prioritate cu 1 valoare sub prioritatea normala- THREAD_PRIORITY_NORMAL indica o prioritate normala- THREAD_PRIORITY_ABOVE_NORMAL indica o prioritate cu 1 valoare peste prioritatea normala- THREAD_PRIORITY_HIGHEST indica o prioritate cu 2 valori peste prioritatea normala

35


Recommended