Sunteți pe pagina 1din 114

Dorin Bocu

Metode evoluate de
programare
(Elemente de programare
vizuala utilizând Delphi)
Cuvânt înainte

Sintagma Metode evoluate de programare este discutabilă. Întrebarea “Care


metode de programare sunt evoluate şi care nu” ne aduce pe un teren relativist şi
controversat. Relativist, deoarece ceea ce astăzi este revoluţionar sau evoluat, mâine
devine fapt comun. Controversat, deoarece linia de demarcaţie între metodele
evoluate de programare şi “restul lumii” este departe de a fi recunoscută de întreaga
comunitate a programatorilor.
Programarea orientată pe obiecte este o metodă evoluată de programare?
Programarea care insistă pe un anumit tip de modularizare este o metodă evoluată de
programare? Programarea bazată pe componente este o metodă evoluată de
programare? Oare modelul de dezvoltare are vreun impact asupra metodei de
programare? Multe sunt întrebările care ar putea face obiectul discursului acestui
curs.
Cert este că activitatea de programare nu se mai poate desfăşura după canoanele
anilor ‘60, nici măcar după canoanele anilor ‘80. Sistemele de operare moderne
propun, de regulă, o anumită viziune asupra caracteristicilor unei aplicaţii.
Referindu-ne la sistemul de operare Windows, de exemplu, vom vorbi despre aplicaţii
Windows, care au caracteristici precum: interfaţă grafică cu utilizatorul, acces
potenţial la capabilităţile multitasking ale sistemului de operare, posibilităţi nelimitate
de utilizare a memoriei, acces la tehnologiile Microsoft (DDE, OLE-ACTIVEX,
DIRECTX, COM, DCOM, etc.). De asemenea, activitatea de programare nu mai
poate fi concepută în afara sprijinului oferit de mediile de programare. Acestea
sunt sisteme soft care integrează o serie de elemente suport (editor de texte,
compilator, debuger, gestionare proiecte, editor de resurse, etc.), în conformitate cu o
strategie de abstractizare adecvată, cu scopul de a mări randamentul activităţii de
programare precum şi indicele de calitate al programelor (fiabilitate, corectitudine,
interfaţă ergonomică, etc.)
Deşi nu este locul pentru a epuiza subiectul, utilizarea mediilor de programare
pentru a trece la producţia industrială a softului, nu este posibilă fără a
conştientiza imortanţa modelelor de dezvoltare în procesul de realizare a
sistemelor soft.
Astfel de probleme ne vor preocupa în acest curs, cu intenţia clară de a mai face
un pas înainte pe drumul înţelegerii importanţei relaţiei modelare-implementare,
sub auspiciile unui mediu de programare, în meseria de dezvoltator de sisteme
soft.
Mediul de programare cobai pentru prezenul curs poate fi Delphi sau C-Builder.
Prezentul suport de curs se va axa pe prezentarea unora dintre liniile de forţă esenţiale
ale mediului vizual de programare Delphi, recunoscut pentru accesibilitatea şi
eleganţa soluţiilor pe care le propune pentru realizarea de aplicaţii Windows, în
principal. Mediul vizual de programare Delphi se bazează pe limbajul Object Pascal,
un urmaş puternic al limbajului Pascal (viziunea Borland). În Object Pascal şi sub
Delphi, există suport pentru a face modularizare metodică, orientare pe obiecte
metodică, tratare structurată a excepţiilor, etc. Trecerea la C-Builder nu ridică decât
probleme de acomodare cu limbajul C++, dacă acestea există. Mediul vizual de

2
programare C-Builder este, abstracţie făcând de limbajul din spate, identic cu mediul
vizual de programare Delphi. De aceea, va fi uşor pentru fanii împătimiţi ai C++ să
cocheteze cu C-Builder, după ce au descoperit strategia de lucru sub Delphi.
Dată fiind întinderea universului problematic al unui mediu vizual de programare
(Delphi sau C-Builder), o parte dintre aceste probleme vor fi, din fericire, abordate la
cursul opţional de Programare Windows.
*
Programarea în Pascal, din perspectivă DOS, reprezintă un prilej de afirmare a
unor principii foarte clare ale “modelului clasic de rezolvare a unei probleme” cu
ajutorul calculatorului:

• Fiecare program se bazează pe existenţa a trei secţiuni: citirea datelor de


intrare, efectuarea prelucrărilor specifice şi afişarea rezultatelor.
• Ordinea determinantă pentru execuţia instrucţiunilor este ordinea secvenţială.
• Odată lansat în execuţie, posibilităţile de comunicare operativă ale unui
program cu mediul, sunt, principial, extrem de reduse.
• Interactivitatea program-utilizator, într-o formă cât mai complexă, înseamnă
efort uriaş de programare pentru realizarea interfeţelor (proiectare + gestiunea
evenimentelor asociate).

Acest model de abordare a problemelor de programare rămâne dominant şi în


varianta orientată pe obiecte a limbajului Pascal. Deşi orientarea pe obiecte crează
premize pentru eliminarea multor neajunsuri ale paradigmelor clasice, barierele
impuse de sistemul de operare limitează beneficiile potenţiale (Sistemele de operare
compatibile DOS sunt monotasking, monouser şi, ceea ce este extrem de neproductiv
pentru programatori, sunt străine de preocuparea de a promova nişte standarde
relativ la “filozofia” de proiectare, programare şi execuţie a sistemelor soft).
Pentru eliminarea neajunsurilor esenţiale ale sistemelor de operare compatibile
DOS, o alternativă a fost şi este mediul de operare Windows. De menţionat faptul că
există numeroase alte familii de sisteme de operare (OS, UNIX, etc.) care, în viziunea
unor specialişti sunt chiar mai puternice şi mai interesante decât Windows.
Noutatea adusă de mediul de operare Windows poate fi rezumată astfel:

• Interactivitate ridicată a utilizatorului cu aplicaţia;


• Introducerea datelor şi comunicarea rezultatelor în formă grafică;
• execuţia simultană a mai multor programe sau a mai multor instanţe ale
aceluiaşi program;
• comunicarea datelor între programe.
Toate aceste caracterisrici îşi găsesc suport în Windows, care este, prin întreaga
lui ofertă de servicii, un mediu deschis de operare şi programare.
Prin sintagma de mai sus înţelegem faptul că mediul Windows oferă toate
facilităţile necesare pentru ca orice programator să dezvolte şi să adauge
aplicaţii care să se comporte asemănător celorlaltor componente livrate odată cu
mediul Windows. Mai exact, programatorul are la dispoziţie o mulţime

3
impresionantă de funcţii, constante şi structuri de date care îi permit să creeze
aplicaţii conform standardelor Windows. Toate aceste facilităţi sunt grupate în
interfaţa de programare a aplicaţiilor (Win32API - Applicaţion Programming
Interface).
Cum am mai spus, mai multe detalii pe teme de programare Windows se pot afla
la cursul opţional de Programare Windows sau din nenumăratele surse de informare
care există în librării şi, din păcate, mai puţin în bibliotecile şcolilor noastre.
Firma Borland a oferit programatorilor şansa de a programa în spirit Windows
prin intermediul pachetului Borland Pascal for Windows al kitt-ului Borland Pascal
7.0. Evoluţia galopantă a paradigmelor în materie de comunicaţie electronică şi în
materie de gestiune a colecţiilor de date a scos la rampă mediile vizuale de
programare a sistemelor soft utilizator. Deşi pionier în această direcţie, Visual Basic
are o serie de neajunsuri pe care specialiştii de la Borland le-au sesizat şi le-au
rezolvat prin propunerea mediului Delphi de dezvoltare a aplicaţiilor utilizator şi nu
numai (a se vedea C-Builder sau J-Builder!).
Delphi este un mediu vizual de dezvoltare de aplicaţii cu adevărat orientate pe
obiecte şi modularizate, pornind de la platforma Windows. Prin aceasta Delphi devine
un instrument ideal pentru aplicarea în practică a paradigmei RAD (Rapid
Applications Development). Deşi nu este un mediu CASE (Computer Aided
Software Engineering), Delphi este o platformă care permite rezolvarea multor
probleme a căror soluţie se bazează pe prototipizare (=construirea unor versiuni sau
componente simplificate ale sistemului soft propus, care pot fi analizate înainte de a
se continua dezvoltarea).

Ucenicul care începe urcuşul pe panta programării vizuale, trebuie să înţeleagă că


are de parcurs un drum lung, plin de surprize şi, fireşte, obstacole, care trebuie
surmontate investind timp şi, dacă este cazul, pasiune şi inteligenţă. În programarea
vizuală perspectivele se deschid larg pentru programator, dar, în egală măsură, este
nevoie şi de o nouă abordare în partea de proiectare pentru a nu eşua graţios, mai
devreme sau mai târziu.

4
Ce noutăţi oferă DELPHI ?

Delphi este o colecţie integrată de capabilităţi de dezvoltare a sistemelor soft care,


mânuite în spiritul care a dus la specificarea lor, pot simplifica mult existenţa,
îndeosebi a programatorilor implicaţi în derularea unui proiect de sistem soft. Ceva
mai exact putem spune că “Delphi este un mediu de programare vizuală, obiect
orientat, pentru dezvoltare rapidă şi cu scop general a aplicaţiilor Windows 95,
98, 2000 şi NT, XP, etc.”.
Dintre caracteristicile principale ale sistemului Delphi, semnalăm:

Mediul de dezvoltare poate fi personalizat.


Este cunoscut faptul că, de câţiva ani, mediile vizuale de programare au adăugat
clasicelor IDE (Integrated Development Environment), care integrau trei instrumente
de bază în programare( editor, compilator şi depanator), capabilităţi de realizare a
interfeţelor cu suport vizual şi de generare automată a codului aferent. Delphi merge
un pas mai departe, permiţând utilizatorului să personalizeze IDE Delphi cu ajutorul
serviciilor oferite de componenta Open Tools API.

Orientarea pe obiecte
Limbaje precum Visual Basic sunt pseudo-obiect orientate, folosind obiecte şi
metode fără a oferi suport pentru încapsulare, moştenire şi polimorfism. Limbajul
Pascal Object, care stă la baza aplicaţiilor Delphi, este un limbaj cu adevărat obiect
orientat, care permite combinarea datelor şi a codului asociat pentru a defini clasele
(încapsulare), crearea de descendenţi ai acestor clase (moştenire) şi tratarea unei clase
descendente în relaţia cu o clasă părinte din perspectivă polimorfică.

Biblioteca de componente
Toate elemenetele cu ajutorul cărora sunt realizate, în mod uzual, interfeţele
aplicaţiilor Windows sunt standardizate şi puse la dispoziţia programatorilor ca şi
componente, păstrate în biblioteca de componente a sistemului. Dacă există
programatori care vor să modifice funcţionalitatea componentelor oferite de Delphi, o
pot face elegant, printr-o derivare adecvată, dar cu un efort de programare
considerabil mai mare decât în cazul simplei utilizări a componentelor.

Suport OCX şi ActiveX


Delphi “tolerează” obiecte care sunt create cu alte limbaje (ca de exemplu C++) şi
sunt distribuite conform standardului OCX. Obiectele OCX sunt, în general,
furnizate de companii de soft specializate, asigurând o gamă largă de funcţionalităţi.
ActiveX este o redezvoltare a modelului OCX, cu utilizare largă, îndeosebi pentru
browserele de Internet. OCX, ActiveX, COM, DCOM, OLE, etc. sunt tehnologii
Microsoft importante pentru a înţelege mai exact puterea oferita programatorilor de
paradigma Windows de programare. Din nou fac trimitere la optionalul de
programare Windows sau la autoinstruire.

5
Şabloane
Delphi recunoaşte patru tipuri de şabloane: forma, aplicaţia, componenta şi codul.
Şabloanele de tip formă, aplicaţie şi componentă permit reutilizarea colecţiilor de
obiecte în programe diferite sau ca bază pentru realizarea unui program nou.
Şabloanele de tip cod simplifică procesul de scriere a codului aferent unor enunţuri
Delphi standard.

Compilare adevărată
Multe medii de dezvoltare Windows generează executabile semi-compilate (p-
cod). Deoarece p-codul nu este executabil pe o maşină fizică, el trebuie translatat în
momentul execuţiei, ceea ce înseamnă o semnificativă penalizare a performanţei unui
program. Delphi produce cod executabil autentic care, în plus, nu pretinde
performanţe deosebite din partea mediului de execuţie gazdă. Totodată, filozofia
Delphi permite lucrul cu componente DLL, fapt ce are implicaţii asupra
performanţelor programului şi mediului de execuţie. Orientarea pe componente DLL
a aplicaţiilor realizate în spirit Windows creeaza, este drept, niste probleme de
portabilitate de la sisteme puternic configurate la sisteme mai modeste, atât din punct
de vedere hard cat si din punct de vedere al forţei sistemului de operare.

Aplicaţii robuste
Sunt cunoscute de la alte limbaje dificultăţile legate de tratarea de către
programator a excepţiilor care pot să apară în timpul execuţiei unui program. Delphi
rezolvă aceste probleme propunând enunţuri de limbaj adecvate pentru soluţionarea
lor. Aceste enunţuri nu fac altceva decât să transpună în sintaxă Object Pascal,
semantica cunoscută de la abordarea C++ pentru tratarea excepţiilor.

Gestiunea colecţiilor de date


Specialiştii de la Borland sunt conştienţi de faptul că foarte multe aplicaţii sunt
realizate în jurul ideii de gestiune a datelor. De aceea, Delphi oferă obiecte şi
componente care reduc semnificativ efortul de realizare a aplicaţiilor cu baze de date.

Delphi este, în felul lui, un mediu de dezvoltare mamut care permite o


deschidere aproape totală către toate capabilităţile specifice aplicaţiilor Windows
(aplicaţiile grafice, aplicaţiile multimedia, locale sau în reţea).

Aş mai adăuga incă un motiv important în alegerea mediului Delphi pentru a
face programare vizuală: uşurinţă a învăţării protocoalelor de dezvoltare asistată a
aplicaţiilor Delphi, comparativ cu alte medii (Visual Basic sau Visual C++).

6
2. Fundamentele limbajului Object Pascal
Deşi capabilităţile mediului Delphi permit realizarea unor aplicaţii utilizând,
esenţial, doar click-ul de mouse, adevăratele aplicaţii utilizator presupun, încă,
efort de programare pentru rezolvarea unor probleme specifice acestora. Limbajul
prin intermediul căruia se face inserţia de comportament specific în aplicaţiile
Delphi este limbajul Object Pascal. Schema de principiu după care un programator
combină capabilităţile Delphi de generare a codului cu activitatea de adăugare a
codului specific poate fi dedusă făcând o scurtă trecere în revistă a disciplinei Delhpi
de realizarea a unei aplicaţii.

2.1. Componentele de bază ale mediului de dezvoltare Delphi


Pentru a simplifica procesul de dezvoltare a aplicaţiilor, Delphi pune la dispoziţia
programatorului patru componente esenţiale: editorul de forme, editorul de cod,
inspectorul de obiecte şi biblioteca de componente Delphi (VCL). În procesul de
dezvoltare a unei aplicaţii, interacţiunea dintre aceste componente este permanentă.
Invăţarea “semanticii” acestei interacţiuni este cheia succesului în programarea
Delphi, alături, evident, de cunoaşterea limbajului Object Pascal.

În Delphi, forma este un obiect special, destinat să preia toate proprietăţile


ferestrei care va fi vizibilă în momentul lansării în execuţie a proiectului. La fiecare
lansare în execuţie, sistemul Delphi crează o formă, care nu conţine nici o
componentă. Să remarcăm, totuşi, faptul că, această formă este deja înzestrată cu o
serie de funcţionalităţi ascunse în caseta de activare a meniului sistem(deplasare
fereastră, redimensionare fereastră, minimizare fereastră, maximizare fereastră,
închidere feresatră). Pe formă se pot aşeza componente vizuale şi nevizuale cu
ajutorul cărora se realizează interfaţa program-utilizator. O aplicaţie poate conţine
mai multe forme (dintre acestea una corespunde ferestrei principale a aplicaţiei,
celelalte fiind asociate altor ferestre de dialog, subordonate funcţional ferestrei
principale). Fişierul corespunzător unei forme are extensia .DFM. Numele implicit
al formei este Unit1.DFM. Codul care descrie o formă nu este de tip text ASCII.
Pentru vizualizarea ASCII a codului care descrie o formă se poate efectua un click pe
butonul drept al mouse-ului într-o porţiune neocupată a formei. Din meniul local
afişat se va alege comanda View as Text . Textul afişat este următorul:

object Form1:Tform1
Left =200
Top =110
Width =544
Height =375
Caption =’Form1’
Font.Charset =DEFAULT_CHARSET
Font.Color =clWindowText
Font.Height =-11
Font.Name =’MS Sans Serif’
Font.Style =[]
PixelsPerInch=96

7
TextHeight =13
end

Dacă doreşte, programatorul poate modifica unele dintre proprietăţile care apar în
vizualizarea de mai sus.
Revenirea de la reprezentarea de tip text la reprezentarea vizuală a unei forme se
poate face cu ajutorul comenzii View as Form (Alt+F12), accesibilă în meniul local
al reprezentării de tip text.

Inspectorul de obiecte este o componentă a mediului Delphi, responsabilă de


actualizarea proprietăţilor de tip câmp sau eveniment, asociate componentelor care
contribuie la funcţionalitatea unei aplicaţii. Este vorba de acele proprietăţi ale
obiectelor unei aplicaţii care sunt publicabile (se va vedea mai precis sensul acestei
sintagme când se va prezenta perspectiva Object Pascal asupra conceptului de clasă).
Pentru programator este important faptul că, inspectorul de obiecte este instrumentul
care permite adaptarea proprietăţilor obiectelor unei aplicaţii la cerinţele concrete ale
aplicaţiei, cooperând permanent cu editorul de forme şi cu editorul de cod. Impactul
dinamicii relaţiei inspector de obiecte - editor de cod - editor de forme poate fi
apreciat corect doar rezolvând efectiv probleme cu ajutorul mediului Delphi.

2.2. Conceptul de proprietate


Pentru descrierea obiectelor care alcătuiesc o aplicaţie se utilizează conceptul de
proprietate. În Delphi obiectele pot avea proprietăţi (un concept nou pe care îl vom
lămuri din interiorul limbajului Object Pascal). Aceste proprietăţi pot fi de tip câmp
sau de tip eveniment. Proprietăţile de tip câmp optimizează procesul de gestiune a
atributelor informaţionale ale unui obiect. Proprietăţile de tip eveniment
optimizează procesul de gestiune a atributelor comportamentale ale unui obiect,
implicate în gestiunea mesajelor unei aplicaţii, ştiut fiind faptul a o aplicaţie Windows
este puternic dirijată de evenimente şi în consecinţă intens preocupată de tratarea
diverselor mesaje care apar pe timpul execuţiei acestei aplicaţii.
De exemplu, proprietatea Width a unei forme descrie lăţimea acesteia.
Evenimentul OnClick în contextul unei forme se referă la efectuarea unui click de
mouse pe formă. Aceleaşi consideraţii sunt valabile şi relativ la o componentă
oarecare. Prin intermediul proprietăţilor stabilim caracteristicile vizuale sau
funcţionale ale formelor sau componentelor. Unele proprietăţi au valori implicite;
valorile altora pot fi selectate dintr-o mulţime de alternative. Totodată, proprietăţile
pot fi modificate şi în timpul execuţiei aplicaţiei. De fapt, proprietatea de tip câmp
este un concept cu ajutorul căruia se obţine un spor de flexibilitate în ceea ce
priveşte accesul la câmpurile unui obiect. În spatele proprietăţilor de tip
eveniment se vor afla întotdeauna metode ale claselor care le abstractizează.
Evident, acestor metode le asociem cod Object Pascal care reprezintă tratarea
evenimentului cu care sunt solidare.
Conform strategiei Delphi de organizare a codului scris de programator, fiecare
formă are asociat şi un fişier cu extensia .PAS în care se păstrează atât codul generat
automat de Delphi cât şi codul adăugat de programator structurat după exigenţele
conceptului de unit, cunoscut din Pascal. Mai multe forme într-o aplicaţie înseamnă

8
mai multe unit-uri. Legarea formelor, astfel încât acestea să formeze o aplicaţie este
realizată cu ajutorul conceptului de proiect.
Nu este interzis ca o formă să îşi implementeze funcţionalitatea cu ajutorul mai
multor unit-uri, dacă este necesar din punct de vedere al modularizării.

2.3. Conceptul de proiect


În timp ce unit-urile corespunzătoare formelor reprezintă modalitatea prin care
Delphi organizează obiectele unei aplicaţii, prin conceptul de proiect se oferă o
pârghie de reprezentare a structurii de prelucrare a aplicaţiei la un nivel înalt de
abstractizare (care ar putea imita oarecum ideea de program principal din Pascal sau
TVision). Astfel că putem spune că, programului principal al unei aplicaţii, Delphi îi
asociază un fişier cu extensia .DPR . Implicit, numele fişierului proiect este
Proiect1.DPR. În cazul unei aplicaţii cu o singură formă codul asociat este:

program Proiect1;
uses Forms,
Unit1 in “Unit1.pas’ {Form1}
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(Tform1,Form1);
Application.Run;
end.

Aşadar, aplicaţiile Delphi încă se mai bazează pe abilitatea programatorilor de a


scrie cod. Date fiind particularităţile limbajului Object Pascal, putem
concluziona că procesul de realizare a aplicaţiilor Delphi nu este întotdeauna un
exerciţiu în care rutina şi automatismele înseamnă totul. Aplicaţiile adevărate
presupun cunoştinţe temeinice de algortimică, modelare obiect orientată,
modularizare, precum şi o cunoaştere profundă a tuturor posibilităţilor oferite de
binomul Object Pascal – IDE Delphi.

2.4. Tipuri de date în Object Pascal


Prin intermediul tipurilor de date compilatorul este informat cu privire la modul în
care vor fi organizate datele programului în memorie. Ori de câte ori se declară o
variabilă, este necesară raportarea la un tip de dată. Anumite tipuri de date sunt deja
definite în limbaj (predefinite); alte tipuri pot fi definite de către utilizator. Pascal a
fost unul dintre primele limbaje de programare care a permis programatorului să
definească tipuri de date noi, conform cerinţelor programelor.
Despre limbajele care oferă suport pentru declararea de tipuri utilizator
(date ,pointer sau procedurale, în general) se spune că sunt limbaje cu suport
pentru tipizare.
Sintaxa Pascal referitoare la definirea şi instanţierea tipurilor de date este valabilă
şi în Object Pascal.

9
Observaţie
În mod uzual, identificatorii de tip în Object Pascal pot fi utilizaţi doar în
contextul definirii unui nou tip sau în contextul unei declaraţii de variabile.
Există, totuşi, câteva rutine care folosesc identidicatorii de tip ca parte a unei
instrucţiuni executabile. De exemplu, SizeOf( T ) returnează numărul de octeţi
necesari pentru o instanţă de tip T.

Tipuri de date simple


Fiecare tip de dată din lumea reală, oricât de complicat, poate fi exprimat cu
ajutorul unor componente simple, uşor de manipulat la nivel de microprocesor. În
Object Pascal, astfel de tipuri de date simple sunt separate convenţional în două
grupe: tipurile ordinale (care reprezintă informaţia cu ajutorul unor componente de
mărime variată, uşor de manipulat de către microprocesor) şi tipul real (care
aproximează informaţii ce pot fi reprezentate prin numere reale.

Tipuri ordinale
Dintre tipurile de date simple, cele mai simple sunt tipurile ordinale. Tipurile
ordinale reprezintă informaţia prin elemente discrete. Relaţia între elementele discrete
şi modul în care acestea sunt reprezentate în memorie instituie o relaţie de ordine
naturală între elemente. De aici denumirea de ordinal.
Object Pascal are trei grupe predefinite de tipuri ordinale: întregi, caractere şi
valori booleene. Grupele de tipuri ordinale definite de utilizator sunt: enumerările şi
subdomeniile.

Valorile oricărui tip ordinal formează o secvenţă ordonată astfel încât valoarea
ordinală a oricărei valori de tip ordinal este determinată de poziţia valorii înăuntrul
secvenţei ordonate. Exceptând valorile de tip întreg, care pot fi atât pozitive cât şi
negative, primul element al unui tip ordinal are indexul de poziţie 0, al doilea are
indexul de poziţie 1 ş.a.m.d.. Indexul de poziţie al unei valori de tip întreg este chiar
valoarea.
În acest context, toate tipurile ordinale partajează anumite operaţii comune care
permit manipularea valorilor lor conform Tabelului 2.1.

Observaţie
Pentru toate tipurile ordinale, Object Pascal asigură un mecanism typecasting
pentru convertirea valorilor întregi în valoarea ordinală corespunzătoare, asftel:

“Dacă T este numele unui tip ordinal şi X este o expresie întreagă, atunci
T(X) returnează o valoare de tip T a cărui valoare ordinală este X.

Low(T) Funcţie; returnează valoarea minimă a tipului


ordinal T.
High(T) Funcţie; returnează valoarea maximă a tipului
ordinal T.
Ord(X) Funcţie; returnează valoarea ordinală a

10
expresiei ordinale X, relativ la tipul ordinal
gazdă.
Pred(X) Funcţie; returnează predecesorul valorii
expresiei X. Pentru expresii întregi returnează
X-1.
Succ(X) Funcţie; returnează succesorul valorii
expresiei X. Pentru expresii întregi returnează
X+1.
Dec(V) Procedură; decrementează variabila V; Efectul
ei este echivalent cu V:=Pred(V).
Inc(V) Procedură; incrementează variabila V; Efectul
ei este echivalent cu V:=Succ(V).
Tabelul 2.1 Proceduri şi funcţii relativ la tipurile ordinale

Tipuri întregi
Tipurile întregi reprezintă informaţia ca numere întregi. În Object Pascal tipurile
întregi predefinite se împart în tipuri fizice (fundamentale) şi tipuri logice
(generice). În mod uzual în aplicaţii sunt preferate tipurile logice deoarece acestea
sunt implementate astfel încât să asigure cele mai bune performanţe pe o maşină şi un
sistem de operare date. Tipurile întregi fizice sunt utile atunci când se doreşte un
control strâns asupra numărului de octeţi afectaţi întregilor cu care lucrează
programul. Distribuţia exactă pe cele două tipuri a varietăţilor de întregi o prezentăm
în Tabelul 2.2 şi Tabelul 2.3.

Tip Ordin de mărime Reprezentare fizică


ShortInt -128..127 8 biţi /cu semn
SmallInt -32768..32767 16 biţi/cu semn
LongInt -2174486648..2147483647 32 biţi/ cu semn
Byte 0..255 8 biţi/fără semn
Word 0..65535 16 biţi/fără semn
Tabelul 2.2 Tipurile fizice

Tip Ordin de mărime Tip reprezentare fizică


Integer -32768..32767 16 biţi/cu semn/SmallInt
Integer -2147483648..2147483647 32 biţi/cu semn/LongInt
Cardinal 0..65535 16 biţi/fără semn/Word
Cardinal 0..2147483647 32 biţi/fără semn/LongInt
Tabelul 2.3 Tipurile logice
Să binevoim faţă de cititor şi să-i spunem că, utilizând tipurile fizice punem nişte
“contre” mai mari sau mai mici portabilităţii programelor noastre, ceea ce, la un
anumit nivel de profesionalism nu este lipsit de importanţă.

Tipurile de date întregi partajează toate operaţiile specifice tipurilor ordinale


având şi operaţii specifice numerelor. În Tabelul 2.4 prezentăm lista acestor operaţii.

11
Operaţia Rezultatul
Abs(X) Returnează valoarea absolută a întregului din X
X Div Y Returnează câtul împărţirii întregului X la întregul Y
X Mod Y Returnează restul împărţirii întregului X la întregul Y
Odd(X) Returnează TRUE dacă X este impar şi FALSE dacă X este par
Sqr(X) Returnează pătratul lui X
Tabelul 2.4 Alte operaţii cu numere întregi
Tipuri caracter
Implementările pe calculatoarele compatibile IBM-PC ale limbajului Pascal au
folosit de la început pentru reprezentarea noţiunii de caracter codul ASCII (American
Standard Code for Information Interchange). Schema de codificare ASCII utilizează
efectiv şapte biţi ai unei locaţii de memorie pentru reprezentarea unui caracter. În
mod evident, bitul suplimentar dublează numărul de caractere care pot fi reprezentate
pe opt biţi. Actuala definiţie a sistemului Delphi utilizează o variantă extinsă a
codului ASCII numită Schema de codificare extinsă ANSI (American National
Standard Institute). Codul extins ANSI permite, pe diferite platforme de operare,
includerea de caractere suplimentare, utile în comunicarea cât mai completă cu
utilizatorii calculatoarelor. Pentru acoperirea tuturor cerinţelor de comunicare a
calculatoarelor cu utilizatorii, în contextul internaţionalizării comunicaţiei prin
Internet, a fost specificat codul pe 16 biţi UNICODE, în care primele 256 de intrări
corespund direct celor 256 caractere definite în codul ANSI. Pentru a facilita
utilizarea acestor tipuri de reprezentare a caracterelor, Object Pascal defineşte două
tipuri fizice de date de tip caracter şi un tip generic sau logic de dată de tip caracter.
Tipurile fizice sunt prezentate în Tabelul 2.5.

Tipul Caracteristici
AnsiChar Caractere orientate byte, ordonate conform setului de caractere extins
ANSI
WideChar Caractere orientate word, ordonate conform setului de caractere
UNICODE. Primele 256 caractere UNICODE corespund setului
extins de caractere ANSI.
Tabelul 2.5 Tipuri fizice de caractere utilizabile în Delhpi

Tipul generic de caracter în Delphi se numeşte simplu char. În limbajul Pascal


clasic exista doar tipul char. În Delphi tipul char corespunde întotdeauna tipului
fizic AnsiChar.
Apelul funcţiei Ord (C) unde C este o valoare de tip caracter, returnează o
valoare de tip întreg folosită la reprezentarea caracterului C în memoria
microprocesorului.
De asemenea, Chr(X) este o funcţie care converteşte întregul X în caracterul
corespunzător codului X. În Delphi, acest apel este echivalent cu Char( X ).
Avem la dispoziţie şi funcţia UpCase care converteşte,dacă este cazul, un singur
caracter la valoarea lui majusculă.

Tipuri logice

12
Programatorii se lovesc de timpuriu de necesitatea de a lucra cu variabile cu două
stări. În Pascalul clasic tipul predefinit care răspunde unei astfel de cerinţe este tipul
boolean care poate lua una din valorile true sau false. În limbajul C valoarea
numerică o este asimilată cu false iar o valoare numerică nenulă este asimilată cu
true.
În Delphi există patru tipuri logice predefinite, prezentate în Tabelul 2.6.

Tip Mărimea reprezentării în octeţi


Boolean 1 octet
ByteBool 1 octet
WordBool 2 octeţi
LongBool 4 octeţi
Tabelul 2.6 Tipuri logice în Delphi

Variabilele de tip Boolean pot lua numai valorile False sau True. Variabilele de
tip ByteBool, WordBool şi LongBool pot lua alte valori ordinale interpretate prin
convenţie ca False pentru 0 sau True pentru orice valoare nenulă.

Tipuri enumerate
În mod uzual, un tip enumerat este capabil să reprezinte valori discrete care au
nume. Tipul Boolean din Object Pascal este un exemplu de tip enumerat predefinit
astfel:
type Boolean=(False, True);
Cele mai multe tipuri enumerate sunt pur şi simplu liste de identificatori unici pe
care programatorul îi va utiliza în situaţii dedicate.
Sintaxa de declarae este:

type <Tip_Enumerat>=(Identificator_1, Identificator_n,…, Identificator_n);

Tipul enumerat este ordinal. Prin urmare, identificatorii din lista enumerată au
asociat un număr numit valoare ordinală asociată. Primul identificator are valoarea
ordinală 0, al doilea are valoarea ordinală 1 ş.a.m.d..

Tipuri subdomeniu
Un tip subdomeniu reprezintă informaţii care pot lua valori de un anumit ordin al
unui tip ordinal corespunzător, altul decât subdomeniu.
Sintaxa de declarare a tipului subdomeniu rămâne aceeaşi din Pascal:

type <Subdomeniu>=<Valoare_De_Început>..<Valoare_De_Sfârşit>;

Variabilele tipului subdomeniu partajează toate caracteristicile tipului definitor.

Tipuri reale
Tipurile reale reprezintă informaţii numerice care pot avea atât parte întreagă cât
şi parte fracţionară. Object Pascal are şase specii de tipuri reale. Aceste tipuri se

13
deosebesc prin ordinul de mărime asociat şi precizia reprezentării corespunzătoare,
fapt ilustrat mai precis în Tabelul 2.7.

Tipul Minimum în Maximum în Cifre Nr.


valoare absoluţă valoare absolută semnificative octeţi
Real 2.9E-39 1.7E38 11-12 6
Single 1.5E-45 3.4EE38 7-8 4
Double 5.0E-324 1.7E308 15-16 8
Extended 3.4E-4932 1.1E4932 19-20 10
Comp 1.0 9.2E18 19-20 8
Currency 0.0001 9.2E14 19-20 8
Tabelul 2.7 Tipuri reale în Delphi

Numerele reale, în înţeles Object Pascal, nu sunt acelaşi lucru cu numerele reale
ca înţeles matematic. Un tip real Object Pascal este o submulţime strictă a lui R,ale
cărei elemente pot fi reprezentate în virgulă mobilă utilizând un registru cu număr
specific de biţi, conform standardului IEEE (Institute of Electrical and Electronic
Engineers). Într-o măsură mult mai mare decât numerele întregi, numerele reale
ridică probleme dintre cele mai neaşteptate celor care au aplicaţii în care precizia
reprezentării şi ordinul de mărime sunt esenţiale.
Unit-ul Delphi System pune la dispoziţia programatorilor o serie de rutine pentru
manipularea numerelor reale. Cele mai uzuale dintre ele sunt prezentate în Tabelul
2.8. Alte rutine de interes în acest scop sunt disponibile în unit-urile SysUtils şi Math.

Funcţia Ce returnează
Abs(x) Valoare absolută a lui x
ArcTan(x) Arctangenta lui x
Cos(x) Cosinusul argumentului x, considerat în radiani
Exp(x) Puterea x a numărului e
Frac(x) Partea fracţionară a lui x
Int(x) Partea întreagă a lui x. Atenţie! Int returnează o valoare de tip
real.
Ln(x) Logaritmul natural al numărului x
Pi Numărul π (3.1416…)
Round(x) Numărul întreg cel mai apropiat de x. Rezultatul returnat de
Round este de tip înreg. Formula “cel mai apropiat de x” devine
ambiguă când partea fracţionară este 0.5. Delphi lasă pe seama
sistemului să decidă cum efectuiază rotunjirea în această situaţie.
În mod uzual, cu procesor INTEL, recomandarea IEEE este de a
se rotunji la cel mai apropiat număr înreg par.
Sin(x) Sinusul trigonometric al argumentului x, considerat în radiani.
Sqr(x) Pătratul lui x. Adică x*x.
Sqrt(x) Rădăcina pătrată a lui x.
Trunc(x) Partea întreagă a lui x. Spre deosebire de Int, Trunc returnează o
valoare de tip întreg.

14
Tabelul 2.8 Funcţii pentru lucrul cu numere reale

Tipuri şir
În expresii, Delphi suportă trei specii de şiruri de caractere format fizic :
-scurt (ShortString);
-lung (AnsiString);
-mărit (WideString).
AnsiString, ShortString şi WideString pot fi utilizate combinat în atribuiri şi
expresii, Delphi executând automat conversiile necesare.
Atât tipul AnsiString cât şi tipul WideString păstrează caracterele în vectori
alocaţi dinamic, a căror lungime este plafonată doar de lungimea fizică a memoriei.
Diferenţa între aceste două tipuri constă în faptul că AnsiString păstrează caracterele
într-un arrray de caractere de tip char iar WideString păstrează caracterele într-un
array de caractere de tip WideChar. În mod uzual este utilizat tipul AnsiString, tipul
WideString fiind indispensabil dacă se realizează aplicaţii care utilizează setul de
caractere UNICODE.
Fizic, tipul ShortString este păstrat ca un array [0..255] of char. Prima poziţie în
şir păstrează lungime dinamică a şirului, care poate varia între 0 şi 255 caractere.
Caracterele efective ocupă poziţiile de la 1 până la 255. Tipul ShortString a fost
introdus din motive de compatibilitate cu Borland Pascal şi versiunile timpurii ale
mediului Delphi.
Tipul şir de caractere generic este cunoscut în Delphi ca string. Cu ajutorul
directivei de compilare {$H} putem stabili dacă string se referă la ShortString sau
AnsiString. Pentru {$H+}, care este starea implicită a directivei, string se referă la
un AnsiString.
Din motive de compatibilitate cu alte limbaje, Delphi suportă o clasă de şiruri de
caractere numite şiruri de caractere null-terminate. Nu există cuvinte rezervate sau
identificatori speciali pentru a indica folosirea şirurilor de caractere null-terminate.
Şirurile de caractere null-terminate se compun din caractere nenule urmate de
caracterul null (#0). Spre deosebire de tipurile Object Pascal AnsiString, ShortString
şi WideString, şirurile de caractere null-terminate nu au indicator de lungime separat.
Tabelul 2.9 prezintă câteva rutine utile în lucrul cu şiruri de caractere.

Funcţia Descrierea
Concat (S1, S2, S3) Returnează rezultatul concatenării şirurilor
S1, S2, S3.
Copy (S, Pos, Len) Returnează un subşir de lungime cel mult
Len caractere, care începe din poziţia Pos a
şirului de caractere S.
Delete (S, Pos, Len) Şterge cel mult Len caractere din şirul S,
începând cu poziţia Pos
Insert ( Sursa, Dest, Pos) Inserează şirul de caractere Sursa în variabila
şir Dest începând din poziţia Pos.
Length (S) Returnează lungimea dinamică a şirului S.
Similară funcţiei LEN din Basic sau funcţiei

15
strlen( ) din C/C++.
Pos (Subs,S) Returnează poziţia primei apariţii a
subşirului Subs în şirul S. Similară funcţiei
SUBSTR din Basic sau funcţiei strstr( ) din
C/C++.
SetLength(S, NewLen) Setează lungimea dinamică a variabilei şir S.
SetString Setează conţinutul unui şir de caractere.
Str (X, S) Converteşte expresia numerică X în şirul de
caractere S.
StringOfCharS Returnează un un şir de un număr dat de
caractere.
Val (S, V, Code) Converteşte şirul S la reprezentarea
numerică corespunzătoare.
Tabelul 2.9 Rutine sistem utile în lucrul cu şiruri de caractere

Tipuri de date structurate


La nivel elementar, cele mai utile tipuri de date sunt acelea care pot conţine
numere sau informaţii de tip caracter sau şir de caractere. Pornind de la tipurile
elementare de date, putem crea alte tipuri de date utile, prin combinarea mai multor
instanţe ale tipurilor elementare. Tipurile de date structurate furnizează capabilităţi de
creare a unor tipuri de date noi, prin extinderea definiţiei unor tipuri de date anterior
definite, astfel încât, în esenţă, mai multe valori ale tipului anterior definit, să poată fi
manipulate cât se poate de comod şi eficient. Aşadar, componentele tipurilor
structurate pot fi manipulate individual, sau ca întreg şi pot fi ele însele de tip
structurat. Tipurile structurate din Delphi sunt:
-Tipul înregistrare (record);
-Tipul tablou(array);
-Tipul mulţime;
-Tipul fişier;
-Tipul clasă;
-Tipul referinţă la clasă;
După cum se va vedea, noutatea faţă de Pascal o reprezintă introducerea
tipului clasă, prin care se operează nu doar o schimbare de nume ci o nouă
abordare a problemelor specifice programării obiect orientate. Tipul referinţă la
clasă, aduce un argument în plus în ceea ce priveşte încercarea platformei Delphi de
a se apropia de alte limbaje importante pentru paradigma obiect orientată.

Tipul înregistrare
Cuvântul rezervat record permite gruparea diferitelor tipuri de date într-un singur
tip. Sintaxa generală a declaraţiei unui tip înregistrare este:

type
:
<Identificator_Tip_Record>=record
<Câmp_1>:<Tip_Câmp_1>;
<Câmp_2>:<Tip_Câmp_2>;

16
:
<Câmp_n>:<Tip_Câmp_n>;
[case <Selector_parte_variabilă> : <Tip_Selector> of
<Val_1_Selector>:<Parte_variabilă_1>;
<Val_2_Selector>:<Parte_variabilă_2>;
:
<Val_k_Selector>:<Parte_variabilă_k>;]
end;
sau:
type
:
<Identificator_Tip_Record>=record
<Câmp_1>:<Tip_Câmp_1>;
<Câmp_2>:<Tip_Câmp_2>;
:
<Câmp_n>:<Tip_Câmp_n>;
[case <Tip_Selector> of
<Val_1_Selector>:<Parte_variabilă_1>;
<Val_2_Selector>:<Parte_variabilă_2>;
:
<Val_k_Selector>:<Parte_variabilă_k>;]
end;

După cum se vede, sintaxa generală permite, opţional, definirea de înregistrări cu


lungime variabilă, în două moduri:
În prima variantă, alegerea părţii variabile se face prin intermediul unei variabile
selector introdusă de clauza case.
În varianta a doua, alegerea părţii variabile se face în funcţie de valoarea unui
câmp discriminator care face parte din lista de câmpuri a părţii fixe. În acest caz
clauza case case introduce doar tipul selectorului.
Este cunoscut faptul că, diferitele instanţe ale unui tip înregistrare cu format
variabil, ocupă în memorie acelaşi număr de octeţi. De asemenea, procedeele de
adresare a câmpurilor unei variabile de tip înregistrare, sunt cele cunoscute de la
Borland Pascal: calificarea individuală cu punct sau calificarea globală cu
ajutorul clauzei with astfel:

:
var
Inreg:<TInregistrare>;
:
…Inreg . <Nume_Câmp> …

:
var
Inreg:<TInregistrare>;
:
with Inreg do

17
:
…<Nume_Câmp>…
:
end;

 Putem remarca faptul că tipul struct din C este echivalent cu tipul record fără
parte variabilă din Delphi. De asemenea, tipul union din C este echivalent cu tipul
record cu lungime variabilă din Delphi.

Tipul array
Structurile de tip array pot exista în variante unidimensionale sau
multidimensionale. Sintaxa generală pentru declararea unui tip array este
următoarea:

:
type
:
<TArray>=array [<Tip_ordinal_1>,<Tip_ordinal_2>,…,<Tip_ordinal_n>]
of <Tip_element>;
:

Deşi este utilizat în varianta trivială, în care tipurile ordinale după care se face
indexarea sunt subdomenii ale unor varietăţi de întregi, tipul array are şi posibilităţi
de indexare după alte tipuri ordinale, în funcţie de particularităţile problemei de
rezolvat.
Tipul mulţime
Cu ajutorul cuvântului rezervat set, se pot defini colecţii ordonate de cel mult 256
valori ordinale distincte. Sintaxe de declarare a tipului mulţime este:

:
type
:
<TSet>=set of <Tip_ordinal>;
:

Declararea variabilelor de tip mulţime respectă sintaxa cunoscută:

:
var
:
<VSety: <TSet>;
:

Notaţia [ ] desemnează mulţimea vidă.

18
Tipul fişier
Un tip file permite controlarea accesului la o secvenţă liniară de elemente care pot
fi de orice tip cu excepţia tipului file şi a tipului class. În Delphi, putem declara tipuri
de fişiere astfel:

:
type
:
<TFile>=file of <Tip_Record>;
sau
<TFile>=file ;
sau
<TFile>=textfile ;
:

Tipul file of corespunde fişierelor cu structură definită de utilizator din Pascal. În


Delphi, tipul file permite tratarea fişierelor la nivel fizic sau nedefint. În sfârşit,
tipul textfile este echivalentul tipului text din Pascal.
Asupra problematicii fişierelor în Delphi se va reveni, pe larg, într-un paragraf
afectat acestui scop, datorită problemelor deosebite pe care le ridică lucrul eficient cu
o structură de tip fişier.

Tipuri speciale

Tipul pointer
Un tip pointer este un tip de dată ale cărui valori sunt adrese către variabile ale
tipului de bază. Altfel spus, o variabilă de tip pointer poate conţine adresa din
memorie a unei variabile. Sintaxa de declarare a varietăţilor de pointeri din Delphi
este:

:
type
:
<Tip_Pointer_Structurat>= ^ <Tip_Definit_De_Utilizator>;
sau
<Tip_Pointer_Nedefinit>=pointer ;
:

În Tabelul 2.10 prezentăm rutinele specifice lucrului cu pointeri în Delphi.

Rutină Descriere
New Alocă memorie (din zona Heap a aplicaţiei) unei
variabile dinamice, prin intermediul unei variabile
pointer.
GetMem Alocă un block de memorie nedefinită (din zona
Heap a aplicaţiei) unei variabile dinamice, prin

19
intermediul unei variabile pointer.
@ Returnează adresa din memorie a unei variabile,
sau adresa punctului de intrare într-o procedură
sau funcţie.
Addr La fel ca la operatorul @
Assigned Verifică dacă o variabilă de tip procedural are
valoarea specială Nil.
Ptr Converteşte o adresă specificată prin <Segment>
şi <Ofsset) la o variabilă pointer.

Tabelul 2.10 Rutine pentru lucrul dinamic cu memoria

Rolul special al constantei Nil, precum şi cerinţele care privesc utilizarea corectă
a tipului pointer sunt cunoscute de la programarea în Pascal.

Tipuri procedurale
Object Pascal permite tratarea procedurilor şi a funcţiilor ca entităţi care pot fi
atribuite variabilelor şi transmise ca parametri (fapt deosebit de benefic, cel puţin în
programarea generică). Astfel de acţiuni sunt posibile datorită tipurilor procedurale.
Sintaxa de definire a tipurilor procedurale este:

:
type
:
<Tip_Procedural>= procedure [(Lista_parametri_formali)]
[of object] [<Conventie_de_apel>];
sau

<Tip_Procedural>= function [(Lista_parametri_formali)]:<Tip_rezultat>


[of object] [<Conventie_de_apel>];
unde <Conventie_de_apel> poate lua una din valorile:{ register, cdecl,
pascal, stdcall, safecall }.
:
Convenţiile de apel indică: ordinea în care sunt transmişi parametrii de la apelant
către apelat, cui îi aparţine responsabilitatea de a descărca stiva de parametri la
revenirea din apelat, precum şi implicarea sau nu a regiştrilor CPU în transferul
parametrilor.
Parametrii sunt transferaţi procedurilor sau funcţiilor prin intermediul regiştrilor
CPU sau prin intermediul stivei, depinde de convenţia de apel. Convenţia register
este singura în care transferul se face prin intermediul regiştrilor CPU.
Pe de altă parte, convenţiile register şi pascal sunt singurele în care se efectuiază
transmiterea parametrilor de la stânga la dreapta (adică, cel mai din stânga parametru
este evaluat şi transmis primul şi cel mai din dreapta parametru este evaluat şi
transmis ultimul). Convenţiile cdecl, stdcall şi safecall transmit parametrii de la
dreapta la stânga.

20
Exceptând convenţia cdecl, în toate celelalte eliminarea parametrilor din stivă este
realizată de procedurile sau funcţiile apelate. În cazul convenţiei cdecl, parametrii
sunt eliminaţi din stivă de apelant.
Convenţia de apel implicită este register.
Revenind, se poate observa că declararea tipurilor procedurale este asemănătoare
declarării antetelor procedurilor sau funcţiilor, cu deosebirea că lipseşte
identificatorul care urmează după cuvintele cheie procedure sau function la
definirea unui antet.
Analiza sintaxei de apel ne arată că există două categorii de tipuri procedurale:
Indicatori de procedură globală
Indicatori de metodă.

Indicatorii de procedură globală


Corespund unei declaraţii de tip procedural în care lipseşte clauza of object. Un
indicator de procedură globală poate referi o funcţie sau procedură globală şi este
specificat ca pointer care păstrează adresa unei proceduri sau funcţii globale.
Exemple:

:
type
TProcedura = procedure;
TSirProc = procedure (const S:string);
TMathFunc = function (X:double):double;
:

Indicatori de metodă
Corespund unei declaraţii de tip în care este prezentă clauza of object. Un
indicator de metodă poate referi o metodă de tip procedură sau funcţie care aparţine
unui obiect. Indicatorul de metodă este specificat cu ajutorul a doi pointeri: in primul
se păstrează adresa metodei; în al doilea se păstrează referinţa la obiect.
Exemple:

:
type
TGenMetoda = procedure of object;
TNotifyEvent=procedure (Sender:TObject) of object;
:

Valori de tip procedural


O valoare de tip procedural poate fi atribuită unei variabile procedurale. Valori
procedurale pot fi:
-Constanta Nil;
-O variabilă referinţă la un tip procedural;
-Un identificator de procedură sau funcţie globală;
-Un designator de metodă.

21
În contextul valorilor procedurale, un identificator de procedură sau funcţie
globală desemnează o valoare a unui pointer la o procedură globală iar un designator
de metodă indică o valoare a unui indicator de metodă.
Exemple:

:
type
TMainForm=class(TForm)
procedure ButtonClick(Sender:TObject);

end;
var
MainForm:TMainForm;
MathFunc:TMathFunc;
Onclick :TNotifyEvent;
function Tan(Unghi:double):double;
begin
Result:=Sin(Unghi)/Cos(Unghi);
end;
:

Variabilelor MathFunc şi OnClick li se pot atribui valori astfel:

:
MathFunc:=Tan;
OnClick:=MainForm.ButtonClick;
:

situaţie în care putem avea apeluri de tipul:

:
X:=MathFunc(X); {Echivalent cu X:=Tan(X)}
OnClick(Self);{Echivalent cu MainForm.ButtonClick(Self);
:

De semnalat faptul că, utilizarea unei variabile procedurale care are valoarea Nil
într-un apel determină o eroare de execuţie destul de neplăcută. Valoarea Nil este
utilizată pentru a indica faptul că o valoare procedurală este neatribuită, asfel că,
dacă există posibilitatea ca o variabilă procedurală să ia valoarea Nil, apelurile care
implică variabila trebuie să fie protejate de un test specific ca în exemplul:

if Assigned (OnClick) then OnClick(Self);

Funcţia standard Assigned returnează True dacă variabilei procedurale argument


i-a fost atribuită o valoare şi False în caz contrar.

Compatibilitatea tipurilor procedurale

22
Pentru a fi considerate compatibile, tipurile procedurale trebuie să aibă:
-aceeaşi convenţie de apel;
-acelaşi număr de parametri;
-parametri de acelaşi tip în poziţiile omoloage;
-În cazul funcţiilor, tipul returnat trebuie să fie identic.
Numele parametrilor nu are influenţă asupra compatibilităţii tipurilor procedurale.
Constanta Nil este compatibilă cu orice tip procedural.
Indicatorii de procedură globală şi indicatorii de metodă sunt întotdeauna mutual
incompatibili din punct de vedere al tipului.
Funcţiile şi procedurile standard, precum şi funcţiile şi procedurile imbricate nu
pot fi utilizate ca valori procedurale.

Tipurile procedurale în expresii


În mod obişnuit, utilizând o variabilă procedurală într-o instrucţiune sau o
expresie se apelează funcţia sau procedura asociată variabilei. Există o singură
excepţie: anume, atunci când compilatorul întâlneşte o variabilă procedurală în partea
stângă a instrucţiuni de atribuire, el ştie că în partea dreaptă se află o valoare
procedurală. De exemplu:

:
type
IntFunc=function:integer;
var
F:IntFunc;
N:integer;
function ReadInt:integer;far;
var
I:integer;
begin
read(I);
ReadInt:=I;
end;
begin
F:=ReadInt; {Atribuire de valoare procedurală}
N:=ReadInt; {Atribuire de rezultat apel funcţie }
end.
:
Compilatorul discerne tipul de atribuire după tipul variabilei din partea stângă a
instrucţiunii de atribuire. Din păcate există şi situaţii în care compilatorul nu poate
decide acţiunea pe care trebuie să o întreprindă din analiza contextului. Astfel, în
exemplul:

:
if F=ReadInt
then
Edit1.Text:=’Egalitate’;
:

23
compilatorul nu ştie dacă trebuie să compare valorea procedurală a lui F cu valoarea
procedurală a lui ReadInt pentru a determina dacă F referă ReadInt sau trebuie să
apeleze F şi ReadInt pentru a compara valorile returnate.
Sintaxa Object Pascal specifică faptul că prezenţa unui identificator de funcţie
într-o expresie înseamnă apelul acelei funcţii, astfel că efectul comparaţiei din
exemplul de mai sus este previzibil. Pentru a cere compararea valorilor procedurale
ale identificatorilor F şi ReadInt sintaxa obligatorie este:

:
if @F=@ReadInt
then
Edit1.Text:=’Egalitate’;
:

Aplicat unei valori procedurale sau unui identificator de funcţie sau procedură,
operatorul @ previne compilatorul să nu apeleze procedura şi, totodată converteşte
argumentul căruia i se aplică în pointer. Aşadar, @F converteşte F într-o variabilă
pointer fără tip care conţine o adresă iar @ReadInt returnează adresa funcţiei ReadInt.
Cele două valori pointer pot fi comparate pentru a determina dacă F referă ReadInt.
O altă situaţie în care putem folosi operatorul @ este prezentată în exemplul de
mai jos:

:
type
TSirComp=function(Sir1,Sir2:PChar):integer;
var
SirComp:TSirComp;

begin
@SirComp:=GetProcAdress(KernelHandle,’istrcmpi’);

end.
:

Funcţia GetProcAdress, definită în Windows API (în WinProcs unit), returnează


adresa unei funcţii exportate unui DLL ca o valoare pointer fără tip. Utilizând
operatorul @, rezultatul apelului funcţiei GetProcAdress poate fi atribuit variabilei
procedurale SirComp.
Remarcă
Pentru a consulta adresa de memorie a unei variabile procedurale, deci nu adresa
păstrată în ea, se apelează la dubla adresare a operatorului @. Astfel că, dacă @P
converteşte P la o variabilă pointer nedefinită, atunci @@P returnează adresa fizică a
variabilei P.

Tipurile variabile

24
Limbajul Object Pascal introduce, prin intermediul cuvântului cheie variant,
posibilitatea de a reprezenta valori al căror tip se modifică dinamic. În timp ce o
variabilă de orice alt tip este strict dependentă de acel tip, o variabilă de tip variant
poate primi valori de tipuri diferite, în timpul execuţiei programului.
Tipul variant are următoarele caracteristici:
O variabilă de tip variant poate conţine: valori întregi, valori reale, şiruri de
caractere, valori booleene, valori de tip data-şi-ora, precum şi obiecte OLE. Mai mult,
o variabilă de tip variant poate conţine tablouri de dimensiuni variabile, populate cu
elemente de oricare din tipurile mai sus precizate.
Valoarea specială de tip variant Unassigned este utilizată pentru a indica faptul
că unei variabile de tip variant nu i s-a atribuit, încă, o valoare.
Valoarea specială de tip variant Null este utilizată pentru a indica o dată lipsă
sau necunoscută.
Valorile de tip variant pot fi combinate între ele sau cu variabile statice de tip
integer, real, string şi boolean în expresii, compilatorul efectuând automat conversiile
necesare.
Dacă o variabilă de tip variant conţine un obiect OLE, atunci aceasta poate fi
folosită pentru a consulta şi seta proprietăţile obiectului sau pentru a invoca metodele
obiectului.
Variabilele de tip variant sunt întotdeauna iniţializate ca Unassigned când sunt
create pentru prima dată. Acest fapt este valabil indiferent dacă o variabilă de tip
variant este globală, locală sau parte a unei structuri de tip tablou, record sau obiect.

Exemplificăm, mai jos, modul de utilizarea a tipului variant:

var
V1,V2,V3,V4,V5: variant;
I:integer;
D:double;
S:string;
begin
V1:=1; {Valoare întreagă }
V2:=1234.5678; {Valoare reală }
V3:=’ Sir de caractere’; {Valoare şir de caractere }
V4:=’1000’; {Valoare şir de caractere }
V5:=V1+V2+V4; {Valoarea reală 2235.5678 }
I:=V1; {I=1 }
D:=V2; {D=1234.5678 }
S:=V3; {S=’Sir de caractere’ }
I:=V4’; {I=1000 }
S:=V5; {S=’2235.5678’ }
end;

De remarcat, faptul că deşi variabilele de tip variant ofera o mare flexibilitate în


manevrarea datelor, ele consumă mai multă memorie decât variabilele obişnuite.

25
O variabilă de tip variant ocupă 16 octeţi iar reprezentarea ei internă constă dintr-
un cod de tip şi o valoare (sau referinţă la o valoare) de un anumit tip dat, conform
codului de tip. Funcţia standard VarType returnează codul de tip al unei variabile de
tip variant. În Tabelul 2.11 prezentăm o listă parţială a constantelor utilizate pentru
identificarea tipului datelor păstrate într- variabilă de tip variant, împreună cu
valorile asociate şi semnificaţia lor.

Constanta Valoare Semnificaţia


varEmpty $0000 Variabilei nu i s-a atribuit o valoare; tipul i
se cunoaşte
varNull $0001 Variabila are tip necunoscut
varSmallInt $0002 Întreg cu semn pe 16 biţi (SmallInt)
varInteger $0003 Întreg cu semn pe 32 biţi (Integer)
varSingle $0004 Valoare virgulă mobilă simplă precizie
(Single)
varDouble $0005 Valoare virgulă mobilă dublă precizie
(Double)
varCurrency $0006 Valoare virgulă mobilă de tip Currency
varDate $0007 Valoare de tip Data şi Ora (tipul
TDateTime)
varOleStr $0008 Referinţă la un sir OLE (un şir UNICODE
alocat dinamic)
varDispatch $0009 Referinţă la un obiect OLE
varError $000A Cod eroare sistem de operare
varBoolean $000B Valoare booleană pe 16 biţi (tipul
WordBool)
varVariant $000C Valori variabile (utilizabila în cazul
tablourilor cu elemente variabile)
varUnknown $000D Referinţă la un obiect OLE necunoscut
varByte $0011 Întreg fără semn pe 8 biţi (Byte)
varString $0100 Referinţă la un şir de caractere de tip
AnsiString alocat dinamic
varTypeMask $0FFF Mască de biţi pentru extragere codului de tip
varArray $2000 Bit care indică un tablou de tip variant.
Tabelul 2.11 Lista parţială a constantelor sistem utilizate pentru controlul
conţinutului variabilelor de tip variant.
Lista completă a constantelor varXXXX returnate de funcţia standard VarType este
definită în unitul System. Help-ul Delphi online oferă, totodată,
informaţii detaliate cu privire la tipurile de conversii operate în expresii
care implică şi variabile de tip variant.

Data şi ora în Delphi


Tipul TDateTime este folosit de rutinele care permit manipularea informaţiilor
referitoare la dată şi oră. Tipul este declarat în unit-ul System astfel:

type TDateTime = type double;

26
Delphi păstrează valorile referitoare la dată şi oră în variabile de tip TDateTime
astfel:
Partea întreagă a valorii păstrate în variabila de tip TDateTime reprezintă
numărul de zile trecute începând din 30 decembrie 1889.
Partea fracţionară a valorii păstrate în variabila de tip TDateTime reprezintă
ora.
O parte din procedurile furnizate de unit-ul SysUtils pentru manipularea
variabilelor de tip TDateTime sunt:

procedure DateTimeToString ( var NewString: string; const Format:


string; DateTime: TDateTime);
DateTimeToString converteşte o variabilă de tip TDateTime la un şir de
caractere, utilizând un format de conversie. Formatele suportate sunt prezentate la
descrierea funcţiei FormatDateTime.

procedure DateTimeToSystemTime (DateTime:TDateTime; var SystemTime:


TSystemTime);
DateTimeToSystemTime converteşte data şi ora păstrate în format TDateTime în
formatul TSystemTime specific interfeţei Win32 API.

function DateTimeToStr( DateTime: TDateTime): string;


Dacă parametrul DateTime nu conţine o valoare referitor la dată atunci data
afişată este 00/00/00. Dacă parametrul DateTime nu conţine o valoare referitor la
timp, ora afişată este 00:00:00 AM.
Exemplu:

procedure TForm1.Button1Click(Sender: TObject);


begin
Label1.Caption := DateTimeToStr(Now);
end;

Acest exemplu presupune că pe forma aplicaţiei curente se află o etichetă (referită


de Label1) şi un buton asociat cu un eveniment OnClick. La efectuarea unui click pe
buton eticheta va arăta data şi ora curentă a sistemului (parametrul Now).

function DateTimeToFileDate(DateTime: TDateTime): integer;


DateTimeToFileDate converteşte o valoare de tip TDateTime la o valoare Dată-Timp
de tip DOS. Rutinele FileAge, FileGetDate, şi FileSetDate operează asupra vaorilor
Timp-Dată specifice DOS (Câmpul Time al tipului TSearchRec din Dos poate
conţine o valoare Dată-Timp de dip DOS).

function DateToStr(Date: TDateTime): string;


Converteşte o dată de tip TDateTime la un şir de caractere.
Conversia foloseşte formatul indicat de variabila globală ShortDateFormat.
Exemplu:

27
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption := DateToStr(Date);
end;

function Date: TDateTime;


Returnează data curentă în format TDateTime.
Exemplu :

procedure TForm1.Button1Click(Sender: TObject);


begin
Label1.Caption := 'Today is ' + DateToStr(Date);
end;

Alte funcţii a căror descriere poate fi găsită cu ajutorul Help-ului Delphi sunt:

function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;


function DayOfWeek(Date: TDateTime): integer;

Operatori şi expresii în Delphi


Doar posibilitatea de a reprezenta informaţii în memorie în diferite moduri nu
rezolvă problemele unui program. Un program adevărat utilizează a doua
capabilitate importantă a unui sistem de calcul exprimată prin puterea de a efectua
calcule şi transformări asupra datelor. La nivelul limbajelor de programare,
componentele care permit valorificarea puterii de calcul a unui sistem de calcul sunt:
operatorii, variabilele şi constantele. Combinarea acestora, după reguli conforme
celor invăţate la aritmetică sau la logică, duce la realizarea, şi în Delphi, a
expresiilor. Specificarea expresiilor în Object Pascal, trebuie aşadar să ţină cont de
ordinea de evaluare a a acestora. Tabloul precedenţelor, valabil în Object Pascal,
este prezentat în Tabelul 2.12.

Operatori Categoria
. ^ Dereferenţiere câmp sau pointer (Precedenţa cea
mai înaltă)
@ not Operatori unari
* / div mod as and shl Operatori multiplicativi şi de typecasting
shr
+ - or xor Operatori conjunctivi(aditivi)
= <> > < <= >= in is Operatori de comparare şi apartenenţă (Precedenţa
cea mai joasă.
Tabelul 2.12 Operatorii Object Pascal grupaţi pe categorii de precedenţă.

28
De remarcat faptul că o parte din operatorii prezentaţi în Tabelul 2.12 au două
întrebuinţări : operatori la nivel de bit sau operatori logici în funcţie de
contextul în care sunt utilizaţi. În Tabelul 2.13 prezentăm, împreună cu
operatorii dedicaţi lucrului la nivel de bit şi operatorii cu dublă
întrebuinţare.

Operator Semnificaţie
not negaţia logică asupra variabilelor booleene / inversarea poziţiilor
binare ale unei variabile convenabile aplicării operatorului.
and şi logic asupra variabilelor booleene / şi logic asupra altor tipuri de
operatori convenabili.
or sau logic asupra variabilelor booleene / sau logic asupra altor tipuri
de operatori convenabili.
xor sau logic exclusiv asupra variabilelor booleene / sau logic exclusiv
asupra altor tipuri de operatori convenabili.
shl Shiftare logică la stânga
shr Shiftare logică la dreapta
Tabelul 2.13 Operatori la nivel de bit în Object Pascal

2.5 Instrucţiuni Object Pascal


Ca în oricare alt limbaj de programare, în Object Pascal instrucţiunile permit, în
ultimă analiză, controlarea ordinii de evaluare a expresiilor sau a numărului de
treceri peste o expresii cu scopul de a o evalua. Cu ajutorul instrucţiunilor se
reprezintă algoritmul de rezolvare a unei probleme date. Deşi acum pare trivial,
trebuie să atragem atenţia asupra faptului că, pentru paradigmele de programare
procedural-secvenţiale, stabilirea unui set minimal de instrucţiuni pentru
reprezentarea structurilor de prelucrare, este un moment–cheie în specificarea unui
limbaj de programare.
Oferta Object Pascal în ceea ce priveşte reprezentarea instrucţiunilor de prelucrare
se compune din:
-Instrucţiuni simple;
-Instrucţiuni structurate.

Instrucţiuni simple
Instrucţiunile simple modifică conţinutul memoriei prin asignarea unei valori,
apelează o procedură sau o funcţie sau (ceea ce nu este tocmai în spirit profesional)
determină transferarea necondiţionată a controlului execuţiei unui program la o
instrucţiune oarecare a programului. Instrucţiunile simple în Object Pascal sunt:
-Instrucţiunea de atribuire;
-Apelul de subrutină;
-Instrucţiunea goto;

Instrucţiunea de atribuire
Sintaxa Object Pascal pentru o instrucţiune de atribuire este:

29
<Identificator_Variabilă>:=<Expresie>;

Toate consideraţiile care se fac în Pascal pe marginea acestei instrucţiuini sunt


valabile şi în Object Pascal. Evident, apar o serie de observaţii legate de introducerea
de tipuri de date noi, conversia acestora şi rezolvarea automată a problemelor de
compatibilitate la atribuiri. Iată un exemplu de situaţie simplă în care atenţia
programatorului trebuie să fie încordată: un caracter poate fi întotdeauna atribuit unei
variabile şir; un şir de caractere nu poate fi atribuit unei variabile de tip caracter.

Apelul de subrutină
Un apel de subrutină determină transferul controlului execuţiei programului către
o procedură, funcţie sau metodă de prelucrare,execuţia blocului de instrucţiuni
aferent, urmată de revenirea şi continuarea execuţiei cu instrucţiunea carea urmează
apelului de subrutină. Sintaxa unui apel de subrutină se circumscrie regulilor
cunoscute deja de la studiul limbajului Pascal.

Instrucţiunea goto
Deşi controverstă, mai ales din perspectiva principiilor programării structurate,
instrucţiunea goto are drept de cetate şi în Object Pascal. Se cunoaşte faptul că, de
exemplu, şi limbajul C, specifică posibilitatea utilizării instrucţiunii goto.
Recomandarea valabilă în orice limbaj de programare este să nu se abuzeze de
utilizarea acestei instrucţiuni, deoarece, în caz contrar, calitatea programului are de
suferit.

Instrucţiuni structurate
Cu ajutorul instrucţiunilor structurate, putem grupa prelucrările simple sau
compuse în conformitate cu cerinţele de moment, putem ramifica prelucrările în
funcţie de valoarea anumitor condiţii logice, putem executa în mod repetat anumite
prelucrări. Adică, pot fi reprezentate structurile fundamentale de prelucrare.
Oferta Object Pascal pentru reprezentarea structurilor fundamentale de prelucrare
este următoarea:
-Instrucţiunea compusă;
-Instrucţiunile condiţionale (if, case);
-Instrucţiunile repetitive (for, while, repeat);
-Instrucţiunea with.

Instrucţiunea compusă
Instrucţiunile compuse specifică o ordine în care instrucţiunile, pe care le conţin,
trebuie executate. Dacă secvenţa de instrucţiuni este delimitată de begin şi end,
atunci întreaga secvenţă poate fi tratată ca o instrucţiune şi utilizată ca atare în
construcţiile sintactice Object Pascal care o permit.
Instrucţiuni condiţionale

Instrucţiunea if
Sintaxa instrucţiunii if este:

30
if <Expresie>
then
<Instrucţiune_1>
[else
<Instrucţiune_2>];
<Expresie> trebuie să returneze un rezultat de tip boolean. Dacă <Expresie>
returnează TRUE, atunci va fi executată <Instrucţiune_1>, care urmează clauze then.
Dacă <Expresie> returnează FALSE şi clauza else este prezentă, atunci se execută
<Instrucţiune_2> care urmează clauzei else. Dacă <Expresie> returnează FALSE şi
clauza else lipseşte, atunci se execută instrucţiunea care urmează după instrucţiunea
if, privită ca întreg. <Instrucţiune_1> şi <Instrucţiune_2> pot fi simple sau compuse.

Instrucţiunea case
Sintaxa instrucţiunii case este:

case <Selector> of
<Val_Sel_1>: <Instrucţiune_1>;
<Val_Sel_2>: <Instrucţiune_2>;
:
<Val_Sel_n>: <Instrucţiune_n>
end;

sau

case <Selector> of
<Val_Sel_1>: <Instrucţiune_1>;
<Val_Sel_2>: <Instrucţiune_2>;
:
<Val_Sel_n>: <Instrucţiune_n>
else
<Instrucţiune>
end;

Instrucţiunea case permite execuţia instrucţiunii prefixate de o constantă egală cu


valoarea variabilei selector sau de un domeniu care conţine valoarea variabilei
selector. De remarcat faptul că, spre deosebire de implementarea Pascal a instrucţiunii
case, implementarea Object Pascal nu permite intersecţii nevide între constantele care
prefixează instrucţiunile într-un case. Dacă nici o constantă-prefix nu este egală cu
valoarea variabilei selector, atunci se va executa instrucţiunea asociată clauzei else,
dacă aceasta este prezentă, sau instrucţiunea care urmează instrucţiunii case în caz
contrar. <Instrucţiune_1>,…,<Instrucţiune_n> pot fi simple sau compuse.
Exemple:

:
case Operator of
Plus: X := X + Y;

31
Minus: X := X - Y;
Times: X := X * Y;
end;
:

sau

:
case I of
0, 2, 4, 6, 8: Edit1.Text := 'Cifra para';
1, 3, 5, 7, 9: Edit1.Text := 'Cifra impara';
10..100: Edit1.Text := 'Intre 10 si 100';
else
Edit1.Text := 'Negativ sau mai mare decat 100';
end;
:

sau

:
case MySelector of
5: Edit1.Text := 'Caz special';
1..10: Edit1.Text := 'Caz general';
end;
:

Instrucţiuni repetitive
Repetitiva cu număr cunoscut de paşi
Pentru reprezentarea secvenţelor repetitive cu număr cunoscut de paşi în Object
Pascal, la fel ca în Pascal, avem la dispoziţie instrucţiunea cu sintaxa generală:

for <Contor>:=<Val_Inceput> to <Val_Sfarsit> do


<Instrucţiune>;

sau

for <Contor>:=<Val_Inceput> downto <Val_Sfarsit> do


<Instrucţiune>;

<Instrucţiune> poate fi simplă sau compusă. Se mai numeşte şi corpul repetitivei.


<Contor> este o variabilă de tip ordinal care va lua la fiecare trecere corpul
repetitivei valorile cuprinse între <Val_Inceput> şi <Val_Sfârşit>, ascendent sau
descendent, după cum este prezentă clauza to sau clauza downto. Nu avem
comentarii deosebite de făcut faţă de semantica Pascal a instrucţiunii.

Repetitive cu număr necunoscut de paşi

32
Pentru reprezentarea repetitivelor cu număr necunoscut de paşi la care se preferă
condiţionarea anterioară avem sintaxa:

while <Expresie> do
<Instrucţiune>;

<Instrucţiune> poate fi simplă sau compusă.


Semantica instrucţiunii este imediată: cât timp în urma evaluării expresiei
<Expresie> se obţine TRUE, se va executa corpul repetitivei. În caz contrar, se predă
controlul primei instrucţiuni care urmează după instrucţiunea while.
Instrucţiune while este preferată atunci când o anumită secvenţa de instrucţiuni
poate fi executată niciodată sau de mai multe ori.
Pentru reprezentarea repetitivelor cu număr necunoscut de paşi la care se preferă
condiţionarea posterioară avem sintaxa:

repeat
<Instrucţiune>
until <Expresie>;

<Instrucţiune> poate fi simplă sau compusă.


Semantica instrucţiunii este imediată: cât timp în urma evaluării expresiei
<Expresie> se obţine FALSE, se revine la execuţia corpului repetitivei. În caz
contrar, se predă controlul primei instrucţiuni care urmează după instrucţiunea repeat.
Instrucţiune repeat este preferată atunci când o anumită secvenţa de instrucţiuni
poate fi executată cel puţin odată.

Instrucţiunea with
Instrucţiunea with este utilizată pentru simplificarea dereferenţierii câmpurilor
unor variabile record şi a membrilor unui obiect. Astfel, în Object Pascal este foarte
frecvent întâlnită o situaţie de genul:

procedure TForm1.Button1Click(Sender: TObject);


begin
ListBox1.Clear;
ListBox1.MultiSelect := True;
ListBox1.Items.Add('One');
ListBox1.Items.Add('Two');
ListBox1.Items.Add('Three');
ListBox1.Sorted := True;
ListBox1.Font.Style := [fsBold];
ListBox1.Font.Color := clPurple;
ListBox1.Font.Name := 'Times New Roman';
ListBox1.ScaleBy(125, 100);
end;

Dacă programatorul utilizează instrucţiunea with secvenţa de cod de mai sus va


arăta astfel:

33
procedure TForm1.Button1Click(Sender: TObject);
begin
with ListBox1 do
begin
Clear;
MultiSelect := True;
Items.Add('One');
Items.Add('Two');
Items.Add('Three');
Sorted := True;
Font.Style := [fsBold];
Font.Color := clPurple;
Font.Name := 'Times New Roman';
ScaleBy(125, 100);
end;
end;

O utilizare similară este posibilă şi în cazul variabilelor record.

2.6 Proceduri şi funcţii în Object Pascal


Introduse în Pascal ca suport pentru modularizare şi abstractizare, procedurile şi
funcţiile joacă acelaşi rol şi în Object Pascal. Toate menţiunile Pascal referitoare la
proceduri şi funcţii sunt în vigoare şi în Object Pascal. O imagine mai precisă asupra
semanticii procedurilor şi funcţiilor în Object Pascal o putem obţine urmărind
diagramele de sintaxă de mai jos.
Declararea unei proceduri

antet procedură ; bloc subrutina ;

Antet procedură
procedur
e Identificator
Identificator metodă
calificată

Listă parametri formali

Bloc subrutină bloc


register ;
directivă externă

pascal bloc asm

cdecl
forward

stdcall 34

safecall
Declararea unei funcţii

antet funcţie ; bloc subrutina ;

Antet funcţie

function Identificator

Identificator metodă
calificată

Listă parametri formali

; Tip rezultat

Bloc subrutină

bloc
register ;
directivă externă

pascal bloc asm

cdecl
forward

stdcall

safecall 35
Din analiza sumară a diagramelor de sintaxă, rezultă o serie de particularităţi
Object Pascal în utilizarea procedurilor şi a funcţiilor. Aceste particularităţi se referă
la posibilitatea de a alege, în funcţie de context, convenţia de apel, precum şi la
protocolul de utilizare a directivelor externe în cazul în care procedurile sau funcţiile
fac parte din potenţialul de calcul al bibliotecilor de legături dinamice (DLL).
Deocamdată, să mai menţionăm un amănunt care nu transpare din analiza diagramei
de sintaxă a funcţiei.
Pentru a returna prin nume o valoare de un anumit tip, în secţiunea executabilă a
unei funcţii trebuie să apară o atribuire de tipul:

<Nume_Funcţie>:=Result;

Variabila Result este creată automat în corpul unei funcţii Object Pascal, având
tipul acesteia.
Precizările care se referă la vizibilitatea variabilelor în blocurile procedurale,
precum şi la transmiterea parametrilor între <apelat> şi <apelant> sunt similare celor
cunoscute de la programarea în Pascal.

2. 7 Unit-uri Object Pascal


Structura de principiu a unui unit Object Pascal este:

ANTET unit <Nume unitate>;


SECŢIUNEA DE INTERFAŢĂ interface
[uses <Lista alte unităţi>
<Declaraţii globale>
<Lista de funcţii şi proceduri
globale>]

SECŢIUNEA DE IMPLEMENTARE implementation


[uses <Lista unităţi utilizate>
<Declaraţii locale>
<Implementare proceduri şi funcţii
>]

SECŢIUNEA DE INIŢIALIZARE [initialization


<Secvenţa de iniţializarea unit-
ului>]

SECŢIUNEA DE FINALIZARE [finalization


<Secţiunea de finalizare a unit-
ului>]
end.

Analiza structurii de mai sus permite următoarele aprecieri:

36
 Secţiunea de interfaţă a unităţii este destinată declarării acelor resurse care
urmează să fie exportate către alte programe sau unit-uri (constante, tipuri, variabile,
proceduri,funcţii);
 Secţiunea de implementare este porţiunea din unit în care apare codul
complet al unităţilor de prelucrare exportate, precum şi codul unor unităţi de
prelucrare de interes local, dacă este cazul.
 Secţiunea de iniţializare a unit-ului este secţiunea în care apare, opţional,
codul care realizează iniţializarea mediului în care urmează să lucreze capabilităţile
unit-ului. Acest cod este executat la începerea execuţiei programului, deci înainte de
a se preda controlul instrucţiunilor programului principal. Dacă sunt mai multe unit-
uri care au secvenţe de iniţializare, acestea se vor executa în ordinea în care sunt
declarate unit-urile în lista asociată clauzei uses.
Secţiunea de finalizare, o noutate Object Pascal, în materie de modularizare a
aplicaţiilor în context Delphi, este utilizată pentru a permite o serie de prelucrări
specifice terminării apelului la resursele unui unit. Această secţiune este opţională,
dar poate apare numai în condiţiile în care există şi o secvenţă de iniţializare.
Instrucţiunile care urmează cuvântului cheie finalization sunt executate la terminarea
programului. Ne putem imagina următorul scenariu plauzibil pentru utilizarea celor
două secţiuni: toate resursele alocate sau deschise în secvenţa de iniţializare
(memorie, fişiere,etc.) sunt eliberate sau închise în secţiunea de finalizare. De
asemenea, secvenţa de finalizare poate elibera orice resursă necesară pentru execuţia
normală a unit-ului însuşi. Dacă sunt mai multe unit-uri care au secvenţe de
finalizare, acestea se vor executa în ordinea inversă în care apar în unit-urile în lista
care face obiectul clauzei uses.
Aşadar, programarea orientată pe unit-uri presupune abilitatea programatorului
de a specifica resurse statice generice (constante, tipuri, variabile) şi, mai ales,
abilitatea de a specifica unităţi de prelucrare cu interfaţă eficientă şi stabilă. Dacă
există astfel de abilităţi, atunci codul obţinut este fiabil, rezistent la modificări şi
versatil. La nevoie, datorită localizării indusă de abstractizare, modificările se fac cu
minim de efort.
Unit-urile oferă pentru programator următoarele avantaje:
 Sunt păstrate în format binar, ceea ce înseamnă scurtarea timpului de generare
a fişierelor executabile;
 Pot fi utilizate ca suport pentru promovarea încapsulării acelor resurse care
sunt critice pentru existenţa aplicaţiei (Se operează o distincţie clară între ceea ce
trebuie văzut din afara unit-ului şi ceea ce este de interes local acestuia);
Constituie o bază a promovării abstractizării, în sensul că pot exista două
unităţi cu aceeaşi interfaţă dar cu implementări diferite, înlocuirea unei unităţi cu alta
nefiind problematică din punct de vedere sintactic.
Referitor la utilizarea unit-urilor, adăugăm următoarele precizări:
 <Nume unitate> este identificatorul unit-ului şi trebuie să coincidă cu
numele fişierului în care este definit acesta. De remarcat faptul că unit-urile
folosite la un moment dat trebuie să aibă nume diferite.
 <Lista alte unităţi> reprezintă lista altor unităţi folosite de către unitatea
curentă. Nu se permit referinţe circulare.

37
 <Declaraţii globale> indică declaraţiile de constante, tipuri,variabile,etc.
vizibile atât în cadrul unit-ului curent cât şi în toate unităţile şi programele care îl
utilizează.
 <Lista de funcţii şi proceduri globale> specifică antetele funcţiilor şi/sau
procedurilor declarate ca vizibile în unit şi în toate unităţile şi programele care îl
utilizează.
 <Lista unităţi utilizate> reprezintă lista altor unităţi utilizate de către unitatea
curentă, dar necesare doar părţii de implementare. Sunt permise referinţe circulare
între unităţi.
 <Declaraţii locale> permite specificarea unor constante, variabile, etc.
necesare doar părţii de implementare, deci invizibile pentru alte unităţi sau programe.
 <Implementare proceduri şi funcţii> ocazionează implementarea procedurilor
şi funcţiior ale căror antete au fost anunţate în interface ,precum şi a altor proceduri
şi funcţii necesare părţii de implementare.

38
3. Concepte avansate în programarea Object
Pascal
În această secţiune ne propunem să luăm în discuţie o serie de aspecte care
subliniază pregnant noutatea ofertei Delphi, în principal, în materie de programare
obiect orientată. Se va putea observa la finalul secţiunii, efortul făcut de cei care au
specificat Object Pascal, pentru a apropia acest limbaj de standardele de facto în
programarea obiect orientată şi, totodată, de a păstra proprietăţile limbajului Pascal
specificate de primul lui părinte Niklaus Wirth.

3.1 Clase în Object Pascal


Programatorii Pascal îşi amintesc de faptul că, ceea ce în modelarea obiect
orientată se numeşte clasă, în Pascal are ca echivalent tipul obiect. Ca formă de
comunicare a ideilor referitoare la soluţia obiect orientată a unei probleme, tipul
obiect poate fi utilizat ca substitut pentru clasă. Din punct de vedere al sintaxei de
definire a unei clase, vom vedea că, în Object Pascal s-a adoptat cuvântul cheie class
în locul cuvântului cheie object, pentru a defini o clasă. Coceptul de clasă în
programarea Object Pascal introduce şi o serie de alte elemente care fac din
programarea pe obiecte un instrument deosebit de puternic, în realizarea de aplicaţii
fiabile, extensibile, puternic interactive, inclusiv în faza de proiectare asistată de
mediul Delphi. Extensia cheie a limbajului Object Pascal pentru mărirea
interactivităţii aplicaţiilor Delphi se referă la introducerea conceptului de
proprietate.
O dată de tip class este o structură care se compune dintr-un număr fix de
componente(membri). Componentele posibile ale unei clase sunt: câmpurile,
metodele şi proprietăţile. Spre deosebire de alte tipuri, un tip class poate fi declarat
doar în secţiunea de declarare a tipurilor cea mai exterioară a programului sau unit-
ului. Astfel că, un tip class nu poate fi declarat în secţiunea de declarare a variabilelor
sau în interiorul procedurilor, funcţiilor sau în blocul de definiţie al metodelor.
Sintaxa de declarare a tipului class este:

<TClasa_Utilizator>=class [(<TClasa_Definitoare>)]
public
<Nume_Camp>:<Tip_Camp>;

<Antet_Metoda>

property
<Nume_Proprietate>:<Tip_Proprietate>
read <Nume_Camp/Nume metoda>
write < Nume_Camp/Nume metoda>

private
:
protected
:
published

39
:
end;

Domenii de vizibilitate
Componentele unei clase pot avea domenii de vizibilitate diferite, în funcţie de
directiva de specificare a vizibilităţii sub a cărei incidenţă se află. După cum se vede
şi mai sus, aceste directive de specificare a vizibilităţii sunt: private, protected,
public şi published. Aceste directive restricţionează vizibilitatea componentelor în
situaţia în care alte unit-uri forţează accesul la ele. În interiorul unit-ului în care este
definită clasa, toate componentele sunt vizibile.

Observaţie
Spre deosebire de mulţi alţi identificatori utilizaţi în declararea tipurilor,
directivele de specificare a vizibilităţii nu sunt cuvinte rezervate în afara contextului
care ocazionează declararea clasei. În practică se recomandă, totuşi, să le tratăm ca şi
când ar fi cuvinte rezervate, în adevăratul sens al cuvântului.

Directivele de specificare a vizibilităţii nu trebuie menţionate explicit pentru


fiecare membru al clasei. Regula este ca după o directivă de specificare a vizibilităţii
să urmeze toţi membrii care au acelaşi tip de vizibilitate. Un domeniu de vizibilitate
se termină în momentul în care este întâlnită altă directivă de specificare a
vizibilităţii.

Specificatorul de vizibilitate private


Acest specificator este cel mai restrictiv. Membrii privaţi ai unei clase nu se văd
în afara unit-ului în care este definită clasa. De obicei se declară ca private
componente ale căror valori sunt critice pentru comportamentul instanţelor clasei
respective. Dacă avem nevoie de două clase care trebuie să aibă acces reciproc la
componentele lor, atunci aceste clase se vor defini în acelaşi unit. Detaliile de
implementare sunt complet ascunse faţă de end-user.

Specificatorul de vizibilitate protected


Specificatorul de vizibilitate protected relaxează restricţiile de vizibilitate, în
sensul că, componente declarate ca protected într-o clasă pot fi accesate de obiecte
care fac parte din domeniul clasei; altfel spus, descendenţii unei clasei au acces la
componentele din secţiunea protected a acesteia. Detaliile de implementare rămân în
continuare ascunse faţă de end-user.

Specificatorul de vizibilitate public


Componentele publice sunt vizibile oriunde este vizibilă şi clasa. Nu se aplică alte
restricţii asupra componentelor publice ale unei clase.

Specificatorul de vizibilitate published


Declararea unei componente ca fiind de tip published, informează compilatorul
că trebuie să genereze informaţii de tip run-time (RunTime Type Information-
RTTI) pentru componenta respectivă.

40
Informaţiile de tip run-time permit unei aplicaţii externe să afle date despre
câmpurile, metodele sau proprietăţile unui obiect, despre clasa definitoare a
obiectului, etc.
Pe timpul execuţiei unui program, din punct de vedere al vizibilităţii, o
componentă published se comportă ca şi când ar fi o componentă de tip public.
Toate componentele published sunt vizibile în orice unit unde clasa care le
încapsulează este vizibilă. Diferenţa constă în faptul că, o aplicaţie externă poate
obţine informaţii de tip run-time despre componentele published.
Ca un exemplu, inspectorul de obiecte al sistemului Delphi foloseşte interfeţele
published ale obiectelor din Paleta de Componente a sistemului Delphi pentru a
determina ce proprietăţi şi evenimente trebuie vizualizate în timpul proiectării unei
aplicaţii.
Există anumite restricţii în ceea ce priveşte modul de utilizarea al directivei
published.
O clasă poate avea componente published dacă este compilată sub incidenţa
directivei {$M} având starea {$M+} sau dacă este derivată dintr-o clasă care deja a
fost compilată astfel încât să aibă componente published. Directiva {$M}
controlează generarea RTTI.
Un câmp definit într-o secţiune published trebuie să fie de tip clasă. Câmpurile
de orice alt tip trebuie plasate în secţiunile public, protected sau private.
Proprietăţile published sunt restricţionate din punct de vedere al tipului. Sunt
acceptate proprietăţi de tip:
-ordinal;
-real(Single, Double, Extended, Comp, nu şi real);
-şir de caractere;
-mulţime (small set);
-clasă;
-identificator de metodă (dar nu tip procedural global)
Small set desemnează un tip mulţime al cărui tip de bază este ordinal şi ale cărui
valori ordinale sunt cuprinse între 0 şi 50.

Metode
În procesul de definire a unei clase, metodele leagă codul cu tipurile de date pe
care codul este abilitat să le manipuleze. În acest scop, metodele au dreptul să
acceseze câmpurile unui obiect fără ca acestea să-i fie trimise explicit ca parametri.
Declararea unei metode are două părţi: declararea signaturii metodei în procesul
de definire a clasei şi implementarea corpului metodei în afara definiţiei clasei, dar
în acelaşi unit în care s-a definit şi clasa. De la programarea Pascal OO se ştie că
declararea signaturii este asemănătoare unei declaraţii forward de procedură sau
funcţie. De subliniat ceea ce, de asemenea, se ştie de la Pascal OO şi anume faptul că
implementarea corpului metodei presupune ca antetul ei să specifice numele clasei
din a cărei definiţie face parte metoda. Referitor la implementarea unei metode mai
facem următoarele precizări:
În interiorul corpului unei metode, o instrucţiune care apelează o funcţie sau o
procedură permite utilizarea designatorilor de metodă calificată pentru a activa o
anumită metodă a unei clase. Un designator de metodă poate fi o variabilă referinţă la

41
un obiect sau o referinţă la o clasă. Cuvântul rezervat inherited desemnează
strămoşul tipului obiect care include metoda. Prezentăm în continuare un exemplu de
definire a unei clase împreună cu implementarea metodei aferente în care se
utilizează şi cuvântul rezervat inherited.
type
TFramedLabel = class(TLabel)
protected
procedure Paint; override;
end;
:
procedure TFramedLabel.Paint;
begin
inherited Paint;
with Canvas do
begin
Brush.Color := clWindowText;
Brush.Style := bsSolid;
FrameRect(ClientRect);
end;
end;

În interiorul blocului care corespunde implementării unei metode, regulile de


vizibilitate sunt, după cum poate că s-a înţeles, diferite de regulile de vizibilitate
pentru proceduri şi funcţii oarecare. Accesul la componentele unui obiect din
interiorul unei metode este simplificat datorită inserării automate în codul unei
metode a unei calificări de tipul:

with Self do
begin
...
end;

Variabila Self este o variabilă de acelaşi tip cu clasa în care apare metoda.
Implicit metodele sunt statice. Object Pascal propune însă şi alte tipuri de metode, din
perspectiva modului de rezolvare a apelului acestora. Le prezentăm în Tabelul 3.1.

Directivă Efect
Virtual Metoda apelată este determinată cu ajutorul tabelei VMT
Dynamic Metoda apelată este determinată cu ajutorul tabelei de metode
dinamice
Message Metoda apelată este determinată cu ajutorul mecanismului de
transmitere a mesajelor
Abstract Metoda nu are implementare dar trebuie redefinită în aval
Override Metoda redefineşte o metodă virtuală sai dinamică
Class Apel de metodă fără a utiliza variabila implicită Self
Tabelul 3.1 Tipuri de metode în Object Pascal

42
Evident, în Object Pascal pot fi metode :procedurile, funcţiile, constructorii şi
destructorii. În linii mari, constructorii şi destructorii se utilizează cu semnificaţia
care se cunoaşte de la limbajul Pascal.

Metode statice
Metodele declarate într-o clasă sunt implicit statice. Nu este necesar un
identificator special pentru a desemna o metodă de tip static. Când este apelată o
metodă statică, tipul variabile este cel care determină ce metodă urmează să fie
executată. Compilatorul determină exact adresa metodei în timpul compilării.
Avantajul fundamental al metodelor statice constă în faptul că executarea lor este
foarte rapidă. Prin contrast, metodele virtuale şi dinamice rezolvă în timpul execuţiei
problema legării codului care trebuie executat, ceea ce lungeşte timpul de execuţie al
programelor dacă se abuzează de apelul la metode virtuale sau dinamice.
O metodă statică nu poate fi schimbată când este moştenită de un descendent al
clasei în care aceasta este definită. Altfel spus, dacă declaraţi o clasă care include în
definiţie o metodă statică, atunci derivând o nouă clasă din aceasta, clasa derivată
partajează exact aceeaşi metodă, situată la aceeaşi adresă. Aceasta înseamnă că nu
putem redefini static metodele.
În exemplul de mai jos, prima clasă declară două metode statice. Cea de-a doua
clasă declară două metode statice cu acelaşi nume, care înlocuiesc metodele
moştenite de la prima clasă.

:
type
TFirstComponent = class(TComponent)
procedure Move;
procedure Flash;
end;
TSecondComponent = class(TFirstComponent)
procedure Move; { diferită de metoda moştenită,
acelaşi antet}
function Flash(HowOften: Integer): Integer; {Evident,
diferită de metoda moştenită }
end;
:

Metode virtuale
Spre deosebire de apelul metodele statice, apelurile metodelor virtuale nu sunt
rezolvate în faza de compilare. Metoda care urmează să fie executată, în cazul virtual
este determinată în timpul execuţiei printr-un procedeu numit legare întârziată.
Orice metodă poate fi făcută virtuală prin menţionarea unei directive virtual la
sfârşitul definiţiei metodei în lista de componente a clasei. Noutatea metodelor
virtuale constă în următorul mecanism: dacă într-un lanţ de derivare, o anumită
metodă, declarată virtuală în clasa rădăcină, apare în descendenţi redefinită (marcată
de directiva override), atunci un apel la metoda respectivă, făcut din contextul unei
variabile compatibilă cu lanţul de derivare, va fi rezolvat în funcţie de tipul curent al

43
variabilei. Tipul variabilei este stabilit în momentul creării instanţei, de către
constructorul corespunzător clasei context.
Alegerea metodei corespunzătoare contextului se face cu ajutorul tabelelor VMT,
unice, asociate claselor care au metode virtuale şi create la apelarea constructorilor.

Metode dinamice
Un mecanism oarecum similar metodelor virtuale este utilizat şi în cazul
metodelor dinamice. Din punctul de vedere al utilizatorului nu se poate face diferenţa
între cele două tipuri de metode. Codul generat, însă, diferă semnificativ, astfel:
apelurile metodelor virtuale sunt mai rapide dar generează creşterea codului; apelurile
metodelor dinamice sunt mai lente, dar generează cod mai mare.
În mod uzual, metodele virtuale sunt preferate dacă se doreşte exploatarea
capabilităţilor polimorfice ale unui lanţ de derivare. Dacă, însă, se doreşte crearea
unei clase de bază din care se derivează un număr mare de descendenţi, şi în fiecare
descendent se redefineşte un număr mic de metode virtuale moştenite.

Metode de tip mesaj


Aceste metode sunt o formă specializată a metodelor dinamice, fiind
indispensabile în manipularea eficientă a mesajelor unei aplicaţii Delphi.
Compilatorul Object Pascal generează cod de apel specific acestor metode dacă sunt
declarate cu directiva message. Mecaismul de apel utilizat este aproape identic cu cel
utilizat în cazul metodelo dinamice. Există, însă, şi elemente specifice de care
programatorul trebuie să ţină cont când utilizează aceste tipuri de metode. Aceste
elemente specifice sunt legate de protocolul de gestiune a mesajelor unei aplicaţii
într-o aplicaţie Windows, în genere şi într-o aplicaţie Delphi, în particular.
Prezentăm, în continuare, un exemplu de specificare a unui handler utilizator de
mesaje.

const
CM_CHANGECOLOR = WM_USER + 400;
type
TMyComponent = class(TControl)
...
protected
procedure CMChangeColor(var Message: TMessage): message
CM_CHANGECOLOR;

end;
procedure TMyComponent.CMChangeColor(var Message: TMessage);
begin
Color := Message.lParam;
inherited;
end;

Recomand studierea atentă a help-ului on-line Delphi şi a exemplelor demonstrative,


pentru a aprofunda problematica lucrului cu mesajele în aplicaţiile Delphi.

44
Metode abstracte
De regulă când se specifică o metodă în lista de componente asociată definiţiei
unei clase, compilatorul se aşteaptă să găsească implementarea metodei în secţiunea
corespunzătoare a unit-ului gazdă. Pe de altă parte, atunci când se specifică o metodă
în clasa de bază, se stabileşte un comportament implicit al tuturor descendenţilor,
relativ la metoda respectivă. Pentru a schimba comportamentul în descendenţi,
trebuie redefinită metoda în descendenţi. Dacă nu are sens asocierea în clasa de bază
a unui comportament implicit, se poate utiliza directiva abstract, pentru a semnala
compilatorului că nu va fi implementată o metodă implicită. De precizat faptul că
orice metodă declarată abstractă trebuie să fi, totodată virtuală sau dinamică, ca în
exemplul de mai jos.

type
Base = class
procedure DaliVision; virtual; abstract;
procedure TellyVision; dynamic; abstract;
end;

Metode redefinite (override)


Atunci când logica unui lanţ de derivare impune redefinirea unor metode
( virtuale sau dinamice), în descendenţi se anunţa redefinirea cu ajutorul directivei
override. Pentru a ilustra ideea, prezentăm şi exemplul de mai jos.

type
TFirstComponent = class(TCustomControl)
procedure Move; { metodă statică }
procedure Flash; virtual; { metodă virtuală }
procedure Beep; dynamic; { metodă dinamică }
end;
TSecondComponent = class(TFirstComponent)
procedure Move; { declarare metodă nouă }
procedure Flash; override; { redefinire metodă moştenită
}
procedure Beep; override; { redefinire metodă moştenită
}
end;

Metode de tip clasă


Metodele de tip clasă nu sunt altceva decât metode ce pot fi apelate ca orice alte
proceduri sau funcţii obişnuite, fără a fi nevoie de vreo instanţiere a clasei care le-a
definit. Acest tip de metode sunt uşor de recunoscut prin prefixarea lor cu directiva
class ca în exemplul de mai jos.
Trebuie reţinut însă că metodele de tip clasă nu trebuie să modifice informaţii
relative la instanţe. Programatorii Java recunosc asemănarea cu metodele statice.
Astfel că, în exemplul:

45
type
Tclass1 = class
Nume:string;
class procedure ModificNume (NumeNou:string);
end;
class procedure ModificNume (NumeNou:string);
begin
Nume:=NumeNou;
end;

compilatorul va semnala eroare deoarece metoda de tip clasă ModificNume încearcă


să modifice valoarea câmpului Nume, care este o variabilă de instanţă a clasei
Tclass1.

Unit-ul System defineşte două tipuri, TObject şi TClass, care sunt tipuri rădăcină
pentru toate tipurile clasă şi referinţă la clasă, despre care vom discuta în continuare.
Rădăcina TObject conţine o bogată colecţie de metode de tip clasă pe care le putem
apela fără a fi nevoie să instanţiem clasa.

type
TObject = class;
TClass = class of TObject;
TObject = class
constructor Create;
destructor Destroy; virtual;
class function ClassInfo: Pointer;
class function ClassName: ShortString;
class function ClassNameIs(const Name: string): Boolean;
class function ClassParent: TClass;
function ClassType: TClass;

procedure CleanupInstance;
procedure DefaultHandler(var Message); virtual;
procedure Dispatch(var Message);
function FieldAddress(const Name: ShortString): Pointer;
procedure Free;
procedure FreeInstance; virtual;
class function InheritsFrom(AClass: TClass): Boolean;
class function InitInstance(Instance: Pointer): TObject;

class function InstanceSize: Longint;


class function NewInstance: TObject; virtual;
class function MethodAddress(const Name: ShortString): Pointer;
class function MethodName(Address: Pointer): ShortString;
end;

46
Conceptul de proprietate
Conceptul de proprietate nu este absolut nou. În Turbo Pascal, proprietăţile se
confundau cu înregistrările sau câmpurile unui obiect. În Delphi, noţiunea de
proprietate, ca şi concept nou, pare să fie strâns legată de necesităţile programării
vizuale. Este adevărat doar în parte deoarece noţiunea de proprietate are o valoare de
întrebuinţare care depăşeşte cerinţele programării vizuale. O definiţie de proprietate
într-o clasă permite declararea unui anumit atribut al obiectelor unei clase şi a
acţiunilor asociate cu citirea şi scrierea atributelor. Exemple de astfel de proprietăţi
sunt : proprietatea “Caption” a unei forme, mărimea fontului intr-un derivat TMemo,
etc.
Putem spune că proprietăţile sunt o extensie naturală a câmpurilor unui
obiect. Atât câmpurile cât şi proprietăţile pot fi utilizate pentru a exprima atributele
unui obiect, dar, în timp ce câmpurile sunt doar locaţii de memorie care pot fi
examinate şi modificate după dorinţă, proprietăţile asigură un control mai mare
asupra valorilor atributelor, datorită mecanismelor de citire /scriere cu care se
asociază o anumită proprietate.
Prezentăm mai jos, cu ajutorul limbajului diagramelor de sintaxă, regulile
sintactice care stau la baza specificării proprietăţilor unei clase.

Definiţie proprietate

property Identificator

Interfaţă
proprietate

Specificatori
;
proprietate

Definiţie interfaţă proprietate

: Tip identificator

Listă parametri
proprietate

index Constantă întregă


47
Definiţie listă parametri proprietate

[ Declarare parametru ]

Definiţie specificatori proprietate

Specificator
Specificator Specificator Specificator
de
READ WRITE implicit
stocare

Definiţie specificator read

read Câmp / Metoda

Definiţie specificator write

write Câmp / Metodă

Definiţie specificator de stocare

stored Câmp /Metodă

Constanta
booleană

Definiţie specificator implicit

48
default Constantă

Definiţie Câmp / Metodă

nodefault
Identificator câmp

Identificator metodă

Modul de utilizare al sintaxei de mai sus poate fi urmărit şi din exemplul


prezentat în continuare, care ne arată modul de scriere a codului sursă al unei
componente în Delphi.

unit Exemplu;
interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TArrayProp = array [1..5] of string[7];

TEverything = class(TCustomControl)
private
{ Private declarations }
FArrayProp : TArrayProp;
function GetArrayPropInt(pIndex: integer): string;
function GetArrayPropStr(pIndex: string): integer;
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
property ArrayPropInt[Index: integer]: string read GetArrayPropInt;
property ArrayPropStr[Index: string]: integer read GetArrayPropStr;
published
{ Published declarations }
end;
procedure Register;
implementation

constructor TEverything.Create(AOwner: TComponent);


begin

49
// Iniţializare FArrayProp
FArrayProp[1] := 'one';
FArrayProp[2] := 'two';
FArrayProp[3] := 'three';
FArrayProp[4] := 'four';
FArrayProp[5] := 'five';
end;

function TEverything.GetArrayPropInt(pIndex: integer): string;


begin
result := 'Necunoscut';
// Dacă pIndex este definit în FArrayProp, setează variabila result la valoarea de
//indice pIndex
if pIndex in [1..5] then
result := FArrayProp[pIndex];
end;

function TEverything.GetArrayPropStr(pIndex: string): integer;


var
x : integer;
begin
result := -1;
for x := 1 to 5 do
if UpperCase(FArrayProp[x]) = UpperCase(pIndex) then
begin
result := x;
exit;
end;
end;

procedure Register;
begin
RegisterComponents('UD3', [TEverything]);
end;
end.

3.2 Tratarea excepţiilor în Delphi


Printre caracteristicile principale ale mediului Delphi, una dintre cele mai
importante este capacitatea de tratare a excepţiilor, prin care programatorul poate să
răspundă elegant la apariţia oricărei erori de execuţie, simplificând astfel şi codul,
ceea ce permite programatorului să se concentreze asupra algoritmilor principali ai
aplicaţiei. Excepţiile în Delphi sunt similare celor folosite de C++, locul lui catch
este preluat de except iar throw devine raise în Delphi. La fel ca în C++ excepţiile
sunt manipulate în blocuri, care la rândul lor pot să suporte incluziunea.

Blocuri de protecţie

50
În Delphi, tratarea excepţiilor se face prin aşa numitele blocuri de protecţie, care
pot executa, fie un cod de terminare pentru a nu fi compromisă sesiunea Windows,
fie o secvenţă de cod care tratează efectiv excepţia, caz în care execuţia programului
continuă normal.
Aceste blocuri de protecţie sunt la rândul lor compuse din alte două tipuri de
blocuri, un bloc de gardă, care, aşa după cum îi spune numele este răspunzător de
interceptarea excepţiei şi un bloc de răspuns ce conţine codul de tratare al excepţiei,
sau codul corespunzător terminării aplicaţiei.
Structura de principiu a unui bloc de protecţie în Delphi este:

try
//Blocul de gardă în care excepţia este susceptibilă
// să apară
finally
//Blocul de răspuns ce conţine codul de terminare,
//fără a înlătura evoluţia excepţiei
end;

sau

try
//Blocul de gardă în care excepţia este susceptibilă
//să apară
except
//Blocul de răspuns ce conţine codul de tratare,
//a excepţiei
on <Tip_Exceptie_1> do <Instrucţiune_1>
on <Tip_Exceptie_2> do <Instrucţiune_2>
:
on <Tip_Exceptie_n> do <Instrucţiune_n>
end;

În varianta cu finally execuţia decurge astfel:

Dacă vreuna dintre instrucţiunile cuprinse între try şi finally provoacă o excepţie,
atunci sistemul predă controlul blocului de răspuns, cuprins între finally şi end.
Dacă nu a apărut nici o excepţie, după epuizarea instrucţiunilor cuprinse între try şi
finally, se continuă cu execuţia instrucţiunilor cuprinse între finally şi end.
Altfel spus, în varianta cu finally avem la dispoziţie un mecanism cu ajutorul
căruia avem garanţia că se execută un cod de terminare corectă a unui tip de
prelucrare, indiferent de excepţiile care pot apare. Prin acest mecanism se urmăreşte
limitarea efectelor posibilelor excepţii la execuţia unui program Delphi.
Să mai adăugăm faptul că, în varianta cu finally, după execuţia codului de
terminare, dacă a apărut o excepţie, aceasta îşi continuă evoluţia (nu este ridicată),
putând fi interceptată şi tratată într-o buclă try externă, iar dacă această buclă nu este
găsită, putând provoca în cele din urmă terminarea anormală a programului.

51
În varianta cu except execuţia decurge astfel:

Lista instrucţiunilor din blocul try se execută în ordine. Dacă nu apare nici o
eroare, blocul except este ignorat, continuându-se execuţia cu prima instrucţiune
aflată după end. Dacă a apărut o excepţie, controlul este dat celui mai interior handler
de excepţie existent. Dacă un astfel de handler de excepţie nu există, atunci se va
căuta un handler de excepţii în exterior, în alt bloc try-except, neterminat încă. Dacă
un astfel de handler nu este găsit, se continuă astfel până la epuizarea blocurilor try-
except, sau până la găsirea handler-ului de excepţie adecvat. Dacă nu este găsit nici
un handler, se generează un mesaj standard de eroare şi execuţia este terminată
anormal.

În sfârşit, să mai adăugăm precizarea că, similar modului în care utilizam în C++
enunţul throw, în Object Pascal putem folosi enunţul raise pentru a genera o excepţie.
Delphi pune la dispoziţia programatorului clase de excepţii, extrem de utile pentru
a monitoriza sistematic apariţia excepţiilor uzuale ale unei aplicaţii Delphi (împărţie
la zero, acces nepermis la memorie, eroare la crearea unui fişier, etc.).

Amănunte despre protocolul de utilizare şi detaliile de sintaxă pot fi urmărite şi


în exemplele de mai jos.

unit UExcept1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
Edit2: TEdit;
Label2: TLabel;
Button1: TButton;
Label3: TLabel;
Edit3: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

52
Op1,Op2,Rezultat:real;
implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);


begin
try
try
Op1:=StrToFloat(Edit1.Text);
Op2:=StrToFloat(Edit2.Text);
Rezultat:=Op1/Op2;
except
on EConvertError do
ShowMessage('Operanzi eronati...');
end;
Edit3.Text:=FloatToStr(Rezultat);
Edit1.SetFocus;
Edit1.Text:='';
Edit2.Text:='';
except
on EZeroDivide do
ShowMessage('Impartire la zero...');
end;
end;

end.

unit UExcept2;
//Aplicatie la tratarea exceptiilor in Delphi
interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons;

//----------------------------------------------------------
// Codul care urmeaza este o interfata intre
//exceptiile aplicatiilor utilizator si sistem
// asigurata de clasa Exception din unit-ul SYSUTILS, prezentată mai jos sub formă
de //comentariu.
//----------------------------------------------------------
(*Exception = class(TObject)
private
FMessage: string;

53
FHelpContext: Integer;
public
constructor Create(const Msg: string);
constructor CreateFmt(const Msg: string; const Args: array of const);
constructor CreateRes(Ident: integer);
constructor CreateResFmt(Ident: integer; const Args: array of const);
constructor CreateHelp(const Msg: string; AHelpContext: integer);
constructor CreateFmtHelp(const Msg: string; const Args: array of const;
AHelpContext: integer);
constructor CreateResHelp(Ident: integer; AHelpContext: integer);
constructor CreateResFmtHelp(Ident: integer; const Args: array of const;
AHelpContext: integer);
property HelpContext: integer read FHelpContext write FHelpContext;
property Message: string read FMessage write FMessage;
end;
*)

type
EMyComponentError = class(Exception)
private
FErrorCode: integer;
public
property ErrorCode: integer read FErrorCode write FErrorCode;
constructor Create(const Msg: string; ErrCode: integer);
end;

EMyCompoRangeError =class(EMyComponentError);
EMyCompoInvalidValue =class(EMyComponentError);

TForm1 =class(TForm)
Button1: TButton;
Button3: TButton;
Button2: TButton;
Button4: TButton;
Button5: TButton;
ListBox1: TListBox;
Button6: TButton;
Button7: TButton;
Button8: TButton;
BitBtn1: TBitBtn;
procedure Button1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);

54
procedure Button7Click(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1 :TForm1;
Stream :TMemoryStream;

implementation

{$R *.DFM}

//----------------------------------------------------------
// Rutinele care urmeaza sunt scrise utilizand
// maniera Delphi de tratare a exceptiilor
//----------------------------------------------------------

function CharFromString(sVal: string; iPos: integer): char;


begin
if iPos > Length(sVal) then
Raise Exception.Create('Out of Range');
result := sVal[iPos]
end;

procedure InsertChar(cVal: char; var sVal: string; iPos: integer);


begin
if iPos > Length(sVal) then
Raise Exception.Create('Out of Range');
sVal[iPos] := cVal;
end;

procedure UseFunctions;
var cVal: char;
sStrVal: string;
begin
try
sStrVal := 'Delphi Rock ';
cVal := CharFromString(sStrVal,13);
if cVal <> 's' then
InsertChar('s',sStrVal,12);
ShowMessage(sStrVal);
except

55
exit;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);


begin
UseFunctions;
end;

//----------------------------------------------------------
// Aceste rutine rezolva aceleasi probleme ca
// mai sus intr-un stil de programare defensiv
// clasic.
//----------------------------------------------------------

function CharFromString(sVal: string; iPos: integer): char;


begin
Result := #0;
if iPos <= Length(sVal) then
result := sVal[iPos]
end;

function InsertChar(cVal: char; var sVal: string; iPos: integer): boolean;


begin
Result := False;
if iPos <= Length(sVal) then
begin
sVal[iPos] := cVal;
Result := True;
end;
end;

procedure UseFunctions;
var cVal: char;
sStrVal: string;
begin
sStrVal := 'Delphi Rock ';
cVal := CharFromString(sStrVal,12);
if cVal <> #0 then
begin
if cVal <> 's' then
if InsertChar('s',sStrVal,12) then
ShowMessage(sStrVal)
else
exit;
end
else

56
exit;
end;

//----------------------------------------------------------
// Aceste rutine exemplifica utilizarea optionala
// a sintaxei [on..do] a unei constructii [try..except]
//----------------------------------------------------------
procedure LowMemTerminate;
begin
{Eventuale instructiuni de de-initializare}
Application.Terminate;
end;

procedure TForm1.Button2Click(Sender: TObject);


var pVal: PChar;
begin
try
GetMem(pVal,sizeof(Stream.Memory^));
StrLCopy(pVal,Stream.Memory,sizeof(Stream.Memory^)+1);
except
On E: EOutOfMemory do
LowMemTerminate;
On E: EAccessViolation do
begin
if MessageDlg(E.Message+': Terminate the program?',
mtError,[mbYes,mbNo],0) = mrYes then
Application.Terminate
end
else
Raise;
end;
end;

procedure TForm1.Button3Click(Sender: TObject);


var pVal: PChar;
begin
try
GetMem(pVal,sizeof(Stream.Memory^));
StrLCopy(pVal,Stream.Memory,sizeof(Stream.Memory^)+1);
except
On E: Exception do
begin
if E is EOutOfMemory then
LowMemTerminate;
if E is EAccessViolation then
begin
if MessageDlg(E.Message+': Terminate the program?',

57
mtError,[mbYes,mbNo],0) = mrYes then
Application.Terminate;
end
else
Raise;
end;
end;
end;

//----------------------------------------------------------
// Imbricare constructii [try..except] si [try..finally]
//----------------------------------------------------------
procedure TForm1.Button4Click(Sender: TObject);
var sVar: string;
pVar: PChar;
begin
try
GetMem(pVar,10);
try
StrCopy(pVar,'ListBox');
with ListBox1.Items do
begin
Add('Line1 - index 0');
Add('Line2 - index 1');
end;
sVar := ListBox1.Items[2];
finally
FreeMem(pVar,10);
end;
except
on EStringListError do
MessageDlg('List index out of bounds', mtError, [mbOk], 0);
on EAccessViolation do
MessageDlg('Memory Overwrite', mtError, [mbOk], 0);
else
Raise;
end;
end;

procedure TForm1.Button5Click(Sender: TObject);


var sVar: string;
pVar: PChar;
begin
GetMem(pVar,10);
try
StrCopy(pVar,'ListBox');
{Instructiuni de manipulare variabila pVar}

58
try
sVar := ListBox1.Items[0];
except
on EStringListError do
begin
ListBox1.Items.Add('Item1');
sVar := ListBox1.Items[0];
end
else Raise;
end;
{Instructiuni de manipulare variabila sVar}
finally
FreeMem(pVar,10);
end;
end;

//----------------------------------------------------------
// Aceste rutine arata utilizarea unei instantede tip EAbort
// [Silent Exception]
//----------------------------------------------------------

var Delphi: string;

procedure SetDelphiVariable(sValue: string);


begin
if Delphi = sValue then
Raise EAbort.Create('');
if (Length(sValue) > 0) and (Length(sValue) < 50) then
Delphi := sValue;
end;

procedure TForm1.Button6Click(Sender: TObject);


begin
SetDelphiVariable('Anders Hejlsberg');
end;

//----------------------------------------------------------
// These routines demonstrate the use of raising an
// exception of type EAbort - the silent exception
//----------------------------------------------------------
constructor EMyComponentError.Create(const Msg: string; ErrCode: integer);
begin
Inherited Create(Msg);
FErrorCode := ErrCode;
end;

const

59
cInvalidValue = 0;
cRangeError = 1;

//----------------------------------------------------------
// These routines relate to the creation of custom exception
// types. Move statments into your global handler and
// replace "Sender" with EInstance to test
//----------------------------------------------------------
procedure TForm1.Button7Click(Sender: TObject);
begin
if Sender is EMyComponentError then
case (Sender as TCOmponent).Tag of
cInvalidValue: {statements for appropriate action here};
cRangeError : {statements for appropriate action here};
else
begin
ShowMessage('Fatal Error - Terminating program');
Application.Terminate;
end;
end;
end;

procedure TForm1.Button8Click(Sender: TObject);


begin
if Sender is EMyComponentError then
begin
if Sender is EMyCompoRangeError then
{statements for appropriate action here}
else
if Sender is EMyCompoInvalidValue then
{statements for appropriate action here};
end
else
begin
ShowMessage('Fatal Error - Terminating program');
Application.Terminate;
end;
end;

procedure TForm1.BitBtn1Click(Sender: TObject);


begin
Close
end;

end.

60
4.Bibliotecile RUNTIME ale sistemului DELPHI
Biblioteca RUNTIME (RTL) a sistemului DELPHI constă din trei unit-uri compilate
separat: System, SysUtils, Math. Capabilităţile acestor unit-uri pot fi utilizate în
programele utilizator implicit sau dacă în unit-urile asociate acestora sunt referite
cu ajutorul clauzei uses.

4.1 Unit-ul System


Acest unit este partea fundamentală a bibliotecii RTL Delphi. El implementează
rutinele low-level necesare compilatorului pentru soluţionarea tuturor proprietăţilor
predefinite ale unei aplicaţii Delphi, precum:
operaţii input/output cu fişiere;
manipulare şiruri de caractere;
rutine pentru calcul numeric în virgulă mobilă;
rutine pentru managementul şi alocarea dinamică a memoriei.
De asemenea, unit-ul System defineşte o serie de tipuri de date şi variabile utile
în numeroase aplicaţii utilizator sau în scrierea de componente.
Unit-ul System este automat utilizat de către programele Delphi.

Unit-ul System defineşte o serie de tipuri de date care pot fi utilizate în diferite
contexte ale aplicaţiilor utilizator. Astfel avem, de exemplu, tipul TdateTime ,
declarat ca un o varietate specială de virgulă mobilă, astfel:

:
type
TdateTime =double;
:
Acest gen de redeclarare a tipului double oferă programatorilor posibilitatea de a
distinge variabilele virgulă mobilă utilizate pentru a păstra valori timp/dată de
variabilele virgulă mobilă folosite în alte scopuri.
Există o serie de alte tipuri de date, mult mai complexe, strict necesare pentru accesul
la tipuri de date uzuale. De exemplu, tipul TvarData declară structura internă a tipului
predefinit “Variant”. De asemenea, tipul TvarRec declară structura internă a
variabilelor care sunt transmise rutinelor ca parametri formali de tip “array of const”.

Totodată, unit-ul System defineşte o serie de variabile globale utilizate în


diferite situaţii de alte rutine, ca de exemplu:

:
CmdLine: pchar=nil; //Pointer linie de comandă
CmdShow: integer=0; //Parametru ShowWindow
FileMode: byte=2; //Mod implicit deschidere fişier
Hinstance: longint=0; //Handler-ul instanţei curente în mediul Windows
InOutRes: integer=0; //Bufer reszultat operaţii I/O
Input: text; //Fişierul standard de intrare
IsConsole: boolean; //Returnează dacă sau nu un modul este o
//aplicaţie consolă

61
Null: variant=nil; //Constantă de tip variant care indică că o variabilă
//variant nu are valoare.
Output: text; //Fişierul output standard
RandSeed: longint; //Sămânţă generator de numere aleatoare
:
Dintre rutinele cele mai mult folosite ale unit-ului System, care pot fi apelate
direct amintim:

BlockRead(F, Buffer, Count, Res);


Procedura permite transferul a Count înregistrări din fişierul fără tip asociat cu
variabila F în variabila Buffer. Tipul variabilei Buffer este neimportant dar trebuie să
fie suficient de încăpător pentru a păstra Count records. Numărul efectiv de
înregistrări citite este păstrat în variabila întreagă Res.

BlockWrite(F, Buffer, Count, Res);


Procedura permite transferul a Count înregistrări din variabila Buffer, în fişierul
fără tip asociat cu variabila F. Numărul efectiv de înregistrări scrise în fişier este
păstrat în variabila întreagă Res.

ChDir(S);
Schimbare director curent în directorul S.

GetDir(N,S);
Procedura returnează în S directorul curent al unui drive specificat prin
parametrul N. Valorile pentru N sunt:

0 Drive-ul implicit;
1 Drive-ul A
2 Drive-ul B
2 Drive-ul C.

Exemplu:
:
var

s : string;
begin
GetDir(0,s); { 0 = Drive-ul curent }
MessageDlg('Current drive and directory: ' + s, mtInformation, [mbOk] , 0);
end;
:

MkDir(S);
Procedura permite crearea unui director de cale S..

ParamCount

62
Funcţia returnează numărul de parametri transmişi programului prin linia de
comandă.

ParamStr(N);
Funcţia returnează al N-le parametru transmis prin linia de comandă.

Random;
Funcţia returnează un număr pseudoaleator. Fără parametru, funcţia returnează un
număr pseudoaleator cuprins între 0 şi 1. Când este apelată sub forma:
Random(N)
funcţia returnează un număr pseudoaleator cuprins între 0 şi N-1.

Randomize;
Procedura iniţializează generatorul de numere aleatoare cu o valoare aleatoare
dependentă de ceasul sistem.

RmDir(S);
Procedura şterge direcorul specificat prin calea S.
Append(VF);
Procedura deschide un fişier text existent pentru operaţii de adăugare.

AssignFile(VF,FileName);
Procedura permite asignarea unui nume extern de fişier la o variabilă fişier
compatibilă ca tip.

CloseFile(VF);
Procedura închide fişierul deschis referit de variabila VF.

Eof(VF)
Funcţia returnează True dacă pointerul de fişier reperează marcajul de sfârşit de
fişier.

Eoln(VF)
Funcţia returnează True dacă pointerul de prelucrare a unui fişier text detectează
marcajul de sfârşit de linie.

Erase(VF)
Procedura şterge fişierul extren asociat cu variabila VF.

FilePos(VF)
Funcţia returnează poziţia curentă într-un fişier cu tip sau fără fip.

FileSize (VF)
Funcţia returnează numărul de înregistrări într-un fişier Pascal cu tip sau fără tip.

Flush (VF)
Procedura goleşte buffer-ul unui fişier text.

63
IOResult
Funcţia returnează un întreg care codifică rezultatul ultimei operaţii I/O.

Read (VF,V1,V2, …,Vn)


Procedura permite citirea din fişierul specificat de cvariabila VF a valorilor
variabilelor V1,V2,…,Vn.

Readln (VF,V1,V2,…,Vn)
Procedura permite citirea din fişierul text asociat cu variabila VF a valorilo
variabilelor V1,V2,…,Vn, urmată de retur de car şi salt la linie nouă.
Rutinele:
Rename
Reset
Rewrite
Seek
SeekEof
SeekEoln
SetTextBuf
Truncate
Write
Writeln
au valoarea de întrebuinţare cunoscută de la limbajul Pascal.

4.2 Unit-ul SysUtils


Unit-ul SysUtils extinde capabilităţile unit-ului System, adăugând declaraţii de
tipuri de date, constante şi rutine necesare pentru rezolvarea unor probleme precum:
tratarea excepţiilor, rutine pentru lucru la nivel de stringuri, rutine pentru manipularea
orei şi a datei, rutine pentru asistarea gestiunii fişierelor,etc.
Semnalând faptul că în unit-ul SysUtils sunt declarate o serie de constante de
maxim interes pentru manipularea fişierelor (constante atribute fişiere, constante mod
deschidere fişiere) precum şi o serie de tipuri de date şi variabile de utilitate extrem
de diversă, prezentăm în continuare cele mai importante rutine ale unit-ului SysUtils,
din punctul de vedere al programatorului de nivel mediu.

Rutine ale unit-ului SysUtils


Rutinele declarate în unit-ul SysUtils au diferite valori de întrebuinţare.

Rutine ale unit-ului SysUtils pentru lucru la nivel de şir de caractere

AdjustLineBreaks(S)
Funcţie. Returnează sirul S concatenat cu <CR>/<LF> dacă a avut în coadă <CR>
sau <LF> sau secvenţa <LF>/<CR>.

AnsiLowerCase(S)
Funcţie. Returnează şirul ANSI S convertit la litere mici.

64
AnsiUpperCase(S)
Funcţie. Returnează şirul ANSI S convertit la litere mari.

LowerCase(S)
Funcţie. Returnează şirul ASCII S convertit la litere mici.

UpperCase(S)
Funcţie. Returnează şirul ASCII S convertit la litere mari.

Trim(S)
Funcţie. Curăţă şirul S de spaţiile sau caracterele de control care îl preced sau
postced.

TrimLeft(S)
Funcţie. Curăţă şirul S de spaţiile sau caracterele de control care îl preced.

TrimRight(S)
Funcţie. Curăţă şirul S de spaţiile sau caracterele de control care îl postced.

AnsiCompareStr(S1,S2)
Compară ANSI şirurile S1 şi S2 făcând diferenţă între litere mari şi litere mici.

AnsiCompareText(S1,S2)
Compară ANSI şirurile S1 şi S2 fără a face diferenţă între litere mari şi litere
mici.

Rutine ale unit-ului SysUtils pentru lucru la nivel de directoare

CreateDir(NumeDirector)
Funcţie. Returnează TRUE dacă s-a creat un director cu numele NumeDirector şi
FALSE în caz contrar.

RemoveDir(NumeDirector)
Funcţie. Returnează TRUE dacă s-a şters directorul cu numele NumeDirector şi
FALSE în caz contrar.

Rutine ale unit-ului SysUtils pentru lucru cu ora şi data

Date
Funcţie. Returnează data curentă.

Now
Funcţie. Returnează data şi ora curentă. Se poate utiliza funcţia DateToStr pentru
a converti valoarea returnată de funcţia Now din format TdateTime în format string.

65
Time
Funcţie. Returnează ora curentă. Se poate utiliza funcţia TimeToStr pentru a
converti valoarea returnată din format TdateTime în format string.

DateTimeToStr(DT)
Funcţie. Converteşte valoarea variabilei DT, de tip TdateTime, la format şir de
caractere.

DateTimeToString( ResultStr, FormatStr,DT)


Procedură. Converteşte valoarea variabilei DT de tip TdateTime la format şir de
caractere utilizând formatul de conversie FormatStr. Rezultatul conversiei se obţine
în ResultStr.

DateToStr(DT)
Funcţie. Converteşte valoarea variabilei DT de tip TdateTime la şir de caractere.

FormatDateTime(Format,DT)
Funcţie. Returnează ca şir de caractere valoarea variabilei de tip DT, utilizând
formatul specificat.

TimeToStr(DT)
Funcţie. Converteşte valoarea variabilei DT, de tip TdateTime, la şir de caractere.

Rutine ale unit-ului SysUtils pentru lucrul cu fişiere şi periferice

DeleteFile(FileName)
Funcţie. Returnează True dacă ştergerea fişierului FileName a decurs cu succes.
FileName este nume extern de fişier. Fals în caz contrar.

FileAge(FileName)
Funcţie. Returnează un număr întreg care păstrează informaţii cu privire la vârsta
fişierului. Valoarea returnată poate fi convertită la format TdateTime cu rutina
FileDateToTime. Dacă fişierul nu există, rutina returnează –1.

FileCreate(FileName)
Funcţie. Crează un fişier de nume specificat returnând un întreg, care este handle-
rul fişierului. Rutina este utilizată pentru rezolvarea unor probleme de comunicare cu
Windows API. Nu este recomandată pentru fişiere native Pascal.

FileGetAttr(FileName)
Funcţie. Returnează un întreg care încapsulează atributele fişierului specificat.

FileSetAttr(FileName, NewAttr)
Funcţie. Setează atributele fişierului. Returnează zero în caz de succes.

RenameFile(OldName,NewName)

66
Funcţie. Redenumeşte fişierul de nume OldName. Returnează 0 în caz de succes.
FileExists(FileName)
Funcţie. Returnează True dacă fişierul de nume specificat există.

FileSearch(FileName, DirList)
Funcţie. caută fişierul FileName în lista de directoare DirList. Returnează calea
completă către fişier dacă găseşte fişierul sai stringul vid în caz contrar. FileSearch
function. Lista de directoare este specificată ca în exemplul de mai jos.

Gasit := FileSearch(‘Test.dbf', ‘c:\fpd26’;’c:\fpw26’);

FindClose(SearchRec)
Procedură. Termină o secvenţă FindFirst/FindNext.

FindFirst(FileSpec,Attr,Searchrec);
FindNext(Searchrec);
Proceduri. Au aceeaşi valoare de întrebuinţare pe care o aveau înPascal.

ExtractFileName(FileName)
Funcţie. Extrage numele fişierului din specificatorul FileName.

ExtractFilePath(FileName)
Funcţie. Extrage calea către fişierul indicat de specificatorul FileName.

ExtractFileExt(FileName)
Funcţie. Extrage extensia unui fişier indicat de specificatorul FileName.

67
5. Dezvoltarea rapidă a aplicaţiilor în Delphi

5.1 Introducere
Unii specialişti consideră Delphi ca fiind versiunea RAD (Rapid Application
Development) a mediului de programare Borland Pascal. Unul dintre primele lucruri
care trebuie înţelese când se lucrează într-un mediu RAD se referă la faptul că un
mediu RAD este o tehnologie de elaborare a soluţiilor unor probleme de informatică,
bazată be o serie de concepte, componente şi protocoale de utilizarea a acestora. Un
mediu RAD devine cu adevărat puternic în mâinile unui programator dacă acesta ştie:
Să modeleze obiect orientat soluţia unei probleme date;
Să utilizeze suportul Delphi pentru progranmare obiect orientată;
Să utilizeze componentele Delphi în procesul de dezvoltare rapidă de aplicaţii;
Să reutilizeze propriul effort de dezvoltarea rapidă a aplicaţiilor Delphi.
Deprinderea de a modela obiect orientat soluţia unei probleme se formează prin
însuşirea unei metodologii de modelare adecvate şi prin mult exerciţiu în contextul
respectivei metodologii.
Elementele referitoare la suportul Delphi pentru programarea obiect orientată le-
am prezentat în Capitolele 2 şi 3.
În acest capitol voi încerca o incursiune selectivă în ceea ce înseamnă oferta
Delphi de componente şi facilităţi pentru operaţionalizarea paradigmei RAD.
Înainte de a face acest lucru voi încerca să explic cititorului ce se înţelege mai
precis prin sintagma RAD, strâns legată în ingineria softului de ideea de prototipizare.

 RELAŢIA RAD-PROTOTIPIZARE

Multe modele de dezvoltare a sistemelor soft se bazează pe utilizarea, în anumite


momente, a abordărilor iterative (de exemplu, analiza poate implica o serie de sarcini
care sunt iterativ repetate până când modelele analizei sunt considerate complete).
Deşi promite un cadru mai realist de dezvoltare a softului o astfel de abordare
poate fi uşor “descumpănită” de constatarea că, în zilele noastre utilizatorul final sau
indirect ştie să folosească sistemul odată ce acesta a fost livrat, ceea ce creează foarte
repede împrejurările necesare pentru ca acesta (utilizatorul) să observe eventualele
neconcordanţe între cerinţele lui faţă de sistem şi cele implementate efectiv.
Modelul prototipizării oferă o abordare care, potenţial, poate contribui la
eliminarea omisiunilor şi ambiguităţilor care pot exista în cerinţe.

În ingineria softului se numeşte prototip un sistem sau un sistem parţial finisat care
este construit rapid pentru a explora anumite aspecte ale cerinţelor faţă de sistem şi
care nu este considerat sistem gata de livrarea finală la utilizator.

Un sistem soft aflat în faza de prototip se deosebeşte de un sistem soft gata de


livrare prin o serie de omisiuni asumate sau strecurate involuntar în faza de codificare
(implementare).
Astfel că un prototip are, în mod obişnuit, o funcţionalitate incompletă (capacitate
limitată de procesare a datelor, performanţe reduse în timpul execuţiei, siguranţă în
funcţionare problematică, etc.).

68
Dezvoltarea prototipului este posibilă efectiv doar utilizând instrumente pentru
dezvoltarea rapidă a sistemelor soft (medii vizuale de proiectare, medii vizuale de
programare, etc.).
Când realizăm un prototip putem avea diferite obiective în minte.
Putem construi un prototip pentru a investiga cerinţele utilizator; în acest scop ne
putem focaliza efortul de dezvoltare pe realizarea interfeţei cu utilizatorul pentru a
stabili ce date aşteaptă utilizatorul de la sistem şi ce date furnizează utilizatorul
sistemului.
Prototipul poate fi folosit pentru a determina cel mai adecvat gen de interfaţă.
Putem construi un prototip pentru a stabili dacă o platformă de implementare
anume poate suporta anumite cerinţe de prelucrare.
În sfârşit, un prototip ar putea să urmărească determinarea eficienţei unui limbaj
particular, a unui SGBD sau a unei infrastructuri de comunicaţie.
O perspectivă mai clară asupra proprietăţilor modelului MP putem obţine şi din
Figura 5.1.

Analiza Definire
iniţială obiective
prototip

Specificar
e prototip

Evaluare prototip Construire


şi stabilire protoip
schimbări

Prototip
complet

Figura 5.1 Dezvoltarea rapidă a softului utilizând prototipizarea

69
Aşadar, fazele principale necesare pentru a pregăti un prototip sunt:

Efectuarea unei analize iniţiale;

Definirea obiectivelor prototipului ;

Specificarea prototipului;

Construirea prototipului;

Evaluarea prototipului şi stabilirea schimbărilor de efectuat.

Efectuarea unei analize iniţiale


Întreaga activitate de dezvoltare a softului foloseşte resurse valoroase. Începerea
unui exerciţiu de prototipizare fără o analiză iniţială este posibil să conducă la o
activitate nestructurată şi greşit focalizată care va produce un soft proiectat
nesatisfăcător.

Definirea obiectivelor prototipului


Prototipizarea este de dorit să aibă obiective clar stabilite. Un exerciţiu de
prototipizare poate implica multe iteraţii, fiecare iteraţie având drept rezultat o
anumită îmbunătăţire a prototipului. Pentru participanţii la un exerciţiu de
prototipizare, la un moment dat poate fi dificil de stabilit dacă prototipizarea trebuie
sau nu să continue.
Pentru evitarea unei astfel de posibilităţi definirea clară a obiectivelor de
îndeplinit poate fi de mare folos.

Specificarea prototipului
Deşi prototipul nu este realizat în perspectiva unor operaţii de extindere este,
evident, important să aibă un comportament scontat. De aceea, este absolut firesc să
luăm în calcul posibilitatea unor modificări care să apropie prototipul cât mai mult de
comportamentul scontat.
Aceste modificări sunt mult mai uşor de făcut dacă softul este realizat potrivit
unor principii de proiectare profunde.

Construirea prototipului
Deoarece este important ca prototipul să fie realizat rapid este firesc ca în această
fază să se apeleze la un mediu de dezvoltare rapidă a plicaţiilor (Delphi, Visual Basic,
Visual C, C-Builder, etc.).

Evaluarea prototipului şi stabilirea schimbărilor de efectuat


Motivul principal pentru care realizăm un prototip este testarea şi explorarea
anumitor aspecte ale sistemului soft de realizat. Prototipul trebuie evaluat în
conformitate cu obiectivele identificate la începerea exerciţiului de prototipizare.

70
Dacă obiectivele nu au fost îndeplinite, evaluarea are drept consecinţă o serie de
modificări care urmăresc apropierea prototipului de obiectivele asumate.
După cum se vede şi din Figura 5.1, ultimele trei faze sunt parcurse ciclic, până
când toate obiectivele asumate de exerciţiul de prototipizare sunt îndeplinite.
În cele ce urmează putem prezenta avantajele acestui model dar şi o serie de
aspecte de care ar trebui să ţinem cont înainte de a ne “aventura” în prototipizare.

Avantaje:

Ilustrarea timpurie a funcţionalităţii sistemului ajută la identificarea tuturor


dezacordurilor dintre specialistul IS şi client;

Cerinţele client omise au şanse să fie identificate;

Dificultăţile legate de proiectarea interfeţei pot fi conştientizate şi rezolvate;

Realizabilitatea şi utilitatea sistemului soft pot fi testate chiar dacă, prin natura
lui, prototipul este incomplet.

Probleme:

Clientul poate percepe prototipul ca parte a sistemului final dar nu poate


înţelege amploarea efortului cerut, uneori, de realizarea formei finale a sistemului,
motiv pentru care are senzaţia că acesta (sistemul final) trebuie livrat mai curând
decât este posibil în realitate;

Prototipul poate distrage atenţia de la aspectele funcţionale (uneori critice


pentru sistem) către problemele de interfaţă (fetişizate oarecum de nevoia de a da
permanent satisfacţie clientului/utilizatorului);

Prototipizarea se bazează pe o implicare semnificativă a utilizatorului;

Managementul care se bazează pe modelul MP are de luat decizii dificile de-a


lungul întregului ciclu de viaţă.
Pentru o mai bună înţelegere a ideilor prezentate mai sus, i-ar prinde bine
cititorului o lectură atentă a unei cărţi de iniţiere în ingineria softului. Recomand,
cartea cu titlul INŢIERE ÎN INGINERIA SISTEMELOR SOFT, apărută la
Editura Albastră din Cluj-Napoca, autor D. Bocu.

5.2 Centrul de control al mediului Delphi


Numit de unii şi fereastra principală a mediului, centrul de control se compune
din următoarele secţiuni principale:

Bara meniu

71
Această secţiune este unul dintre cele mai comune elemente ale aplicaţiilor
Windows. În Delphi, bara meniu asigură mecanisme de acces la toate funcţiile IDE
Delphi, precum: instalarea componentelor, setarea mediului şi a opţiunilor de
compilare, crearea de noi forme şi unit-uri, etc. Bara meniu apare imediat sub bara de
titlu a ferestrei principale.

Containerul cu acceleratori (Speedbar)


În această secţiune a ferestrei principale se găsesc o serie de elemente “shortcut”
care permit accesul rapid la 14 dintre cele mai mult utilizate comenzi ale mediului
Delphi. Aceste comenzi asigură funcţiile prezentate în tabelul de mai jos. Containerul
cu acceleratori este situat sub bara meniu în stânga.

Nr. Nume accelerator Descriere.


crt.
1 Open Project Deschide un proiect existent.
Echivalentă cu comanda File / Open
2 Save all Salvează toate elementele proiectului actual.
Echivalentă cu comanda File / Save All
3 Add file to project Adăugarea unui fişier la proiect.
Echivalentă cu comanda File / Add to project
4 Select unit from list Selectarea unui unit din lista.
Echivalentă cu comanda View / Units
(Ctrl+F12)
5 Select form from list Selectare unei forme din listă.
Echivalentă cu comanda View / Forms
(Shift+F12)
6 Run Compilarea şi lansarea în execuţie a aplicaţiei.
Echivalentă cu comanda Run / Run (F9)
7 Pause Pauză temporară în execuţia programului.
Echivalentă cu comanda Run / Program
Pause
8 Open File Încărcare proiect, formă, unitate sau fişier text
în editorul de coduri.
Echivalentă cu comanda File / Open.
9 Save File Salvarea modificărilor efectuate în fişierele
incluse în proiect.
Echivalentă cu comanda File / Save (Ctrl+S).
10 Remove file from project Ştergerea unui unit din proiectul curent.
Echivalentă cu comanda File / Remove from
project.
11 Toggle Form/Unit Comutare între formă şi unit-ul asociat.
Echivalentă cu comanda View/Toggle
Form/Unit (F12).
12 New form Crearea unei forme vide şi a unei noi unităţi şi
adăugarea lor la proiectul curent.
Echivalentă cu comanda File / New Form.

72
13 Trace into Execuţia pas cu pas a programului (inclusiv
instrucţiunile conţinute în subprograme).
Echivalentă cu comanda Run/Trace into
(F7).
14 Step over Execuţia pas cu pas a programului.
Subprogramele apelate sunt execuate într-un
singur pas.
Echivalentă cu comanda Run/Step over (F8).

Paleta de componente
Conţine peste 100 de componente utilizate în dezvoltarea aplicaţiilor, care sunt
organizate în mai multe pagini. Componentele pot fi vizuale (de exemplu butoane,
linii de editare,etc.) sau nevizuale (de exemplu ferestrele standard de dialog, ceasul
sistemului, etc.). O componentă se numeşte vizuală dacă dacă este vizibilă în timpul
execuţiei proiectului în care apare. O componentă se numeşte nevizuală dacă în
timpul proiectării este prezentă ca icoană, iar la execuţia proiectului nu se vede sau
este vizibilă doar dacă este activată prin metode dedicate. Paleta de componente
repartizează componentele în liste astfel:

Lista de componente STANDARD


Sub această etichetă puteţi găsi toate componentele standard pe care le puteţi
folosi cu Delphi: etichete, meniuri, câmpuri de editare, butoane de apăsare, butoane
radio, panouri. Fiecare dintre aceste componente conţine o funcţie de bază cerută de
majoritatea aplicaţiilor.

Lista de componente Additional


Sub această etichetă se regăsesc câteva dintre componentele grafice de bază, cum
ar fi butoanele de tip BitBtn, tipul Tshape, precum şi o serie de alte componente
destinate realizării unor obiective speciale în aplicaţii Delphi (Bevel, ScrollBox,
Chart, StaticText, etc.).

Lista de componente Win32


Componentele din această listă utilizează accesul pe 32 biţi (Windows 95/98 şi
NT).
Lista conţine toate noile componente ale interfeţei, puse la dispoziţie de mediul
Windows 95/98/NT (ImageList- Listă de imagini, ProgressBar- Bara de progres,
StatusBar- Linia de stare, TrackBar-Bara de glisare,etc.).

Lista de componente System


Această listă conţine câteva dintre cele mai interesante componente puse la
dispoziţie de Delphi. Această listă poate fi folosită, de exemplu, pentru a adăuga un
cronometru aplicaţiei Dvs..Tot în această listă veţi găsi un program media player şi
componente DDE.

Lista de componente Data Access

73
Componentele din această listă permit realizarea legăturilor spre articolele
diferitelor baze de date. Ele sunt componente invizibile (în timpul execuţiei nu sunt
afişate pe ecran). Dintre componentele din această listă semnalăm:
- Componenta DataSource – care realizează legătura între componentele
invizibile Table, Query, StoredProc şi componentele vizibile de acces spre
baze de date (de exemplu TDBGrid).
- Componenta Table – Încarcă date dintr-un tabel, care se transmit, prin
intermediul componentei DataSource) spre componentele vizuale de acces la
baze de date.
- Query – Permite utilizarea diferitelor instrucţiuni SQL.

Lista de componente Data Controls


Componentele din această listă sunt destinate afişării şi editării articolelor unei
baze de date. Sunt componente vizuale, care asigură interfaţa vizuală între utilizator şi
o bază de date. Dintre componentele din această listă semnalăm:
- DBGrid – Permite afişarea articolelor unei baze de date sub forma unui tabel
(reţea). Componenta permite şi editarea articolelor bazei.
- DBNavigator - Creează un panou format din mai multe butoane de comandă,
cu ajutorul cărora se poate naviga printre înregistrările bazei de date.
- ş.a.m.d.

Lista de componente Dialogs


Componentele acestei liste permit afişarea şi utilizarea ferestrelor de dialog, care
sunt specifice sistemului de operare Windows 95 (deschideri, salvări, tipăriri de
fişiere).

Alte liste de componente prezente în Paleta de componente: Internet, Decision


Cube, Qreport, Win3.1, Samples, ActiveX.

Inspectorul de obiecte
Inspectorul de obiecte al mediului Delphi este prevăzut cu două pagini. Pagina
Properties permite stabilirea proprietăţilor componentelor în timpul procesului de
proiectare. Pagina Events gestionează diferitele evenimente legate de componentele
aplicaţiei.
La rândul ei, pagina Properties este prevăzută cu două coloane. În coloana din
stânga sunt listate denumirile proprietăţilor. În coloana din dreapta sunt afişate
valorile actuale aferente diverselor proprietăţi. Pentru a atribui o anumită valoare unei
proprietăţi, se efectuiază un click de mouse pe numele proprietăţii. Numele
proprietăţii fiind selectat, atribuirea unei valori la o proprietate poate fi realizată în
trei moduri diferite:
- prin linia de editare aferentă proprietăţii;
- prin lista derulantă corespunzătoare proprietăţii;
- prin intermediul unei ferestre de dialog.

Fereastra formei

74
În procesul de dezvoltare a unei aplicaţii Delphi, forma ocupă un loc central prin
proprietăţile şi evenimentele cu care se poate asocia. Se poate afirma, pe drept cuvânt,
că în jurul conceptului de formă se desfăşoară partea cea mai importantă a
activităţilor specifice unui demers RAD de realizare a unei aplicaţii utilizator.
Pentru descrierea formelor se poate apela, potenţial, la 38 de proprietăţi, care pot
fi stabilite, în perioada de proiectare prin intermediul inspectorului de obiecte, sau
modificate, la nevoie în timpul execuţiei aplicaţiei.
Totodată, formele pot reacţiona la 21 de evenimente. De semnalat faptul că,
majoritatea proprietăţilor şi evenimentelor formelor sunt identice cu proprietăţile şi
evenimentele altor componente importante pentru realizarea aplicaţiilor Delphi.
Acesta este motivul pentru care, vom prezenta, mai jos, cele mai importante
proprietăţi şi evenimente referitoare la forme.

Proprietăţile formelor

Proprietatea ActiveControl
Este utilizată atunci când pe formă au fost aşezate mai multe componente şi se
doreşte specificarea componentei care trebuie să fie în focar în momentul activării
formei sau la un moment dat în timp ce forma este activă. Proprietatea poate fi setată
atât prin intermediul inspectorului de obiecte, în faza de proiectare, cât şi în timpul
execuţiei programului, printr-o atribuire de tipul:

<Variabilă_Formă_gazdă>.ActiveControl:=<Nume_Componentă_focalizată>;

Dacă forma gazdă a componentei memorate în proprietatea ActiveControl nu este


în focar, atunci în momentul în care forma ajunge în focar, componenta memorată în
Active Control este focalizată.

Proprietatea AutoScroll
Este o proprietate de tip boolean care se referă la modul de utilizare a barelor de
defilare ataşate formei. În cazul în care pentru această proprietate se stabileşte
valoarea True, care este şi valoarea implicită, atunci în caz de nevoie, în execuţie
forma va fi prevăzută cu bare de defilare, dacă dimensiunile componentelor
“aşezate” pe formă depăşesc dimensiunile formei. Dacă proprietate este setată la
False, atunci forma nu va mai fi înzestrată automat cu bare de defilare. În acest caz
ataşarea barelor de defilare poate fi realizată prin intermediul proprietăţilor
HorzScrollBar şi VertScrollBar.

Proprietatea BorderIcons
Este o proprietate compusă care se referă la existenţa, în linia de titlu a formei, a
meniului sistem şi a butoanelor de minimizare/maximizare a formei. Această
proprietate este de tip mulţime, valorile posibile fiind:

Valoare Semnificaţie
biSystemMenu Forma este prevăzută cu meniul sistem
biMinimize Forma este prevăzută cu un buton de minimizare

75
biMaximize Forma este prevăzută cu un buton de maximizare
biHelp Dacă proprietatea BorderStyle conţine valoarea
bsDialog sau dacă sunt excluse valorile biMinimize şi
biMaximize, atunci în bara de titlu apare un semn de
întrebare. Dacă se efectuiază un click pe acest semn,
cursorul de mouse va avea forma definită de constanta
crHelp.

Proprietatea BorderStyle
Se referă la stilul chenarului formei. Valorile posibile ale acestei proprietăţi sunt:

Valoare Semnificaţie
bsDialog Chenar neredimensionabil; chenarul standard al
ferestrelor de dialog.
bsSingle Chenar neredimensionabil, desenat cu o linie simplă
bsNone Chenar neredimensionabil, desenat cu linie invizibilă
bsSizeable Chenar redimensionabil standard
bsToolWindows Similar cu bsSingle, dar este prevăzut cu un mic titlu
bsSizeToolWin Similar cu bsSizeable, dar este prevăzut cu un mic titlu

Proprietatea Caption
Este o proprietate de tip string care specifică un şir de caractere care este afişat în
linia de titlu a formei. În cazul componentelor această proprietate desemnează
eticheta ataşată componentei. În acest ultim caz, litera precedată de caracterul “&”
este litera de selecţie a componentei, care va apare subliniată (Componenta poate fi
selectată prin combinaţia Alt+Litera subliniată).

Proprietăţile ClientHeight şi ClientWidth


Acestea sunt două proprietăţi de tip integer care specifică înălţimea şi, respectiv,
lăţimea zonei client a formei. Aceste valori sunt specificate în puncte. Zona client
este aria utilizabilă în interiorul chenarului formei.

Proprietatea Color
Proprietatea este de tip TColor=longint, stabilind culoarea de fond a formei.
Pentru iniţializarea valorică a acestei proprietăţi pot fi folosite constante predefinite
sau valori returnate de funcţia RGB. Valoarea implicită este clBtnFace . Dacă pentru
proprietatea ParentColor corespunzătoare unei componente se ia valoarea True , şi se
modifică valoarea proprietăţii Color corespunzătoare formei proprietar al
componentei, atunci se va modifica automat şi culoarea componentei.

Proprietatea Ctl3D
Fiind de tip boolean, această proprietate stabileşte aspectul tridimensional al
formei pentru True şi aspect bidimensional pentru False. Valoarea implicită este True.
Dacă pentru proprietatea ParentCtl3D corespunzătoare unei componente se ia

76
valoarea True, şi se modifică valoarea proprietăţii Ctl3D corespunzătoare formei
proprietar al componentei, atunci se va modifica automat şi aspectul componentei.

Proprietatea Cursor
Stabileşte imaginea utilizată pentru reprezentarea cursorului de mouse. Pentru
selectarea unei imagini se vor folosi diferitele constante predefinite asociate. Valoarea
implicită este crDefault.

Proprietatea Enabled
Şi această proprietate este de tip boolean şi se referă la accesibilitatea formei sau
componentei.Dacă proprietatea este setată la True, care este şi valoarea implicită,
atunci forma sau componenta va reacţiona la diferite evenimente pe care este abilitată
să le trateze. Dacă se alege varianta False, forma sau componenta este inhibată.
Valoarea acestei proprietăţi se modifică, de regulă, în timpul execuţiei. Astfel, dacă la
un moment dat, un anumit buton trebuie dezactivat, proprietatea Enabled a acestuia
este setată la False. Evident, la nevoie, componenta dezactivată poate fi reactivată.

Proprietatea compusă Font


Stabileşte fontul utilizat în textele care sunt afişate pe obiectul Canvas al formei,
precum şi la textele aferente componentelor aşezate pe formă. Fontul utilizat poate fi
definit în perioada de elaborare a proiectului, însă poate fi modificat şi în timpul
execuţiei, prin redefinirea subproprietăţilor Color, Height, Name, Pitch, Size, sau
Style.
Astfel că, dacă este necesar, sunt absolut plauzibile setările de mai jos.

Font.Color:=clBlue;
Font.Size:=18;
Font.Style:=[fsBold];

Proprietatea FormStyle
Stabileşte stilul formei. Valorile posibile ale acestei proprietăţi sunt următoarele:

Valoare Semnificaţie
fsNormal Forma crează o fereastră normală (nici MDI copil,
nici MDI părinte). Valoare implicită.
fsMDIChild Forma creează o fereastră MDI copil.
fsMDIForm Forma creează o fereastră MDI părinte.
fsStayOnTop Forma va fi afişată deasupra celorlaltor forme
utilizate în proiect.

Proprietţile Height şi Width


Aceste proprietăţi de tip integer stabilesc înălţimea, respectiv, lăţimea formei sau
componentei, în puncte care include şi dimensiunile rezervate chenarelor.

Proprietatea Hint

77
Proprietate de tip string, specifică un text explicativ care va fi afişat atunci când
cursorul de mouse este aşezat deasupra unei forme sau componente. Acest text este
afişat numai atunci când proprietatea ShowHint (de tip boolean) este setată la True.

Proprietăţile compuse HorzScrollBar şi VertScrollBar


Stabilesc dacă forma este prevăzută sau nu cu bare de defilare orizontale şi/sau
verticale. Subproprietăţile barelor de defilare sunt prezentate în tabelul următor:

Subproprietate Descriere
Increment Stabileşte distanţa de deplasare a componentei sau imaginii
(O valoare cuprinsă din formă în momentul în care utilizatorul efectuează un
între 1 şi 32767, click pe unul din butoanele ci săgeţi situate în extremităţile
valoarea implicită barelor de defilare.
este 8)
Margin Stabileşte momentul de afişare a barei de defilare.
(De tip word, Această proprietate determină numărul minim de puncte
valoarea implicită 0) care separă componentele formei şi muchia formei. În
execuţie, dacă o componentă ajunge să fie la o distanţă mai
mică decât Margin puncte de la muchie şi dacă proprietatea
Visible este setată la True, atunci se afişează o bară de
defilare.
Position Comunică poziţia curentă a cursorului glisat al barei de
(De tip integer, defilare. Valoarea acestei proprietăţi este actualizată
valoarea implicită 0) automat, în timpul execuţiei aplicaţiei.
Range Dimensiunea maximă de defilare, exprimată în puncte. La
(De tip integer, bara de defilare verticală această valoare trebuie să fie mai
valoarea implicită 0) mare decât valoarea proprietăţii Height (în caz contrar, bara
verticală este invizibilă). La bara de defilare orizontală
această valoare trebuie să fie mai mare decât valoarea
proprietăţii ClientWidth (În caz contrar, bara orizontală este
invizibilă).
Tracking Dacă se alege valoarea True, imaginea / componenta din
(De tip boolean, formă se deplasează împreună cu butonul de glisare tras de
valoarea implicită utilizator. Dacă se alege valoarea False, imaginea rămâne
false) statică cât timp utilizatorul trage butonul de glisare,
adică actualizarea imaginii defilate are loc numai în
momentul eliberării butonului glisant al barei de defilare.
Visible Se referă la vizibilitatea barei de defilare. Dacă se alege
(De tip boolean, valoarea True şi dacă componenta se află la o distanţă mai
valoare implicită mică decât Margin puncte de muchia formei, atunci bara de
True) defilare devine vizibilă.

Proprietatea Icon
Specifică simbolul grafic care va fi utilizat când forma este minimizată.

Proprietatea KeyPreview

78
De tip boolean, se referă la modul de gestiune al evenimentelor referitoare la
tastatură (OnKeyDown, OnKeyPress, OnKeyUp). Dacă pentru această proprietate se
alege valoarea True, atunci evenimentele referitoare la tastatură sunt gestionate de
forma actuală, nu de componentele aşezate pe formă, chiar dacă în momentul
respectiv în focar se află o componentă. Astfel că, dacă, de exemplu, forma conţine
un buton de comandă care este în focar, dacă utilizatorul apasă o tastă, evenimentul
aferent va fi gestionat de procedurile formei, nu de procedurile butonului.

Proprietăţile Left şi Top


Stabilesc abscisa, respectiv ordonata :
-formei faţă de colţul stânga sus al ecranului;
-componentei faţă de colţul stânga sus al formei proprietar;
-componentei faţă de colţul stânga sus al unei componente de tip container.
Valorile acestor proprietăţi sunt date în puncte.

Proprietatea Menu
De tip TmainMenu , stabileşte componenta de tip meniu principal care este
utilizată de formă la un moment dat. În perioada de elaborare a proiectului această
proprietate este iniţializată automat cu prima componentă MainMenu aşezată pe
formă. În timpul execuţiei această valoare poate fi modificată, printr-o instrucţiune de
atribuire, ceea ce înseamnă că o formă poate să folosească mai multe componente
MainMenu.
De analizat şi exemplul de mai jos.

procedure TForm1.SchimbMeniu_1;
begin
Menu:=MainMenu2;
end;

procedure TForm1.SchimbMeniu_2;
begin
Menu:=MainMenu1;
end;
Proprietatea PopupMenu
De tip TPopupMenu, identifică componenta de meniu flotant care este utilizată de
formă la un moment dat. Se menţionează faptul că această proprietate nu este
iniţializată automat cu componenta PopupMenu aşezată pe formă. În execuţie
valoarea acestei proprietăţi poate fi modificată printr-o instrucţiune de atribuire ,
astfel că o formă poate să folosesscă, în funcţie de context, mai multe componente
PoppupMenu.

Proprietatea Name
De tip string, este utilizată pentru atribuirea unui nume( ca variabile obiect) unei
forme sau componente. Atribuirile de nume sunt realizate automat de sistemul
Delphi, însă aceste denumiri predefinite (Form1,Form2,…Button1,Button2,…,etc.),
nu întotdeauna pe gustul oricărui programator, pot fi modificate, codul aplicaţiei
putând fi personalizat şi devenind astfel mai lizibil.Dacă proprietatea Caption nu a

79
fost încă modificată şi dacă se atribuie un nou nume unei forme, atunci proprietatea
Caption va fi modificată automat la noul nume.

Proprietatea ParentFont
De tip boolean, se referă la modul de selecţie al fontului corespunzător unei
componente. Dacă se alege valoarea True , atunci fontul utilizat de o componentă este
identic cu fontul utilizat de forma proprietar. Dacă se alege varianta False, atunci
fontul componentei nu va depinde de fontul formei proprietar (adică proprietatea
Font a componentei este prioritară faţă de proprietatea Font a formei gazdă. Valoarea
implicită a acestei proprietăţi este False.

Proprietatea Position
Se referă la dimensiunea şi locul de plasare a formei în timpul execuţiei, faţă de
dimensiunea şi locul de amplasare care au fost utilizate în timpul proiectării. Valorile
posibile ale acestei proprietăţi sunt următoarele:

Valoare Semnificaţie
poDesigned Dimensiunea şi poziţia formei în execuţie coincid cu
dimensiunea şi poziţia formei utilizată în timpul proiectării.
Valoare implicită.
poDefault Nu se conservă nici dimensiunea, nici poziţia iniţială a
formei; noile valori sunt determinate de sistemul Delphi.
poDefaultPosOnly În execuţie va fi conservată dimensiunea formei, însă
poziţia acesteia va fi stabilită de sistemul Delphi.
poDefaultSizeOnly În execuţie va fi conservată poziţia formei, însă
dimensiunea acesteia va fi stabilită de sistemul Delphi.
poScreenCenter La execuţie se conservă dimensiunea formei, însă aceasta
va fi plasată centrat pe ecran.

Proprietatea PrintScale
Se referă la modul de tipărire a formei, mai precis la modul de alegere a scalei
utilizate în procesul de tipărire. Valorile posibile ale acestei proprietăţi sunt :
Valoare Semnificaţie
poNone Nu se face nici o scalare specială, astfel încât forma tipărită
la imprimantă poate să se deosebeasă de forma afişată pe
ecran
poProporţional Se va utiliza o scală prin care dimensiunea formei tipărite va
fi aprozimativ egală cu dimensiunea formei afişate pe ecran
(WYSIWYG). Valoare implicită.
poPrintToFit Forma este tipărită în aşa fel încât se conservă proporţiile
afişate pe ecran, dar dimensiunea de tipărire este determinată
în aşa fel încât forma va încape pe foaia utilizată.

Proprietatea Scaled

80
De tip boolean, stabileşte modul de dimensionare a formei, în funcţie de
proprietatea PixelsPerInch. Dacă se alege valoarea True, care este şi valoarea
implicită, atunci proprietatea PixelsPerIInch stabileşte numărul de puncte care va
corespunde într-un inch al formei. Dacă se alege valoarea False, atunci valoarea
specificată în proprietatea PixelsPerInch va fi neglijată.

Proprietatea Tag
De tip longint, este utilizată atât în cazul formelor cât şi în cazul componentelor.
Cu ajutorul acestei proprietăţi, se poate adăuga o valoare formelor sau
componentelor. Această proprietate nu are o semnificaţie predefinită, putând fi
utilizată în diverse scopuri de către programatori. Prezentăm , în continuare un
exemplu de utilizare a proprietăţii Tag.

unit Unit1;

interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
B:TButton;
implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);


begin
B:=Button1;
end;

procedure TForm1.Button2Click(Sender: TObject);


begin

81
B:=Button2;
end;

procedure TForm1.FormClick(Sender: TObject);


begin
if Assigned(B)
then
case B.Tag of
1: Form1.Caption:='Butonul 1...';
2: Form1.Caption:='Butonul 2...';
end;
end;

end.

Proprietatea Visible
De tip boolean, se referă la vizibilitatea formei. Dacă se alege valoarea True,
forma va fi vizibilă în timpul execuţiei. Dacă se alege valoarea False, forma va fi
invizibilă în timpul execuţiei. Proprietate Visible a unei forme poate primi valoarea
True şi prin intermediul metodelor Show şi ShowModal.

Proprietatea WindowMenu
De tip TMenuItem, este utilizată numai în cazul formelor MDI părinte (al căror
stil este fsMDIForm). Cu ajutorul acestei proprietăţî se desemnează un element de
meniu din linia meniului principal, la care sistemul Delphi va adăuga automat meniul
Window (lista ferestrelor copil deschise în fereastra părinte, cu indicarea ferestrei
active).

Proprietatea WindowState
Se referă la modul de afişare pe ecran a formei. Valorile posibile ale acestei
proprietăţi sunt următoarele:

Valoare Semnificaţie
wsNormal Forma este afişată în stare normală; nici minimizată, nici
maximizată. Valoare implicită.
wsMinimized Forma este afişată în stare minimizată.
wsMaximized Forma este afişată în stare maximizată.

Evenimentele asociate formelor

Evenimentul OnActivate
Acest eveniment apare în momentul în care o formă ajunge în focar (De exemplu,
utilizatorul lucrează simultan cu mai multe forme şi efectuiază un click de mouse pe
una dintre ele, ceea ce determină ajungerea respectivei forme în focar). În cazul în
care proiectul conţine o singură formă, în momentul lansării în execuţie a proiectului

82
forma respectivă va fi automat activată. Proceduta ataşată acestui eveniment are
următorul prototip:

procedure TForm1.FormActivate(Sender: TObject);


begin
:
end;

De observat faptul că, în cazul ferestrelor a căror proprietate FormStyle are


valoarea fsMDIChild , evenimentul onActivate apare numai atunci când focarul este
transferat dintr-o fereastră copil într-o altă fereastră copil.

Evenimentul OnClick
Se produce atunci când utilizatorul unui program efectuiază un click de mouse pe
o zonă liberă a formei sau pe o componentă care în momentul respectiv este inhibată.
Procedura ataşată acestui eveniment are prototipul următor:

procedure TForm1.FormClick(Sender: TObject);


begin
:
end;

Evenimentul OnDblClick
Apare atunci când utilizatorul efectuiază un dublu click de mouse pe o zonă liberă
a formei sau pe o componentă care în momentul respectiv este inhibată. Procedura
ataşată acestui eveniment are prototipul următor:

procedure TForm1.FormDblClick(Sender: TObject);


begin
:
end;

Evenimentul OnCloseQuery
Apare în momentul în care utilizatorul este autorul unei acţiuni prin care
semnalează faptul că doreşte să închidă forma. Astfel de acţiuni sunt: apelarea
metodei Close, efectuarea unui click pe butonul de închidere, efectuarea unui dublu
click pe meniul sistem al formei sau apelarea comenzii Close din meniul sistem.
Procedura ataşată acestui eveniment are următorul prototip:

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);


begin
:
end;

Dacă în această procedură i se atribuie parametrului variabil CanClose valoarea


True, forma poate fi închisă şi în continuare se lansează în execuţie procedura ataşată

83
evenimentului OnClose. Dacă variabile CanClose i se atribuie valoarea False, forma
nu poate fi închisă.

Evenimentul OnClose
Se produce în momentul în care utilizatorul a cerut închiderea formei. El se
declanşează după evenimentul OnCloseQuery. Procedura ataşată are prototipul:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);


begin
:
end;

Parametrul variabil Action stabileşte dacă forma trebuie să fie într-adevăr închisă.
Valorile posibile ale acestui parametru sunt următoarele:

Valoare Semnificaţie
caNone Nu se autorizează închiderea ferestrei
caHide Forma nu este închisă ci doar ascunsă. În continuare
utilizatorul poate să aibă acces la această formă şi poate să
ceară reafişarea formei cu metoda Show. Această valoare
este valoarea implicită în cazul formelor care au stil diferit
de fsMDIChild.
caFree Forma este închisă şi memoria alocată formei este eliberată.
caMinimize Forma nu este închisă, doar minimizată. Această valoare este
valoarea implicită în cazul formelor care au stilul
fsMDIChild.

În exemplul de mai jos se poate urmări un mod de tratare a celor două


evenimente.

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TForm1 = class(TForm)
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;

84
var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);


begin
if MessageDlg('Se inchide forma?',mtConfirmation,
[mbOk,mbCancel],0)=mrCancel
then CanClose:=False
else CanClose:=True;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);


begin
if MessageDlg('Se inchide forma(Y/N?',mtConfirmation,
[mbYes,mbNo],0)=mrYes
then Action:=caFree
else Action:=caNone;
end;

end.

Evenimentul OnCreate
Apare în momentul în care se creează forma (adică la prima execuţie a formei).
De regulă se foloseşte pentru iniţializarea proprietăţilor formei şi a componentelor
aşezate pe aceasta. Procedura ataşată evenimentului OnCreate are următorul prototip:

procedure Tform1.FormCreate(Sender: TObject);


begin
:
end;

De semnalat faptul că în procesul de creare a unei forme, dacă proprietatea de


vizibilitate a acesteia (Visible) este True, se vor declanşa următoarele evenimente, în
ordinea specificată mai jos:

OnCreate
OnShow
OnActivate
OnPaint

Evenimentul OnDeactivate

85
Apare în momentul în care forma urmează să piardă focarul, altfel spus atunci
când aplicaţia foloseşte mai multe forme şi utilizatorul printr-un click de mouse
activează altă formă. De menţionat faptul că trecerea de la o aplicaţie la alta (nu la o
altă formă a aplicaţiei curente) poate fi prelucrată prin evenimentul OnDeactivate
ataşat obiectelor de tip Tapplication.
Procedura ataşată evenimentului OnDeactivate al formei are prototipul:

procedure TForm1.FormDeactivate(Sender: TObject);


begin
:
end;

Evenimentul OnDestroy
Apare în momentul în care se distruge forma actuală (adică se eliberează toate
resursele ataşate formei). Procedura ataşată acestui eveniment are prototipul următor:

procedure TForm1.FormDestroy(Sender: TObject);


begin
:
end;

În această procedură se vor distruge toate acele obiecte, care au fost create în
metoda de tratare a evenimentului OnCreate.

Evenimentul OnHide
Apare în momentul în care forma este ascunsă, adică proprietatea de vizibilitate a
formei Visible este iniţializată cu valoarea False. Procedura ataşată acestui eveniment
are următorul prototip:

procedure TForm1.FormHide(Sender: TObject);


begin
:
end;

Evenimentul OnShow
Apare în momentul în care forma este afişată, adică proprietatea de vizibilitate a
formei (Visible) este iniţializată cu valoarea True. Procedura ataşată acestui
eveniment are prototipul următor.

procedure TForm1.FormShow(Sender: TObject);


begin
:
end;

Evenimentul OnPaint

86
Este declanşat în momentul în care unele zone ale formei curente trebuie să fie
redesenate (de exemplu datorită faptului că unele zone ale formei au fost acoperite
temporar de alte ferestre). Procedura ataşată acestui eveniment are prototipul următor:

procedure TForm1.FormPaint(Sender: TObject);


begin
:
end;

Evenimentul OnResize
Este declanşat în momentul în care forma a fost redimensionată de utilizator. De
regulă în procedura aferentă acestui eveniment se va realiza reaşezarea şi
redimensionarea componentelor aşezate pe formă. Se menţionează faptul că acest
eveniment este declanşat şi în procesul de creare a formei. Procedura ataşată acestui
eveniment are prototipul:

procedure TForm1.FormResize(Sender: TObject);


begin
:
end;

Alte evenimente asociate formei vor fi prezentate în contexte în care este


oportună o discuţie mai amplă şi mai precisă asupra lor.

Fereastra de editare a codului


În momentul iniţial, fereastra de editare a codului se află în spatele ferestrei
formei, fiind vizibilă partea ei inferioară, deci poate fi activată oricând printr-un click
de mouise. În această fereastră se introduce codul programului, care stabileşte modul
de tratare a diferitelor evenimente. Fereastra este un editor ASCII complet; pot fi
deschise simultan mai multe ferestre de cod. Conţinutul lor este salvat în diferite unit-
uri. Extensia fişierelor de unităţi este întotdeauna .PAS, prin care se semnalează
faptul că aceste fişiere conţin un anumit cod scris în limbajul Object Pascal.
Formatul acestor fişiere este întotdeauna ASCII.
La intrare în Delphi sau la crearea unui nou proiect, editorul de cod conţine textul
sursă aferent unităţii principale. Numele implicit al fişierului unităţii principale este
Unit1.PAS şi are următorul conţinut:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TForm1 = class(TForm)

87
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

end.

5.3 Cum se foloseşte un mediu vizual de programare?


După ce am văzut ce înseamnă dezvoltarea rapidă de aplicaţii, după ce ne-am
format o idee despre “potenţialul de asistare” al mediului Delphi, după ce, în sfârşit,
am înţeles câte ceva despre suportul oferit de Object Pascal pentru a realiza sisteme
soft, merită şi chiar cred că este folositor să vedem, din perspectivă pragmatică, cum
se foloseşte un mediu vizual de programare.
Cu referire directă la Delphi, am putea să luăm în considerare următoarele:

1. Realizarea interfeţei cu utilizatorul este simplificată enorm, îndeosebi dacă


tipul de interfaţă este aliniat la standardele aplicaţiilor Windows. Aşadar,
programatorul poate să investească timpul consumat, altfel, pentru realizarea
interfeţei, în activităţi de modelare a soluţiei, de optimizare a codului, etc.

2. Mare parte din problema gestiunii evenimentelor recunoscute de o aplicaţie


este rezolvată cu suport consistent din partea mediului. În procesul de
proiectare, forma sau formele care compun o aplicaţie este/sunt populate de
diferite componente care au un comportament predefinit dar au şi deschidere
către disponibilităţi comportamentale specifice unei aplicaţii anume. În
această privinţă succesul în utilizarea unui mediu vizual de programare
depinde de gradul de cunoaştere a comportamentului implicit al
componentelor. Necunoaşterea acestui comportament generează “reinventarea
roţii” sau dificultăţi deosebite în rezolvarea chiar şi a unor probleme mărunte.
De reţinut că programatorul în stil clasic trebuie să lupte cu obişnuinţa de a
controla “tot ce mişcă” într-un program dacă s-a hotărât să lucreze într-un
mediu vizual de programare.

3. Odată adăugate elementele grafice ale interfeţei aplicaţiei cu utilizatorul,


programatorul trebuie să adauge cod pentru a da răspunsuri evenimentelor
specifice ale aplicaţiei. În Delphi acest cod seamănă atât de bine cu codul
Pascal incât orice programator cu abilităţi în scrierea de cod Pascal devine
rapid un aprogramator abil în Delphi dacă rezolvă, tot rapid, nişte probleme de

88
mentalitate formată în Pascalul clasic. Este vorba despre obiect orientare şi de
o serie de noutăţi în materie de sintaxă în zona obiect orientată, cu predilecţie.

4. Am lăsat la urmă, dar, poate că această problemă trebuie rezolvată prima,


chiar şi într-un mediu vizual de programare, înainte de a ne repezi în tastatură,
trebuie să vedem cât de clare sunt o serie de probleme referitoare la:
-cerinţele faţă de aplicaţie;
-structura interfeţei;
-tipul de modularizare ales;
-structura algoritmilor critici folosiţi.
Alinierea la paradigma RAD ne mai atrage atenţia şi asupra altor aspecte
demne de luat în seamă, înainte de a porni “voiniceşte” la scrierea de cod
Object Pascal, de exemplu..

89
6. Aplicaţii cu baze de date în Delphi
6.1. Introducere

Utilizând Borland Database Engine (BDE), Delphi oferă capabilităţi de


comunicare cu lumea SGBD-urilor gen: Paradox, dBase, Access, FoxPro,
servere SQL, etc., folosind în acest scop un protocol de lucru unitar.
Realizarea aplicaţiilor Delphi care implică utilizarea intensă a bazelor de date
presupune învăţarea acestui protocol unitar cât şi a elementelor suport disponibile în
VCL pentru realizarea aplicaţiilor cu baze de date.
Pentru cei interesaţi ar fi de spus faptul că ediţia standard a kitt-ului Delphi 5, de
exemplu, nu conţine capabilităţi de tip “database conectivity”. Ediţia profesională
furnizează capabilităţi de acces la fişiere Paradox, dBase (în mod nativ), Access,
FoxPro şi fişiere în format text ASCII, la care se adaugă deschidere către surse de
date ODBC şi Local Interbase.
Delphi Enterprise, construit peste Delphi Profesional, are deschidere către
Interbase, Microsoft SQL Server, Oracle, Informix Dynamic Server, Sybase Adaptive
Server, DB2.
Există destui specialişti care laudă Delphi pentru abilitatea de a aduce uşor în
aplicaţiile utilizator date provenind din “pestriţa” lume a SGBD-urilor. Există şi
specialişti care manifestă reţinere faţă de această “frenezie” a mediilor vizuale de
programare de a lua în stăpânire, cu pretenţii din ce în ce mai mari, universul
aplicaţiilor puternic marcate de prezenţa bazelor de date. Nu avem timp de
consideraţii pe marginea “suferinţelor” nici uneia dintre categoriile de specialişti mai
sus menţionate. Ceea ce vom face în continuare va fi un lucru foarte precis:

-învăţarea universului conceptual cu care se operează în Delphi, în procesul


de realizare a aplicaţiilor cu baze de date;
-exemplificarea şi comentarea elementelor de sintaxă Object Pascal, esenţiale
pentrru realizarea aplicaţiilor cu baze de date;
-Prezentarea, dacă este cazul, a componentelor direct implicate în lucrul cu
baze de date.

6.2 Concepte în lucrul cu baze de date în Delphi.


Dată fiind diversitatea tipurilor de fişiere (deci baze de date) cu care încearcă Delphi
să comunice, este de aşteptat, pentru a se crea un cadru unitar de lucru cu aceste
fişiere(baze de date), să se realizeze o abstractizare convenabilă a acestei diversităţi.
Cea mai înaltă abstractizare Delphi a unei coleţii de date o reprezintă conceptul de set
de date (DataSet).

90
Fără a exagera cu formalizarea, un set de date este o colecţie de linii de date,
fiecare linie având mai multe coloane, fiecare coloană fiind omogenă din punct
de vedere al tipului.
În limbaj de specialitate, o coloană se mai numeşte şi câmp iar o linie se mai
numeşte şi înregistrare. Putem spune că setul de date abstractizează un procedeu
de caracterizare informaţională a unei realităţi obiectuale sau de altă natură, ca
o coleţie de date structurate pe linii şi coloane.
VCL Delphi încapsulează un set de date într-o componentă abstractă numită
TDataSet. TDataSet introduce multe dintre proprietăţile şi metodele necesare pentru
manipularea şi navigarea într-un set de date. Pentru mai multă rigoare, noţiunile de
bază cu care se operează în lumea aplicaţiilor Delphi orientate pe baze de date sunt:

-Setul de date: o colecţie de înregistrări; fiecare înregistrare are mai multe


câmpuri. Fiecare câmp poate conţine un tip diferit de dată (număr întreg, şir de
caractere, număr zecimal, obiect grafic, etc).
-Tabelul: un tip special de set de date (= un exemplu concret de set de date). Un
tabel este, în general, un fişier conţinând înregistrări care, fizic, sunt păstrate pe un
suport de memorie externă. Tabelul este abstractizat funcţional de clasa TTable a
VCL.
-Query: este, de asemenea un tip special de set de date. De fapt, un Query este un
tabel păstrat în memorie, generat de comenzi speciale care manipulează o anumită
tabelă sau o colecţie de tabele. Obiectele Query sunt abstractizate în VCL de clasa
TQuery. O componentă TQuery vă permite să interogaţi baza de date sau orice altă
sursă de date sub forma unei întrebări precise (formalizate SQL – Structured Query
Language) şi să primiţi ca răspuns numai informaţiile de care aveţi nevoie (a se
analiza ce se întâmplă în maniera clasică de interogare, într-o reţea!).
-Database: desemnează un director pe disc (dacă este vorba de date non-server
specifice Paradox, dBaze, etc.) sau o bază de date SQL în cazul în care se lucrează cu
un server SQL. VCL încapsulează acest concept cu ajutorul clasei TDataBase.
-Index: defineşte regulile care stau la baza ordonării unei tabele. Clasa TTable
conţine proprietăţi ţi şi metode care folosesc la manipularea indecşilor.

6.3 VCL şi lucrul cu baze de date în Delphi


De la o versiune la alta, arhitectura VCL relativă la lucrul cu baze de date a fost
îmbunătăţită, astfel încât un număr tot mai mare de tipuri de baze de date să fie uşor
de folosit în Delphi. În spatele acestui plus de potenţial, de la o versiune la alta, se
află BDE (Borland Database Engine). Rădăcina ierarhiei VCL de clase care
modelează lucrul cu baze de date este ocupată de clasa TDataSet. TDataSet este o
componentă care furnizează o reprezentare abstractă a înregistrărilor şi tipurilor de
date. O serie de metode ale clasei TDataSet pot fi redefinite pentru a crea componente
care comunică cu formate fizice de date particulare.
Pagina Data Acces a VCL conţine componente care pot fi folosite pentru accesul şi
gestiunea BDE-DataSet-urilor.
VCL reprezintă, la interfaţa cu programatorul, dataset-urile, folosind 3
componente: TTable, TQuery şi TStoredProc. Toate aceste componente sunt derivate

91
direct din componenta TDBDataSet care este, la rândul ei, derivată din
TBDEDataSet, având ca strămoş direct TDataSet.

Aşadar:

TDataSet

TBDEDataSet

TDBDataSet

TTable TQuery TStoredPtoc

În această ierarhie:
-TDataSet este o componentă abstractă care încapsulează capabilităţile de
management, navigare şi manipulare a dataset-urilor.
-TBDEDataSet este, de asemenea, o componentă abstractă care reprezintă un
dataset specific BDE.
-TDBDataSet introduce concepte precum: database şi sesiune BDE.
-TTable este o componentă care care reprezintă structura şi datele conţinute într-o
tabelă a unei baze de date.
-TQuery este o componentă care reprezintă un set de date returnate în urma unei
înterogări SQL.
-TStoredProc încapsulează o procedură stocată pe un server SQL.

Deschiderea unui DataSet (Tabel)


Înainte de a face orice altă operaţie asupra unui tabel, trebuie, mai întâi să-l
deschideţi.
Deschiderea unui tabel se poate face cu un simplu apel al metodei Open():

:
Tabel1.Open;
:

92
ceea ce este echivalent cu setarea proprietăţii Active a unui tabel la valoarea True.

:
Tabel1.Active:=True;

Odată ce aţi deschis un tabel, sunteţi liberi să îl manipulaţi. Terminarea lucrului


cu un tabel înseamnă un apel de tipul:

Tabel1.Close;

sau

Tabel1.Active:=false;

Navigarea într-un tabel


TDataSet furnizează o serie de metode simple pentru operaţiile fundamentale
necesare pentru navigarea într-un tabel.
First() – poziţionare pe prima înregistrare a tabelului.
Last() – poziţionare pe ultima înregistrare a tabelului.
Next() – poziţionare pe următoarea înregistrare în tabel, în raport cu pointerul
curent;
Prior() – poziţionare pe precedenta înregistrare în tabel, in raport cu pointerul
curent.
MoveBy() – deplasează pointerul de înregistrare înainte sau înapoi cu un număr
de înregistrări, indicat prin parametrul pozitiv sau negativ al metodei.
TDataSet are proprietăţile booleene BOF şi EOF, care indică dacă înregistrarea
curentă este prima sau ultima relativ la tabelul asociat. Este plauzibil următorul cod:

Table1.First;
while not Table1.EOF do
begin
...
...
Tabel1.Next;
end;

Semne de carte
Semnele de carte permit salvarea poziţiei curente din tabel astfel că, ulterior se
poate reveni rapid în aceeaşi poziţie. Manevrarea semnelor de carte este doar o
problemă de setare/consultare a unei proprietăţi.

:
var
BM:TbookMarkStr;
Begin

93
BM:=Table1.BookMark;
:
Table1.BookMark:=BM;
:

Lucrul cu câmpurile unui tabel


Delphi permite accesul la câmpurile unui tabel cu ajutorul obiectelor de tip
TField şi al descendenţilor acestui tip. Programatorul poate citi şi seta valoarea unui
cîmp al înregistrării curente, dar poate şi să modifice comportamentul câmpului prin
modificarea proprietăţilor lui.

Valorile unui câmp


În Delphi, se pot accesa foarte uşor câmpurile unui tabel. TDataSet are o proprietate
array implicită, numită FieldValues[ ] care returnează valoarea unui câmp particular
ca o valoare de tip Variant. Deoarece FieldValues[ ] este o proprietate array
implicită, nu este necesar să specificaţi numele proprietăţii pentru a accesa array-ul.
De exemplu, în codul:

:
var
S:string;
:
S:=Table1['Nume Client'];

valoarea câmpului 'Nume Client' al înregistrării curente este asignată variabilei S.


O consecinţă imediată a mecanismului ilustrat de codul de mai sus este
posibilitatea de a păstra valorile mai multor câmpuri într-un tablou variant. În Delphi,
unit-ul System declară mai multe funcţii cu ajutorul cărora pot fi manipulate
tablourile Variant.
Astfel avem:

function VarArrayCreate (const Bounds:array of integer; varType:integer):


variant;

Funcţia creează un tablou variant ale cărui limite sunt specificate de Bounds iar tipul
elementelor este specificat de paramatrul varType. Constanta Bounds este un vector
care trebuie să aibă un număr par de elemente, deoarece pentru fiecare dimensiune
trebuie specificată limita inferioară şi limita superioară. VarType este una din valorile
asociate tipurilor recunoscute ca variant mai puţin varArray, varByRef, varString.
Pentru a crea un vector de string-uri se poate folosi codul de tip varOleStr. Dacă
varType este varVariant atunci elementele vectorului sunt variant care pot conţine la
rândul lor alte tipuri variant.

function VarArrayOf (const Values:array of variant):variant;

94
Funcţia este folosită pentru a crea un vector unidimensional având tipul de bază
variant iar valorile care populează vectorul sunt specificate în Values.

function VarArrayDimCount (const A:variant):integer;

Returnează numărul de dimensiuni ale unui tablou variant. În cazul în care A nu


este un tablou variant se returnează 0.

function VarArrayHighBound (const A:variant;Dim:integer):integer;

Returnează limita superioară a dimensiunii Dim a unui tablou variant. Prima


dimensiune este 1, a doua dimensiune este 2, etc.

function VarArrayLowBound (const A:variant;Dim:integer):integer;

Returnează limita inferioară a unei dimensiuni. Utilizând potenţialul unui tablou


variant, este plauzibil următorul cod:

:
const
Sir=' %s are funcţia %s şi are salariul %f ';
:
var
VarArr:variant;
F:double;
:
begin
VarArr:=VarArrayCreate([0,2],var Variant);
VarArr:=Table1['Nume;Funcţia;Salariul '];
F:=VarArr[2];
ShowMessage(Format(Sir,[VarArr[0],VarArr[1],F));
end;

Delphi 1 a introdus o tehnică de acces la valorile câmpului unui tabel, bazată pe


proprietatea array Fields[], sau pe funcţia FieldsByName() şi pe asocierea unui
obiect TField cu un tabel.
Fields[] este un tablou zero-bazat, ceea ce înseamnă că Fields[0] returnează un
obiect reprezentând primul câmp logic al înregistrării curente şi aşa mai departe.
FieldsByName() acceptă un parametru string care specifică numele unui câmp al
unei tabele.
Dat un obiect TField, puteţi regăsi sau asigna valoarea unui câmp folosind una din
proprietăţile TField.

Proprietate Valoare returnată


AsBoolean Boolean
AsFloat Double
AsInteger Longint

95
AsString String
AsDataTime TDataTime
Value Variant

Deci este plauzibil codul:


:
var
S:string;
S:=Table1.Fields[0].AsString;
:

Tipuri de date câmp


Dacă doriţi să cunoaşteţi tipul unui câmp, consultaţi proprietatea DataType a
obiectului TField, care indică tipul de date raportat la tabela bazei de date (indiferent
de tipul Object Pascal corespunzător). Proprietatea DataType este de tip TFieldType
iar TFieldType are definiţie de genul:

:
type
TFieldType=(ftUnknown, ftString, ftSmallint, ftInteger,
ftWord, ftBoolean, ftFloat, ftCurrency, ftBCD,ftDate,
ftTime, ftDateTime, ftBytes, ftVarBytes, ftAutoInc,
ftBlob, ftMemo, ftGraphic, ftFirstMemo, ftParadoxOLE,
ftDBazeOle, ftTypedBinary, ftCursor, ftFixedChar,
ftWideString,...)
:

Numele şi numărul unui câmp


Pentru a găsi numele unui câmp se poate folosi proprietatea FieldName a unui
obiect TField. Astfel, putem avea:

:
var
S:string;
begin
S:=Table1.Fields[0].FieldName;
end;

De asemenea, se poate obţine numărul unui câmp al cărui nume se cunoaşte cu


ajutorul proprietăţii FieldNo, astfel:

:
var
I:integer;
begin
I:=Table1.FieldsByName('Name').FieldNo;
end;

96
Manipularea câmpurilor de date
Există trei paşi în editarea unuia sau a mai multor câmpuri ale înregistrării curente:

1. Apelarea metodei Edit() a unui DataSet pentru a trece un DataSet în modul Edit.
2. Asignarea noilor valori câmpurilor alese printr-o astfel de operaţie.
1. Validarea schimbărilor efectuate asupra DataSet-ului, sau prin apelul metodei
Post() sau prin trecerea la o nouă înregistrare, ceea ce validează automat
rezultatul editării.

:
Table1.Edit;
Table1['Nume']:= 'Corneliu Vadim';
Table1.Post;
:

De remarcat şi proprietatea CanModify, care returnează True dacă DataSet-ul poate


fi editat.

Unui DataSet i se pot insera sau adăuga înregistrări şi astfel:

1.Apelaţi una din metodele Insert() sau Append() ale DataSet-ului pentru a comuta
în modul insert sau append.

2.Atribuiţi valori câmpurilor.

3.Validarea unei înregistrări în DataSet prin apelul metodei Post() sau prin trecerea la
o nouă înregistrare, care forţează validarea.

Dacă dintr-un anume motiv, adăugările sau modificările făcute, dar nevalidate,
trebuie abandonate, acest lucru este posibil prin apelul metodei Cancel(), ca mai jos:

:
Table1.Edit;
Table1['Nume']:= 'Corneliu Vadim';
Table1.Cancel;
:

Apelul metodei Cancel invalidează schimbările operate asupra ultimei înregistrări,


scoate DataSet-ul din modul Edit, Append sau Insert şi îl aduce înapoi la modul
Browse. Pentru a şterge o înregistrare a unui dataset, se foloseşte metoda Delete()
astfel:

:
Table1.Last;
Table1.Delete;
:

97
pentru a şterge ultima înregistrare din dataset.

Editorul de câmpuri
Delphi oferă un mare grad de control şi flexibilitate asupra câmpurilor unui
DataSet, prin intermediul Editorului de câmpuri.
Cu ajutorul editorului de câmpuri, care poate fi activat din meniul derulant asociat
unui DataSet (de cele mai multe ori tabel) se pot efectua următoarele operaţii:

1.Adăugarea unui câmp nou (prin ştergerea unui câmp existent, păstrarea numelui lui
şi schimbarea tipului).

2.Definirea unui câmp calculat (calculated field).

3.Definirea unui câmp de tip lookup, ale cărui valori se obţin prin relaţionarea tabelei
la care se adaugă câmpul lookup cu o altă tabelă.

Adăugarea unui câmp de tip dată nou


Paşii de parcurs pentru adăugarea unui astfel de câmp sunt:

1.Activare editor câmpuri.

2.Selectare câmpuri DataSet.

3.Ştergerea câmpului al cărui tip dorim să-l modificăm

4.Activare fereastră de dialog new fields din meniul derulant asociat editorului de
câmpuri.

5.Completare nume câmp în caseta de editare Name asociată. Acest nume trebuie

coincidă cu numele câmpului şters.

6.Selectare tip şi, eventual completarea informaţiei de lungime.

7.Activare buton Data în grupul de radio butoane Field Type.

8.OK. în fereastra New fields.

Efectele sunt imediate dacă DataSet-ul este asociat cu o componentă browser

Definirea unui câmp calculat


Cu ajutorul editorului de câmpuri puteţi adăuga câmpuri calculate unui dataset.
Protocolul de adăugare a unui astfel de câmp este următorul:

1.Activare fereastră de dialog New Field.

98
2.Introducerea unui nume pentru câmpul calculat în caseta de editare Name. Se
va evita introducerea unui nume de câmp deja existent în DataSet-ul contextual.

3.Selectare tip din caseta combo box asociată tipului.

4.Introducere informaţie de lungime, dacă este cazul.

5.Activaţi butonul Calculated în grupul de radio butoane Field Type.

6.Selectaţi OK.

Noul câmp este automat adăugat în lista câmpurilor persistente ale editorului de
câmpuri.

7.Adăugaţi codul care calculează valorile pentru câmpul calculat. Acest cod se
asociază evenimentului OnCalcFields al DataSet-ului.
De remarcat, totodată, că pentru a edita proprietăţile sau evenimentele asociate
unui câmp, selectaţi numele câmpului în lista editorului de câmpuri şi, vă puteţi folosi
de inspectorul de obiecte, ca de obicei.

Definirea unui câmp lookup


Adăugarea la lista de câmpuri a unui dataset a unui câmp lookup echivalează cu
adăugarea unui câmp ale cărui valori sunt obţinute prin relaţionare cu un alt dataset.

Lucrul cu câmpuri BLOB


Un câmp BLOB (Binary Large Object) este un câmp capabil să conţină o
cantitate nedeteminată de date. Cel mai adesea, câmpurile BLOB sunt utile pentru
păstrarea unei cantităţi mari de text, imagini grafice sau fluxuri de date, precum
obiectele OLE.
VCL Delphi include un descendent al tipului TField, numit TBlobField, care
încapsulează un câmp BLOB.
TBlobField are o proprietate BlobType de tip TBlobType, care indică ce tip de
dată este păstrat în câmpul BLOB. TBlobType este definit în unit-ul DB astfel:

TBlobType=ftBlob..ftOraClob;

Toate tipurile de câmpuri asociate definiţiei de mai sus sunt:

99
Tip câmp Tipul de dată
ftBlob Dată fără tip sau definită de utilizator
ftMemo Text
ftGraphic Bitmap Windows
ftFmtMemo memo formatat Paradox
ftParadoxOle object OLE Paradox
ftDbase Ole object OLE DBase
ftTypedBinary

Reîmprospătare Dataset
DataSet-ul abstractizează de cele mai multe ori un tabel. În momentul în care un
dataset se cuplează la o tabelă (în urma unei operaţii de tip Open(), DataSet-ul se
comportă ca un flux în care adaugăm înregistrări, din care ştergem înregistrări sau în
care modificăm înregistrări. Din diverse motive, conţinutul DataSet-ului trebuie pus
de acord, din când în când cu conţinutul tabelei asociate.
În acest scop se foloseşte metoda Refresh().

Proprietatea State a unui DataSet


De multe ori este necesar să ştim dacă un tabel este în unul dintre modurile Edit,
Append, Insert, sau chiar dacă este activat. Astfel de informaţii se pot obţine
consultând proprietatea State a DateSet-ului.
Proprietatea State este de tip TDataSetState şi poate avea una din valorile:

dsBrowse Dataset-ul este în mod Browse (normal).


dsCalcFields A fost apelat evenimentul OnCalcFields şi un calcul de valoare
înregistrare este în derulare.
dsEdit DataSet-ul este în Edit mod. Acesta înseamnă că metoda Edit a
fost apelată, dar înregistrarea editată nu a fost încă operată efectiv (ceea ce se
întâmplă la aplicarea metodei Post sau la trecerea la o nouă înregistrare.).
dsInactive DataSet-ul este închis.
dsInsert DataSet-ul este în modul Insert
dsSetKey DataSet-ul este în SetKey mod, ceea ce înseamnă că a fost
apelată
metoda SetKey, dar încă nu s-a făcut un apel de tip GotoKey().
dsNewValue DataSet-ul este într-o stare temporară, caracterizată prin faptul
că este accesată proprietatea NewValue a DataSet-ului.
dsOldValue DataSet-ul este într-o stare temporară, caracterizată prin faptul
că este accesată proprietatea OldValue.
dsCurValue DataSet-ul este într-o stare temporară, ca la dsOldValue
dsFilter DataSet-ul este asociat, în stare curentă, cu procesarea unui
filtru.

100
Filtre
Filtrele permit programatorilor să efectueze căutări sau filtrări asociate cu un
DataSet, utilizând numai cod Object Pascal. Principalul avantaj al utilizării filtrelor
constă în faptul că nu sunt necesare fişiere index sau alte pregătiri ale DataSet-urilor
de acest gen.
Filtrele pot fi mai lente decât căutarea bazată pe indexare, dar sunt încă mult
folosite în o serie de aplicaţii, fie şi numai din motive de simplificare a portării unei
aplicaţii.

Filtrarea unui DataSet


Una dintre cele mai obişnuite utilizări ale mecanismului Delphi de filtrare este de
a limita vizibilitatea DataSet-ului la un număr de înregistrări care îndeplinesc o
anumită condiţie. Această filtrare se obţine, relativ simplu astfel:
1. Asignarea unei proceduri evenimentului OnFilterRecord al DataSet-ului.
Înăuntrul acestei proceduri trebuie scris cod care acceptă înregistrări pe
baza valorilor unuia sau mai multor câmpuri.
2. Setarea proprietăţii Filtered la valoarea True.

Exemplu de procedură asignată evenimentului OnFilterRecord:

procedure TForm1.Table1Filterrecord(DataSet:TDataSet; var


Accept:Boolean);
var
FieldVal:String;
begin
FieldVal:=DataSet[‘Compania’];
Accept:=FieldVal[1]=’S’;
end;

In acest cod s-a definit un filtru care permite prelucrarea doar a înregistrărilor din
tabelă pentru care câmpul ”Compania” începe cu “S”.

Find First / Find Next


TDataSet dispune de metodele FindFirst(), FindNext(), FindPrior() şi
FindLast() care întrebuinţează handlerul evenimentului OnFilterRecord al unui
DataSet pentru a permite poziţionarea pe prima înregistrare, următoarea înregistrare,
precedenta înregistrare, respectiv, ultima înregistrare care îndeplineşte o condiţie
specificată în termeni de filtre.

Poziţionarea pe o înregistrare (Căutarea unei înregistrări)


Filtrele nu sunt folositoare doar pentru a specifica o anumită perspectivă asupra
unui DataSet; ele sunt folosite şi pentru a căuta înregistrări ale unui DataSet utilizând
valori ale unuia sau mai multor câmpuri. Metoda furnizată de DataSet în acest scop
este Locate().
Definiţia metodei este:

101
function Locate(const KeyFields:string; const KeyValue:Variant; Options:
TLocateOptions): boolean;

-KeyFields- indică numele câmpului(câmpurilor) după care se face căutarea;


-KeyValues- indică valoarea(valorile) câmpului(câmpurilor) căutate;
-Options- permite personnalizarea tipului de căutare;

TLocateOptions este un tip set definit în unit-ul DB astfel:

.
.
type
TLocateOption = (loCaseInsensitive, loPartialKey);
TLocateOptions = set of TLocateOption;
.
.

loCaseInsensitive - căutarea nu este sensibilă la case.


loPartialKey - valoarea conţinută în KeyValues este validă chiar şi în calitate
de
subşir al unei valori de tip câmp.

Locate() returnează True dacă a găsit o înregistrare. De exemplu, pentru a găsi


prima apariţie a valorii ‘Corneliu’ în câmpul Nume al tabelei Table1, folosim
sintaxa:
.
.
Table1.Locate(‘Nume’,’Corneliu’,[lopartialKey]);
.

Utilizarea tipului Ttable


Prezentăm, în continuare, proprietăţile şi metodele comune ale tipului TTable şi
modul de utilizare a acestora.

Căutarea înregistrărilor
Dacă aveţi nevoie să căutaţi înregistrări într-un tabel, VCL furnizează câteva
metode de ajutor în acest caz
Dacă lucraţi cu tabele dBase sau Paradox, Delphi presupune că tabelele sunt
indexate după câmpurile implicate în procesul de căutare. În deosebi în cazul
tabelelor SQL, performanţa procesului de căutare va avea de suferit dacă fişierele în
care căutăm nu sunt indexate.
Pentru căutare putem folosi:

tehnica FindKey()
sau
tehnica SetKey()..GotoKey().

102
Metoda FindKey() permite căutarea unei înregistrări după unul sau mai multe
câmpuri cheie. FindKey() acceptă ca parametru un vector de constante (reprezentând
criteriul de căutare) şi returnează True în caz de reuşită a procesului de căutare.
Exemplu:
.
.
if not Table1.FindKey([123,’Ionescu Victor’])
then MessageBeep(0);
.
.
Codul de mai sus determină poziţionarea în DataSet pe înregistrarea pentru care
primul câmp-index are valoarea 123 iar al doilea câmp-index are valoarea ‘Ionescu
Victor’.

SetKey()..GotoKey()
Apelarea metodei SetKey() trece tabelul într-un mod care pregăteşte câmpurile lui
pentru a fi încărcate cu valori reprezentând criterii de căutare. Odată ce criteriul de
căutare a fost stabilit se foloseşte metoda GotoKey() pentrua face o căutare top-down
a unei înregistrări specificate în criteriul de căutare. În varianta SetKey()..GotoKey()
exemplul precedent se scrie:

.
.
with Table1 do
begin
SetKey;
Fields[0].AsInteger:=123;
Fields[1].AsString:=’Ionescu Victor’;
if not GotoKey then MessageBeep(0);
end;
.

7. Câte ceva despre lucrul cu fişiere în DELPHI


Lucrul cu fişiere, directoare şi drive-uri de periferice reprezintă exemple de
probleme de programare invitabile. La fel ca Pascal, Object Pascal oferă suport
pentru lucrul cu 3 tipuri de fişiere: fişiere text, fişiere cu tip şi fişiere fără tip(sau
binare). De semnalat faptul că fişierele text conţin text ASCII.

7.1 Lucrul cu fişiere text


1.Declararea unui fişier text:
.
.
var VfText:TextFile;
.
.

2. Asignarea unei variabile la un fişier text:

103
.
.
AssignFile(VFText,’Fişier.txt’);
.
.

3. Deschiderea unui fişier text:


Rewrite(VFText): Dacă fişierul există, va fi suprascris, dacă nu există,
este
creat
Reset(VFText): Un fişier existent este deschis pentru operaţii de citire.
Append(VFText): Un fişier existent este deschis pentru operaţii de
adăugare.

4. Manipulare fişier text utilizând procedurile predefinite:writeln si readln.

5. Închiderea fişierului:
CloseFile(VFText).

7.2 Lucrul cu fişiere cu tip


1. Declararea tipului record:

.
.
type
.
.
TPersonRecord=packed record
Nume:string[20];
Iniţiala:string[3];
Prenume:string[20];
DataNaşterii:TdateTime;
end;
.
.

2. Declararea tipului fişier:


.
.
Tfile=file of TpersonRecord;

3. Declararea variabilei fişier:


.
.
var
.
.
VFPers:TFile;

104
.
.

4. Utilizarea variabilei fişier ca în exemplele:


.
.
var
IPersRec:TPersonRecord;
VFTip:Tfile;
begin
AssignFile(VFTip,’Persoana.dat’);
Reset(VFTip);
try
if not(Eof(VFTip))
then
read(VFTip, IPersRec);
finally
CloseFile(VFTip);
end;
end;

sau

.
.
var
IPersRec:TPersonRecord;
VFTip:Tfile;
begin
AssignFile(VFTip,’Persoana.dat’);
Reset(VFTip);
Seek(VFTip, FileSize(VFTip));
try
write(VFTip, IPersRec);
finally
CloseFile(VFTip);
end;
end;

7.3 Utilizarea clasei TfileStream


TFileStream este o clasă care poate fi folosită pentru a gestiona articole care nu
sunt obiecte. Este o clasă ale cărei metode pot fi folosite pentru a lucra ca înregistrări
având orice structură.
Protocolul de utilizare a clasei TFileStream presupune:
1. Încapsularea tipului de înregistrare cu care se lucrează şi a descendentului
clasei TFileStream într-un unit.
2. Utilizarea unit-ului definit la 1 pentru a rezolva problema asociată tipului
de înregistrare.

105
Utilizând TFileStream se poate realiza foarte uşor un browser
specializat pe un anumit tip de înregistrare.
De fapt TFileStream abstractizează noţiunea de fişier cu tip în ideea de a
simplifica efortul de programare depus pentru gestionarea datelor păstrate într-un
fişier cu o structură oarecare.
O instanţă a clasei TFileStream este creată cu ajutorul constructorului Create,
care are sintaxa:

constructor Create(const Filename:string; Mode:Word);

Aşadar, la crearea unei instanţe de tip TFile Stream trebuie să specificăm numele
fişierului asociat şi modul de operare asupra acestuia. Consultaţi help-ul Delphi
pentru a vedea valorile posibile pentru parametrul Mode şi semnificaţia acestora. Tot
cu ajutorul help-ului se poate învăţa sintaxa metodelor cu ajutorul cărora se fac citiri,
scrieri poziţionări în fişiere asociate cu o instanţă TFile Stream. Protocolul de lucru
cu instanţe TFileStream poate fi urmărit şi în exemplul de mai jos.

{
Exemplu de cod Object Pascal care ilustreaza utilizarea
tipului TFileStream
}

unit persrec;

interface
uses Classes, dialogs, sysutils;

type

// Defineste inregistare care pastreaza date despre o


persoana.
TPersonRec = packed record
FirstName: String[20];
LastName: String[20];
MI: String[1];
BirthDay: TDateTime;
Age: Integer;
end;

// Creare descendent TFileStream capabil sa lucreze cu


instante TPersonRec

TRecordStream = class(TFileStream)
private
function GetNumRecs: Longint;
function GetCurRec: Longint;
procedure SetCurRec(RecNo: Longint);

106
protected
function GetRecSize: Longint; virtual;
public
function SeekRec(RecNo: Longint; Origin: Word):
Longint;
function WriteRec(const Rec): Longint;
function AppendRec(const Rec): Longint;
function ReadRec(var Rec): Longint;
procedure First;
procedure Last;
procedure NextRec;
procedure PreviousRec;
// NumRecs arata numarul de inregistrari in stream
property NumRecs: Longint read GetNumRecs;
// CurRec arata inregistrarea curenta in stream
property CurRec: Longint read GetCurRec write
SetCurRec;
end;

implementation

function TRecordStream.GetRecSize:Longint;
begin
{ Returneaza lungimea in octeti a unei inregistrari de
tip
TpersonRec din stream}
Result := SizeOf(TPersonRec);
end;

function TRecordStream.GetNumRecs: Longint;


begin
// Returneaza numarul de inregistrari din stream
Result := Size div GetRecSize;
end;

function TRecordStream.GetCurRec: Longint;


begin
Result := (Position div GetRecSize) + 1;
end;

procedure TRecordStream.SetCurRec(RecNo: Longint);


begin
if RecNo > 0 then
Position := (RecNo - 1) * GetRecSize
else
Raise Exception.Create('Cannot go beyond beginning of
file.');
end;

107
function TRecordStream.SeekRec(RecNo: Longint; Origin:
Word):
Longint;
begin
Result := Seek(RecNo * GetRecSize, Origin);
end;

function TRecordStream.WriteRec(Const Rec): Longint;


begin
// Scrierea unei inregistrari in stream
Result := Write(Rec, GetRecSize);
end;

function TRecordStream.AppendRec(Const Rec): Longint;


begin
// Adaugarea unei inregistrari in stream
Seek(0, 2);
Result := Write(Rec, GetRecSize);
end;

function TRecordStream.ReadRec(var Rec): Longint;


begin
{Citirea unei inregistrari din stream si pozitionarea
la
inceputul inregistrarii citite}
Result := Read(Rec, GetRecSize);
Seek(-GetRecSize, 1);
end;

procedure TRecordStream.First;
begin
//Pozitionarea la inceput in stream
Seek(0, 0);
end;

procedure TRecordStream.Last;
begin
// Pozitionarea pe ultima inregistrare din stream
Seek(0, 2);
Seek(-GetRecSize, 1);
end;

procedure TRecordStream.NextRec;
begin
if ((Position + GetRecSize) div GetRecSize) =
GetNumRecs then
raise Exception.Create('Cannot read beyond end of
file')
else

108
Seek(GetRecSize, 1);
end;

procedure TRecordStream.PreviousRec;
begin
if (Position - GetRecSize >= 0) then
Seek(-GetRecSize, 1)
else
Raise Exception.Create('Cannot read beyond beginning
of
the file.');
end;

end.

7.4 Lucrul cu fişiere fără tip


Declararea unei variabile fişier fără tip:

.
.
var VFFărăTip:File;

Deschiderea unui fişier asociat cu o variabilă fişier fără tip:

{Pentru operaţii de citire / scriere în cazul în care fişierul există deja}


.
.
Reset(VFFărăTip,[<RecSize>]);
.
.

sau

{pentru operaţii de citire / scriere atunci când fişierul nu există ; dacă fişierul
există
atunci este vidat la deschidere}

.
Rewrite(VFFărăTip[,<RecSize.]);
.
.

Pentru citirea datelor din fişiere fără tip avem procedura:

procedure BlockRead(var F:File; var Buf;


const: Integer[; var Result:Integer]);

109
Pentru scrierea datelor într-un fişier fără tip avem procedura:

.
.
procedure BlockWrite(var F:File; var Buf;
const:Integer[; var Result:Integer]);
.
.
Dimensiunea implicită a blocului elementar de transfer: 128.

Consultaţi help-ul sau [6] pentru a vedea cum se lucrează profesional cu fişierele,
structurile de tip directoare şi drive-urile în Object Pascal. Consultaţi, de asemenea,
paragraful 4 al acestui suport de curs pentru a afla mai multe despre capabilităţile
Delphi relativ la lucru cu fişiere şi directoare.

Alte precizări relativ la


posibilităţile mediului
Delphi
Evident, puterea mediului Delphi nu se reduce la topicile prezentate în acest
suport de curs. Elementele prezentate fac parte din categoria cunoştinţelor de bază.
Elementele de programare avansată în Delphi întregesc universul preocupărilor unui
programator în Delphi. Topici care intră sub incidenţa sintagmei “programare
avansată” în Delphi sunt:
-Utilizarea multitasking-ului în aplicaţiile Delphi (procese, fire de execuţie,
sincronizare);
-Utilizarea memoriei în aplicaţiile Windows create sub Delphi;
-Aplicaţii grafice;
-Lucrul cu imprimanta;
-Obiecte programabile sub Delphi;
-Aplicaţii INTERNET;
-Aplicaţii multimedia, etc.

Majoritatea acestor topici presupun un studiu temeinic şi din perspectiva


numeroaselor tehnologii Windows care le fundamentează; parţial acest studiu este
realizat la opţionalul de Programare Windows.
Dincolo de acest “parţial” stau nenumăratele cărţi din librării şi biblioteci şi
marele sfetnic din totdeauna al omului: NECESITATEA.

110
Când va fi cazul, important este să ştim de unde să începem demersul de
soluţionare a unei probleme, care necesită mai mult decât ştim la un moment dat
despre un anume univers.

Bibliografie minimală
1. Blaga, A., Ultima provocare Borland Delphi, Editura Promedia Plus, 1998
2. Kovacs, S., Delphi 3.0 Ghid de utilizare, Editura Albastră, 1998
3. Miller, T., Powell, D., ş.a., Ghid de referinţă complet Delphi 3, Editura
Teora, 1998
4. Norton, P., Ghid complet pentru Delphi 2, Editura Teora, 1997
5. Oltean, M., Programarea avansată în Delphi, Editura Albastră, 1999
6. Teixeira, S., Pacheco, X., Delphi 5 Developer’s Guide, SAMS Publishing,
2000

111
Propuneri de teme pentru proiecte la disciplina
Metode evoluate de programare
Tema nr. 1
Să se realizeze o aplicaţie Delphi care asistă învăţarea matematicii de
gimnaziu. Se vor lua în considerare următoarele cerinţe:

• Învăţarea interactivă a teoriei


• Aplicaţii statice şi interactive
• Teste de verificare a cunoştinţelor
• Alte idei sunt negociabile
• Modelarea orientată pe obiecte a soluţiei
• Se va scrie cod de tratare a excepţiilor
• Interfaţa va fi bine structurată funcţional şi confortabilă, din
punctul de vedere al utilizatorului potenţial al aplicaţiei (un
profesor de matematică).

Tema nr. 2
Să se realizeze o aplicaţie Delphi care gestionează fluxurile
informaţionale ale unei familii. Exemple de activităţi ale unei familii care
ar putea prezenta interes din apunct de vedere al analizei informaţionale:
gestiunea veniturilor şi a cheltuielilor, gestiunea împrumuturilor(cărţi,
casete video, etc.), gestiunea mijloacelor fixe (cărţi, casete video, alte
obiecte), planificarea activităţilor zilnice, săptămânale, lunare, etc., date
despre cunoştinţele apropiate sau cu care există relaţii de diferite tipuri,
etc.
Sunt valabile şi pentru această temă cerinţele:

• Modelarea orientată pe obiecte a soluţiei


• Se va scrie cod de tratare a excepţiilor
• Interfaţa va fi bine structurată funcţional şi confortabilă, din
punctul de vedere al utilizatorului potenţial al aplicaţiei (membrul
unei familii).

112
Tema nr. 3
Să se realizeze o aplicaţie Delphi care modelează ideea de dicţionar
explicativ enciclopedic. Aplicaţia trebuie să permită:
• Încărcarea dicţionarului cu date
• Consultarea polivalentă a dicţionarului
În afară de explicaţiile asociate cuvintelor, dicţionarul trebuie să poată
conţine şi obiecte grafice, la care se fac referire din textele explicative
asociate cuvintelor.
Alte idei sunt binevenite.
Sunt valabile şi pentru această temă cerinţele:

• Modelarea orientată pe obiecte a soluţiei


• Se va scrie cod de tratare a excepţiilor
• Interfaţa va fi bine structurată funcţional şi confortabilă, din
punctul de vedere al utilizatorului potenţial al aplicaţiei (membrul
unei familii).

Fiecare proiect va conţine următoarele piese:

1. Enunţul problemei de rezolvat.

2. Specificarea cerintelor faţă de sistemul soft care


urmează să fie realizat.

3. Un inventar al claselor a căror colaborare va furniza


comportamentul specific al aplicaţiei; eventual, relaţiile
dintre aceste clase, în notaţie UML.

4. Descrierea interfeţelor aplicaţiei cu utilizatorul.

5. Codul sursă al aplicaţiei Delphi.

113
Toate aceste „piese” vor fi realizate în format
electronic şi, opţional, listate pe format A4 şi
îndosariate!!

114

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