1.1 Bază de date. Baze de date relaţionale
În sensul cel mai simplu o bază de date este o colecţie de
înregistrări şi fişiere organizate pentru un scop anume [1]. Astfel
o bază de date poate fi considerată: toate numerele de telefon ale
diferitelor cunoştinţe păstrate pe un calculator personal,
totalitatea datelor personale despre studenţii unei universităţi
păstrate pe calculatorul acesteia etc. Documentele procesate care sunt
organizate în ordine alfabetică pot constitui de asemenea într-un
sens mai restrâns o bază de date. Un alt tip de baze de date pot fi
considerate fişierele de tip foaie de calcul organizate după tipul
întrebuinţării.
Bazele de date relaţionale se referă la o colecţie de date,
structurate sub forma mai multor tabele ce poartă numele de relaţii
[2]. Termenul de relaţional provine din faptul că fiecare
înregistrare din baza de date conţine informaţii referitoare la un
singur subiect şi numai la unul. De asemenea datele cuprinse în
categorii de informaţii pot fi manipulate de o singură entitate,
bazată pe valori de date asociate.
În legătură cu bazele de date relaţionale sunt folosiţi mai mulţi
termeni. Astfel o relaţie (relation) –conţine informaţii despre un
singur subiect, cum ar fi clienţii, comenzile, studenţii sau
universităţile [1]. De obicei o relaţie este stocată ca un tabel
dintr-un sistem de gestionare a bazelor de date relaţionale. Termenul
atribut desemnează o informaţie specifică unui subiect [2]. Astfel
un atributele poate fi considerate capetele de tabelă. Rândurile vor
purta numele de tuple. O legătură reprezintă modul cum informaţiile
dintr-o tabelă sunt legate cu cele din altă tabelă.
Diferenţele dintre o relaţie şi un tabel sunt următoarele [2].:
• atributele şi tuplele unei relaţii nu sunt ordonate, în timp ce
într-un tabel există o ordonare atât a coloanelor cât şi a
rândurilor
• două tuple ale unei relaţii nu pot avea valori identice, în timp
ce într-un tabel două sau mai multe rânduri ce ocupă poziţii
diferite în tabel pot conţine valori identice
Un domeniu reprezintă mulţimea valorilor pe care le pot lua
atributele unei relaţii [5]. Astfel fiecare atribut dintr-o bază de
date relaţională este definit pe un anumit domeniu, de unde acesta va
lua valori. Mulţime domeniilor pe care este definită o bază de date
formează vocabularul bazei de date.
1.1.1 Chei primare, chei secundare
O cheie este formată din numărul minim de atribute, astfel alese
încât valorile acestor atribute să fie unice [2]. În consecinţă,
fiecare tuplă a relaţiei este identificată în mod unic de valoarea
cheii respective. Totuşi într-o relaţie pot fi mai multe grupuri de
atribute care identifică în mod unic tuplele relaţiei, deci acestea
reprezintă chei ale relaţiei respective.
În modelul relaţional liniile unui tabel sunt unice. Unicitatea
înregistrărilor poate fi asigurată prin stabilirea unei chei
primare, care este o coloană sau un grup de coloane ale tabelei care
va conţine valori unice în tabelă [3]. Aceste tabele care conţin
valori unice se numesc chei candidat. Una din cheile candidat este
considerată cheie primară, iar cele rămase se numesc chei
alternative.
Valorile cheilor primare sunt utilizate pentru a face corelaţii între
tuplele mai multor relaţii şi pentru a reprezenta legăturile dintre
entităţile bazei de date. Astfel o cheie secundară a unei relaţii
este formată din unul sau mai multe atribute ale căror valori sunt
utilizate ca şi chei primare în alte relaţii [2]. Întotdeauna
valorile atributului cheie secundară trebuie să aparţină aceluiaşi
domeniu ce cel al atributului cheie primară din cealaltă relaţie.
1.1.2 Relaţii
O relaţie exprimă un raport sau o asociere între două sau mai multe
tabele. Între două sau mai multe entităţi pot exista următoarele
tipuri de relaţii:
• relaţii de tipul 1:1 (one-to-one) sunt acele tipuri de relaţii
în care fiecărei linii din prima tabelă îi corespunde cel mult o
linie în cea de-a doua tabelă. Acest tip de relaţii sunt utile
atunci când se doreşte împărţirea tabelei în două sau mai multe
tabele pentru motive de securitate, de performanţă, sau de exemplu,
în cazul sistemului de gestiune a bazelor de date Access datorită
limitei de 255 de coloane pentru o tabelă;
• relaţii de tipul 1:m (one-to-many) sunt relaţiile în care pentru
fiecare linie din prima tabelă există zero, una sau mai multe linii
în cea de-a doua tabelă, dar pentru fiecare linie din cea de-a doua
tabelă există exact o linie în prima tabelă;
• relaţii de tipul m:m (many-to-many) sunt acele tipuri de relaţii
în care pentru fiecare linie din cea de-a doua tabelă pot exista mai
multe linii în cea de-a doua şi, totodată pentru fiecare linie din
cea de-a doua tabelă pot exista mai multe linii în prima.
1.1.3 Teoria normalizării
Teoria normalizării se ocupă cu îmbunătăţirea succesivă a
schemei conceptuale, fiind satisfăcute în acelaşi timp următoarele
condiţii [3]:
• conservarea datelor –în schema conceptuală finală trebuie să
existe toate datele din cadrul schemei iniţiale;
• conservarea dependenţelor dintre date –trebuie să se păstreze
tipurile de relaţii dintre entităţi;
• descompunerea minimală a relaţiilor iniţiale –în schema
conceptuală finală nici o relaţie nu trebuie să fie conţinută
într-alta.
Normalizarea [3] constă astfel într-o serie de teste efectuate asupra
datelor
existente, în scopul de a elimina redundanţa şi de a garanta că
datele sunt asociate cu tabelele sau relaţiile corespunzătoare. În
total există şase astfel de teste, dintre care doar trei sunt mai des
folosite în practică şi anume:
• Prima formă normală: - o tabelă este în prima formă normală
dacă valorile tuturor atributelor care o compun sunt indivizibile şi
în plus nu trebuie să existe atribute sau grupuri de atribute
repetitive [3];
• A doua formă normală: - o tabelă este în a doua formă normală
dacă este în prima formă normală şi fiecare atribut care nu face
parte din cheia primară este dependent de întreaga cheie primară
[3];
• A treia formă normală: -spunem că o tabelă este în a treia
formă normală dacă este în forma normală doi şi toate coloanele
care nu fac parte din cheia primară depind direct de cheia primară
[3];
• A patra formă normală: -elimină redundanţele datorate
relaţiilor de tipul m:m;
• A cincea formă normală: -este mai mult „academică” şi apare
foarte rar în practică;
• Forma normală Boyce-Codd: -o relaţie este în forma Boyce-Codd
dacă fiecare determinant este o cheie candidat (Putem defini
determinantul ca pe un atribut sau o mulţime de atribute neredundante
care constituie un identificator unic pentru un alt atribut sau o altă
mulţime de atribute ale unei relaţii.
1.2 Sisteme de gestiune a bazelor de date
În perioada actuală caracterizată printr-un progres continuu în
toate domeniile vieţii sociale şi economice un rol deosebit de
important îl deţine informaţia. O parte importantă a resurselor
fiecărei entităţi economice sau sociale este orientată astfel spre
acumulare, prelucrarea şi stocarea datelor. Acest proces se
identifică în mod normal cu crearea, întreţinerea şi utilizarea
unei baze de date pe sistemele de calcul moderne.
O bază de date este formată dintr-o colecţie de date diverse şi un
software care să controleze accesul la acestea, software cunoscut sub
numele de sistem de gestiune a bazelor de date (SGBD). Un SGBD
reprezintă astfel [2] un program ce furnizează o interfaţă între
sistemul de operare de pe sistemul de calcul respectiv şi utilizator,
cu scopul de a simplifica pe cât posibil accesul la date.
Un SGBD îndeplineşte următoarele funcţii importante [2]:
• stocarea, regăsirea şi actualizarea datelor (astfel se permite
utilizatorilor să creeze şi să manipuleze date fără a fi necesar
să cunoască structura internă a datelor);
• crearea şi întreţinerea dicţionarului de date;
• gestionarea facilităţilor legate de accesarea simultană a unor
înregistrări ale bazei de date de către mai mulţi utilizatori;
• păstrarea unei copii de siguranţă („back-up”);
• probleme de securitate a datelor (parole de acces ale
utilizatorilor, verificări etc.)
Gestionarea informaţiei sub forma unei baze de date prezintă o serie
de avantaje dintre care amintim [2]:
• Independenţa datelor: Într-o bază de date, datele sunt păstrate
astfel încât schimbarea structurii acestora să nu afecteze nici unul
dintre programele de aplicaţie ce utilizează baza de date
respectivă.
• Consistenţa datelor: Modificarea articolelor din baza de date este
percepută de fiecare dintre utilizatorii sistemului de baze de date.
• Controlul redundanţei: În sistemele de gestiune neorientate spre
baza de date, aceiaşi informaţie poate fi păstrată în mai multe
fişiere diferite şi în consecinţă creşte nejustificat spaţiul
fizic ocupat pe disc, precum şi timpul consumat cu actualizarea
datelor redundante.
• Integritatea datelor: Un SGBD furnizează utilizatorilor
posibilitatea specificării anumitor restricţii. Dacă de exemplu se
adaugă un nou produs în baza de date impunem să fie adăugat şi
preţul acestuia, astfel încât acest câmp nu va putea niciodată fi
omis.
• O mai mare securitate a datelor: Un SGBD va asigura faptul că
doar utilizatorii autorizaţi vor avea acces la date.
• Un control centralizat al datelor prin intermediul unui
administrator al bazei de date.
• O mai mare cantitate de informaţii disponibilă utilizatorilor: Cu
un SGBD utilizatorii accesează informaţia ce a fost păstrată
anterior în sisteme de calcul diferite, chiar incompatibile între
ele.
• Orice SGBD modern furnizează un limbaj de interogare a datelor, de
obicei de tip SQL („Structured Data Language”), ce permit
utilizatorilor să obţină mult mai rapid şi mai simplu informaţiile
dorite, decât dacă utiliza un program scris într-un limbaj
prodedural.
1.2.1 Limbaje de interogare. SQL
Limbajele de interogare pot fi clasificate [2] în două categorii:
a) limbaje algebrice, în care interogările asupra relaţiilor sunt
exprimate prin intermediul unor operatori aplicaţi asupra lor. În
această categorie intră limbajul SQL.
b) Limbaje bazate pe calcul relaţional, în care interogările asupra
relaţiilor sunt exprimate prin intermediul unor condiţii pe care
tuplele relaţiilor trebuie să le satisfacă. Această categorie de
limbaje se clasifică la rândul ei în două categorii în funcţie de
obiectul asupra căruia se aplică operaţia şi anume:
b1) limbaje bazate pe calcul relaţional orientat pe tuple, în
care predicatele se implică asupra tuplelor relaţiilor, reprezentativ
fiind aici QUEL, limbajul de interogare Ingres;
b2) limbaje bazate pe calcul relaţional orientat pe domenii, în
care predicatele domeniului din care ia valori atributul relaţiei.
Reprezentativ pentru aceste categorie este QBE, limbajul de interogare
dezvoltat de IBM.
Pentru reprezentarea structurii logice a datelor dintr-o bază de date
există trei modele şi anume: modelul ierarhizat , care presupune
crearea unei structuri arborescente de reprezentarea a datelor, modelul
reţea, în care elementele ce reprezintă datele sunt legate între
ele prin pointeri, formându-se astfel o reţea, şi modelul
relaţional, acesta din urmă impunându-se net în faţa celorlalte
două, fiind la ora actuală la baza realizării majorităţii
produselor.
În esenţă o bază de date relaţională poate fi gândită ca şi o
colecţie de tabele bidimensionale ce se numesc relaţii, coloanele
(atributele relaţiei) au nume distincte, iar rândurile (tuple)
conţin elemente ale datelor ce poartă numele de entităţi.
Organizarea datelor sub forma mai multor tabele poartă numele de
schema reprezentării datelor. O schemă nu specifică doar care sunt
coloanele ce intră în componenţa fiecărui tabel, ci va stabili de
asemenea legătura logică dintre entităţile stocate în baza de
date.
Limbajul standard care a fost conceput ca un limbaj de descriere a
datelor şi acces la informaţiile din bazele de date relaţionale este
SQL. El a fost iniţial utilizat de către firma IBM pentru produsul
DB2, devenind la mijlocul deceniului trecut un standard de facto în
domeniu. De atunci şi până în prezent au fost dezvoltate un număr
de şapte versiuni ale standardului SQL, trei dintre acestea
aparţinând Institutului American de Standarde (ANSI), celelalte fiind
concepute de firme de prestigiu ca IBM, Microsoft şi Borland, sau de
către consorţiile industriale SAG („The SQL Access Group”) şi
X/Open, primul format din sute de firme ce comercializează software
pentru baze de date, iar cel din orientat spre activităţi de
promovare a standardelor în domeniul sistemelor deschise.
1.3 Modelul relaţional
1.3.1. Scurtă descriere a modelului relaţional
Modelul relaţional a fost formulat şi publicat pentru prima oară la
începutul anilor ’70 de către dr. Edgar F. Codd, cercetător la
laboratoarele IBM din San Jose (California), care a publicat între
anii 1970-1974 lucrările sale referitoare la modelul relaţional
pentru bazele de date. Acest model relaţional, are avantajul că
permite proiectantului bazei de date să studieze proprietăţile
sistemului de gestiune a bazelor de date fără a fi necesar să-l
implementeze.
Una din caracteristicile de bază ale modelului relaţional este
simplitatea sa şi rigurozitatea sa din punct de vedere matematic, fapt
care l-a impus în faţa celorlalte modele, fiind adoptat în ultimul
deceniu de majoritatea cercetătorilor şi programatorilor din domeniu.
Datele şi relaţiile sunt reprezentate sunt reprezentare explicit,
utilizând o structură logică ce poartă numele de relaţie. Pe de
altă parte, modelul relaţional a fost definit cu o deosebită rigoare
matematică, furnizând un mijloc performant de studiu al
proprietăţilor logice ale unui sistem de baze de date.
Spre deosebire de modelul relaţional, celelalte modele impuse
anterior, modelul ierarhizat şi modelul reţea, nu au beneficiat de un
fundament teoretic atât de solid. O altă deosebire esenţială între
modelul relaţional şi celelalte două modele este aceea că în timp
ce primul este orientat spre mulţimi, celelalte două sunt orientate
spre fişiere; aceasta rezidă din faptul că, dacă pentru modelul
ierarhizat şi modelul reţea, programatorul trebuie să proiecteze
programe procedurale, care să acceseze baza de date înregistrare cu
înregistrare utilizând legături fizice pentru înregistrări, pentru
modelul relaţional, o singură instrucţiune de limbaj neprocedural
(cum este SQL), determină de obicei prelucrarea mai multor
înregistrări.
O altă proprietate specifică modelului relaţional este aceea că
nefiind orientat spre sistemul de calcul, se pot adresa doar
proprietăţile logice ale sistemului de baze de date, nu şi cele
fizice. Drept urmare, modelul nu include regulile, structurile şi
operaţiile referitoare la implementarea fizică a unui sistem de baze
de date. De astfel unul din obiectivele modelului relaţional a fost
acela de a introduce o distincţie clară între aspectele fizice şi
cele logice ale unei baze de date, obiectiv numit de E.F. Codd
„independenţa datelor”.
La începutul fundamentării teoretice a modelului relaţional, au
existat temeri serioase privind eficienţa aplicării modelului
relaţional pentru baze de date de dimensiuni mari. Dezvoltarea
tehnologică fără precedent în domeniul electronicii şi
informaticii din ultimii ani, concretizată în creşterea puterii de
prelucrare a calculatoarelor a condus la eliminarea acestor temeri prin
larga utilizare a sistemelor de baze de date relaţionale inclusiv pe
calculatoarele personale.
1.3.2 Reguli de fidelitate ale bazelor de date
Pe la mijlocul anilor ’80 matematicianul Edgar F. Codd a publicat un
set de reguli în raport cu care un sistem de gestiune a bazelor de
date (SGBD) poate fi apreciat ca fiind „relaţional”. Aceste reguli
sunt denumite „Cele 13 reguli de fidelitate ale lui Codd”. Ulterior
Codd a extins numărul acestora, de la 13 reguli publicate în anul
1986, la un număr de 100 în 1990. Totuşi nici un sistem de gestiune
a bazelor de date pus în vânzare pe piaţa comercială nu respectă
absolut toate regulile definite de Codd, ci doar un număr mai mic sau
mai mare al lor. Spre exemplu, produsul IBM DB2 respectă un număr de
7 reguli din cele 13.
Astfel cele 13 reguli de fidelitate ale lui Codd sunt[2] următoarele:
Regula 0: (Regula de bază)
Pentru a fi relaţional, un SGBD trebuie să fie capabil să gestioneze
o bază de date prin intermediul caracteristicilor sale relaţionale.
Astfel un SGBD trebuie să cuprindă trei părţi: o parte de definire
a datelor (DDL), o parte de manipulare a datelor (DML) şi o altă
parte de integritate şi control a datelor (DCL)
Regula 1: (Regula reprezentării informaţiei)
Într-o bază de date relaţională, informaţia este reprezentată la
nivel logic într-un singur fel, şi anume sub forma unor tabele.
Datele sunt stocate sub forma unor structuri tabelare, formate din
rânduri denumite tuple şi coloane denumite atribute. Aceste structuri
sub formă de tabele, oferă o serie de avantaje şi anume: claritate,
generalitate (majoritatea tipurilor de date pot fi reprezentate sub
această formă) şi flexibilitate (această structură poate fi
modificată atât pe rânduri cât şi pe coloane).
Regula 2: (Regula accesului garantat la date)
Fiecare dată dintr-o bază de date relaţională trebuie să poată fi
adresată în mod logic printr-o combinaţie formată din numele
relaţiei în care se află, valoarea cheii primare şi numele
atributului.
Se poate regăsi orice valoarea aparţinând oricărui atribut al unei
relaţii, dacă sunt specificate: numele relaţiei, numele tuplei (prin
utilizarea cheii primare) şi numele atributului.
Regula 3: (Regula reprezentării informaţiei necunoscute)
Un SGBD în totalitate relaţional trebuie să poată permite
utilizatorului definirea unui tip de date denumit „NULL” pentru
reprezentarea unei informaţii necunoscute la momentul respectiv şi
aceasta într-un mod sistematic pentru orice tip de date.
Într-un SGBD relaţional trebuie să se poată face diferenţierea
între o valoare fixată intenţionat pe 0, un şir vid de caractere
şi o valoare necunoscută.
Regula 4: (regula dicţionarului de date)
Asupra descrierii bazelor de date trebuie să se poată aplica
aceleaşi operaţii ca cele asupra datelor din baza de date.
Toate informaţiile referitoare la relaţii, vizualizări, indexi etc.
, trebuie să poată fi stocate sub forma unor relaţii ce formează un
catalog de sistem (dicţionar), şi prin urmare să poată fi accesate
în acelaşi mod ca şi datele propriu-zise prin intermediul aceloraşi
comenzi.
Regula 5: (Regula limbajului de interogare)
Un SGBD relaţional trebuie să poată permite utilizarea a cel puţin
unui limbaj, care să prezinte următoarele caracteristici: să
permită definirea datelor, definirea vizualizărilor, manipularea
datelor, restricţii de autorizare, realizarea tranzacţiilor
(operaţiile COMMIT şi ROLLBACK).
Această regulă precizează că manipularea datelor dintr-o bază de
date trebuie să se facă printr-un limbaj de nivel înalt (de exemplu
SQL), limbaj care permite utilizatorilor să definească relaţii şi
vizualizări, să regăsească informaţia şi să o poată actualiza.
De asemenea limbajul mai permite verificarea şi corectarea datelor de
intrare, precum şi restrângerea accesului la relaţii şi
vizualizări prin intermediul parolelor de acces. El trebuie să
păstreze integritatea bazelor de date prin gestiunea tranzacţiilor .
Regula 6: (Regula de actualizare a vizualizării)
Un SGBD trebuie să poată determina dacă o vizualizare poate fi
actualizată şi să stocheze rezultatul interogării într-un
dicţionar de tipul unui catalog sistem.
Unele vizualizări pot fi actualizate, altele nu, în funcţie de
variantele instrucţiunii SELECT utilizate, pe baza cărora sunt
construite. Prin urmare, un SGBD trebuie să determine acest lucru
printr-un anumit mecanism.
Regula 7: (Regula limbajului de nivel înalt)
Regulile de manipulare asupra unei relaţii luată ca întreg, sunt
valabile atât pentru operaţiile de regăsire a datelor, cât şi
asupra operaţiilor de inserare, actualizare şi ştergere a datelor.
Operaţiile de manipulare a datelor (selecţia, actualizarea,
inserţia, ştergerea) se aplică asupra oricărei părţi dintr-o
relaţie, plecând de la întreaga relaţie şi sfârşind cu o tuplă
sau nici una. Astfel un SGBD relaţional, nu trebuie să oblige
utilizatorul să caute într-o relaţie tuplă de tuplă pentru a
regăsi informaţia dorită.
Regula 8: (Regula independenţei fizice a datelor)
Într-un SGBD relaţional trebuie să se separeu aspectul fizic al
datelor (metoda de stocare sau metoda de acces la date) de aspectul
logic, şi anume programele de aplicaţie.
Orice modificare în modul de stocare al datelor nu trebuie să
afecteze în nici un fel programele de aplicaţie, utilizatorilor
fiindu-le transparente asemenea operaţii.
Regula 9: (Regula independenţei logice a datelor)
Programele de aplicaţie trebuie să fie transparente la modificările
de orice tip efectuate asupra datelor.
Orice modificare asupra unei relaţii nu trebuie să afecteze
operaţiile de manipulare a datelor. Totuşi pot apărea modificări
ale acestor operaţii, dacă se şterg relaţii, vizualizări sau
atribute.
Regula 10: (Regula independenţei datelor din punct de vedere al
integrităţii)
Un SGBD relaţional trebuie să permită atât definirea unor
restricţii de integritate asupra bazelor de date prin intermediul
limbajului, cât şi stocarea lor în dicţionare de tipul cataloagelor
sistem.
Un SGBD relaţional trebuie să permită operaţii de validare a
datelor (restricţii de integritate), utilizând de exemplu limbajul
SQL, gestiunea acestor operaţii trebuie să poată fi făcută prin
stocarea lor în dicţionarul de date şi nu prin scrierea de programe.
Regula 11: (Regula independenţei datelor din punct de vedere al
distribuirii)
Distribuirea datelor pe mai multe calculatoare dintr-o reţea de
comunicaţii de date, nu trebuie să afecteze programele de aplicaţi.
Această regulă reprezintă o extensie a regulii 8, deoarece în
acelaşi mod cum utilizatorii trebuie să fie transparenţi faţă de
unitatea de disc pe care se află stocate relaţiile, în acelaşi mod
ei trebuie să fie transparenţi şi faţă de calculatorul pe care se
află aceste relaţii.
Regula 12: (Regula versiunii procedurale a SGBD)
Orice componentă procedurală a unui SGBD trebuie să respecte
aceleaşi restricţii de integritate ca şi componenta relaţională.
De exemplu, dacă în partea de manipulare a datelor a limbajului
relaţional (DML), data dintr-o coloană este de tipul NOT NULL, orice
altă metodă procedurală de accesare a acestei coloane nu trebuie să
permită introducerea unei valori NULL în această coloană.
Bibliografie
1. Eduard Koller, Monica Roşculeţ - Programare în Acces 97, Editura
TEORA, Bucureşti 1999
2. Corina Pascu, Adrian Pascu -Totul despre… SQL, Editura
Tehnica,
Bucuresti 1994
3. John L. Viescas -Totul despre Microsoft
Access. Editura
Teora Bucuresti 1999
CAP:2. Baze de date, tabele şi relaţii
Încă de la varianta 95, Access vă pune la dispoziţie experţi care
pot crea pentru dumneavoastră toate tabelele, formularele şi
rapoartele unei baze de date pe care o veţi specifica. De asemenea,
Access vă pune la dispoziţie un număr de baze de date predefinite,
din domenii variind de la administrarea unei biblioteci, fonoteci sau
videoteci, până la contacte de afaceri, informaţii despre companii,
servicii, etc. Deşi aceşti experţi vă pot uşura considerabil
munca, scopul nostru este să vă arătăm cum să creaţi propria
bază de date, pornind de la zero.
2.1 Crearea unei baze de date
La pornire, Access vă prezintă o cutie de dialog care vă permite
să optaţi între a deschide o bază de date existentă şi a crea una
nouă. Pentru a crea manual o bază de date, selectaţi Blank Database
şi apăsaţi butonul OK.
Altfel, dacă doriţi să creaţi o bază de date nouă în timp ce
lucraţi cu Access, alegeţi comanda File/New Database sau apăsaţi
butonul New Database de pe bara cu instrumente şi apoi alegeţi Blank
Database din pagina General a cutiei de dialog New.
Fig. 2.1. Fereastra de deschidere din Access
Să creeăm împreună baze de date Cursuri opţionale. Specificaţi
în câmpul File Name al cutiei de dialog File New Database numele
Cursuri Opţionale şi alegeţi din lista Save In directorul în care
doriţi ca Access să salveze noul fişier (aveţi grijă ca tipul
fişierului să fie Microsoft Access Database (*.mdb)).
Fig. 2.2. Tastaţi “Cursuri optionale” în loc de db1 pentru a
denumi baza de date
2.2. Crearea tabelelor
În acest moment, baza de date nu conţine nici o tabelă (dacă aţi
fi folosit un expert pentru a crea baza de date, acesta ar fi creat şi
tabelele, şi chiar ar fi stocat în ele informaţie)
„Atelierul” pe care Access vi-l pune la dispoziţie este fereastra
Database, care se deschide imediat după ce aţi creat o bază de date
nouă, sau aţi deschis una deja existentă. Aceasta conţine pagini
pentru diferitele tipuri de obiecte care pot alcătui o bază de date
Access: tabele, interogări, rapoarte, formulare şi module. Pe
parcursul acestui capitol ne vom concentra atenţia asupra paginii
Tables a ferestrei Database.
Access vă oferă mai multe posibilităţi de a crea o tabelă nouă,
după cum se poate observa şi din figura:
Fig. 2.3. Pagina Tables
- Datasheet View: vă permite să creaţi o tabelă pe baza datelor
stocate în ea (pentru Acces 97);
- Design View: vă ajută să definiţi structura tabelei, specificând
coloanele care o compun şi proprietăţile acestora;
- Table Wizard: este un expert care creează pentru dumneavoastră o
tabelă pe baza unor structuri predefinite;
2.2.1 Crearea manuală a tabelelor
Pentru a crea manual o tabelă, puteţi folosi fie modul Datasheet
View, fie modul Design View.
Modul Datasheet View vă ajută să creaţi tabele simple, prin simpla
introducere a datelor în tabel. Access determină apoi, pe baza cestor
date, tipurile şi formatele coloanelor. De asemenea, Access poate crea
şi o cheie primară. Cu toate acestea, Datasheet View nu vă va
permite să intraţi în detalii cum ar fi stabilirea proprietăţilor
tabelei sau ale coloanelor. Pentru acestea, folosiţi modul Design
View, care vă va oferi control asupra tuturor proprietăţilor
disponibile ale tabelei şi ale coloanelor care o compun, inclusiv
reguli de validare şi valori implicite.
2.2.2 Datasheet View: avantaje
• crearea tabelei
• umplerea ei cu date
În ciuda acestor avantaje, trebuie să ţinem cont de faptul că în
majoritatea cazurilor, bazele de date nu sunt create doar pentru a
stoca informaţiile existente, ci pentru a oferi un mecanism pentru
introducerea ulterioară a datelor şi pentru lucrul cu acestea. După
cum puteţi observa din figură, folosirea modului Datasheet View se
aseamănă cu lucrul cu Microsoft Excel: fiecare linie reprezintă o
înregistrare în tabelă
Pentru a crea o tabelă nouă în modul Datasheet View (97), procedaţi
în felul următor:
1. În fereastra Database, apăsaţi butonul New. Va apărea fereastra
New Table.
2. Din lista prezentată în fereastra New Table, alegeţi Datasheet
View şi apăsaţi butonul OK.
Acum, pe ecran a apărut o fereastră conţinând o tabelă fără
date, dar cu 20 de coloane şi 30 de linii (dacă doriţi, puteţi
adăuga mai multe). În partea de sus a fiecărei coloane se află un
selector ce conţine numele coloanei respective. Făcând clic cu
butonul din stânga al mouse-ului pe acest selector, puteţi selecta
coloana. Iniţial, aceste nume sunt Field1, Field2 etc. dar, ulterior,
le vom schimba în aşa fel încât să reflecte atributele
entităţii descrise de tabelă. Pentru a redenumi o coloană, puteţi
proceda în unul din următoarele trei moduri:
1. Faceţi dublu-clic pe selectorul coloanei, care se va schimba
într-un câmp de editare. Introduceţi noul nume.
2. Selectaţi coloana, alegeţi comanda Format | Rename column şi
editaţi numele.
3. faceţi clic dreapta pe selectorul coloanei. Din meniul context,
selectaţi comanda Rename Column şi editaţi numele.
Notă: deşi Access vă permite includerea de spaţii în numele
coloanelor, încercaţi, pe cât posibil, să evitaţi acest lucru.
Unele sisteme de baze de date (cum ar fi dBase) nu permit folosirea
spaţiilor în numele coloanelor. Deci, dacă aveţi de gând să
legaţi o tabelă dintr-un astfel de DBMS (Data Base Management System
– Sistem de gestionare a bazelor de date) la baza dumneavoastră de
date, nu folosiţi spaţii.
Fig. 2.4. Tabela “Curs_Student
Notă: Access consideră că un câmp gol, care nu conţine date, are o
valoare specială, numită null. Astfel, regăsirea ulterioară a
înregistrărilor pentru care un câmp nu conţine date va fi foarte
uşoară, comparând valoarea lui cu null.
2.2.3 Design View:
Spre deosebire de modul Datasheet View, modul Design View nu vă
permite introducerea de date în tabelă. Cu toate acestea, el este
indispensabil datorită posibilităţilor pe care vi le oferă.
Fig. 2.5. Modul Design View
Pentru a crea o tabelă în modul Table Design View, procedaţi în
felul următor:
1. apăsaţi butonul Tables.
2. Selectaţi din listă opţiunea Create table using Design View .
Va apărea o fereastră ce nu conţine informaţie. Aici se pot defini
coloanele (numite şi câmpuri) ce compun tabela, precum şi
proprietăţile acestora. După cum se poate observa din figură,
fereastra este împărţită în două părţi. Partea de sus
foloseşte la definirea coloanelor, iar partea de jos la stabilirea
proprietăţilor fiecărei coloane în parte şi conţinutul ei se
schimbă în funcţie de tipul pe care l-aţi atribuit coloanei.
2.2.4 Definirea coloanelor
După cum s-a observat, pentru a defini coloanele, se foloseşte
partea de sus a ferestrei Table Design. Pentru a defini prima coloană,
introduceţi numele acesteia în prima linie a coloanei Field Name.
Treceţi apoi în coloana Data Type pentru a alege tipul pe care
doriţi să-l atribuiţi noii coloand. Access vă pune la dispoziţie
un număr de tipuri de date predefinite, despre care vom vorbi în cele
ce urmează:
• Text: şir de caractere (maximum 255), pentru stocarea datelor
alfanumerice. Folosit şi pentru numerele ce nu vor fi folosite la
calcule (de exemplu, numere de telefon).
• Memo: folosit pentru stocarea textelor lungi, de până la 65.535
de caractere.
• Number: folosit pentru stocarea datelor numerice de tipul: întreg,
întreg lung, în virgulă mobilă, cu precizie simplă sau dublă.
• Date/Time: folosit pentru stocarea datei şi a orei.
• Currency: un tip numeric special, folosit pentru valori monetare,
deoarece nu permite rotunjirile de calcul.
• Autonumber: un tip numeric special care poate fi folosit pentru
cheile primare. Coloanele de acest tip sunt de tip read-only (doar
citire), Access introducând automat ori valori consecutive, ori valori
aleatoare la crearea unor înregistrări noi.
• Yes/No: folosit pt stocarea datelor booleene.
• OLE Object: folosit pentru a stoca text sau o combinaţie de text
şi date numerice, folosite ca adresă de hiperlegătură ce poate
conţine trei părţi separate prin semnul #: textul afişat într-un
control sau câmp, adresa (calea către un fişier (UNC) sau către o
pagină (URL)) şi o subadresă (o locaţie din cadrul fişierului sau
paginii).
• Lookup Wizard: vă dă posibilitatea să definiţi un câmp în
care utilizatorul să poată selecta o valoare din altă tabelă sau
dintr-o listă predefinită. (vom reveni asupra acestei probleme)
După ce s-a ales tipul coloanei care se doreşte să o creaţi,
puteţi introduce o scurtă descriere a acesteia în coloana
Description. Deşi acest lucru este opţional, este bine să profitaţi
de el, pentru ca tabela să fie uşor de întreţinut.
2.2.5 Stabilirea proprietăţilor câmpurilor
În această secţiune vom descrie diferitele proprietăţi pe care le
poate acea un câmp (coloană) şi care pot fi stabilite folosind
partea de jos a ferestrei Table design. Setul de proprietăţi pe care
îl aveţi la dispoziţie variază în funcţie de tipul de date ales
pentru coloana respectivă. Multe dintre proprietăţile de bază sunt
comune tuturor tipurior de date. În afară de proprietăţile booleene
(Required, Allow Zero Length şi Indexed), singurele proprietăţi pe
care trebuie să le specificaţi sunt Field Size (pentru tipurile de
date Text, Number şi Autonumber) şi New Values (pentru Autonumber).
Toate celelalte proprietăţi sunt opţionale. În continuare, vom
vorbi mai pe larg despre proprietăţi.
• Field Size: specifică lungimea şirului de caractere sau tipul
numeric al datelor stocate în acest câmp.
• Format: specifică formatul în care vor fi afişate datele.
Puteţi alege un format predefinit sau puteţi crea dumneavoastră
unul. Nu afectează modul de stocare a datelor.
• Decimal Places: Specifică numărul de cifre de după virgulă.
Valoarea Auto arată faptul că numărul de zecimale este dat de
proprietatea Format.
• Input Mask: controlează formatul în care trebuie introduse datele
în câmp. Definiţi acest format apăsând butonul...
• Caption: specifică denumirea sub care va apărea coloana în
formulare şi rapoarte. Dacă nu o completaţi, Access va folosi numele
coloanei.
• Default Value: valoarea atribuită din oficiu câmpului la
inserarea unei noi înregistrări.
• Validation Rule: expresie (regulă de validare) ce limitează
valorile ce pot fi introduse în câmp.
• Validation Text: textul afişat dacă datele introduse în câmp nu
respectă regula de validare.
• Required: arată dacă un câmp poate conţine valoarea null
• Allow Zero Length: arată dacă în câmpurile de tip Text sau Memo
pot fi introduse şiruri de caractere de lincime zero. Această
proprietate este independentă de proprietatea Required. Dacă ea are
valoarea Yes, un şir de lungime zero este o valoare validă pentru un
câmp, indiferent de valoarea proprietăţii Required.
• Indexed: arată dacă un câmp este indexat sau nu. Valoarea Yes
(No Duplicates) arată faptul că un câmp poate fi indexat, iar
valorile stocate în el trebuie să fie unice. Valoarea Zes (Duplicates
Allowed) înseamnă faptul că un câmp este indexat, iar valorile sale
trebuie să fie unice. Valoarea No arată faptul că un câmp nu este
indexat. Despre indecşi şi coloane indexate vom vorbi mai pe larg în
acest capitol.
• New Values: este o proprietate specifică tipului de date
Autonumber şi indică modul în care Access generează numerele ce vor
fi stocate în câmp: crescător (Increment) sau aleator (Random).
Aceste proprietăţi le găsiţi în pagina General din partea de jos a
ferestrei Table Design. Cea de-a doua pagină este Lookup şi, pentru
unele tipuri de date (Text, Number, Yes/No), ea vă permite să
alegeţi tipul de control folosit pentru introducerea datelor în
câmp. Figura reprezintă pagina Lookup pentru un câmp de tip text.
Fig. 2.6. Pagina “Lookup” pentru un cîmp de tip text
Prima proprietate din pagine Lookup este Display Control şi ea
specifică modul în care vor fi afişate datele. În funcţie de
valoarea sa, sunt disponibile sau nu şi alte proprietăţi. Dacă la
tipul coloanei aţi ales Lookup Wizard, valoarea pentru Display Control
va fi stabilită automat. Pentru coloane de tip Text sau Number,
valorile disponibile pentru Display Control sunt Text Box, Combo Box
sau List Box, iar pentru coloane de tip Yes/No, puteţi alege Text Box,
Combo Box sau Check Box.
Dacă aţi optat pentru Text Box, nu mai sunt alte proprietăţi de
stabilit. Valorile Text Box sau Combo Box vă dau posibilitatea să
specificaţi liste din care utilizatorul să selecteze datele ce
trebuie introduse în câmp. Aceste date pot proveni din liste
predefinite sau din alte tabele. Asupra acestei probleme vom reveni
ulterior în acest capitol.
Cel mai simplu mod de a folosi proprietăţile din pagina Lookup este
cu ajutorul expertului Lookup Wizard, despre care vom vorbi în
secţiunea următoare.
2.2.6 Lookup wizard
Expertul Lookup Wizard este folosit pentru a defini modul în care pot
fi regăsite şi afişate valorile ce pot fi introduse într-un câmp.
După cum am mai spus, aceste valori pot proveni din alte tabele,
dintr-o interogare sau dintr-o listă specificată de dumneavoastră.
Pentru a înţelege mai bine mecanismul şi utilitatea expertului
Lookup Wizard, vă propunem să creăm împreună, în modul Table
Design View, tabela Curs_Student, despre care am mai vorbit. Pentru
aceasta este necesar ca dumneavoastră să fi creat în prealabil
tabelele Curs şi Student. Pentru a putea fi stabilite ralaţiile. Vom
folosi Lookup Wizard pentru a regăsi denumirile cursurilor opţionale
disponibile şi a-i oferi utilizatorului posibilitatea de a alege un
curs dintr-o listă.
Notă: dacă tabela Curs este deschisă în modul Datasheet View sau
Design View, închideţi-o, pentru ca Lookup Wizard să îşi poată
finaliza acţiunile.
După ce aţi creat coloanele NrMatricol şi Nota (vezi figura 2.6) ,
urmaţi paşii următori pentru a crea coloana IdCurs:
1. în câmpul Field Name: Introduceţi numele coloanei, IdCurs.
2. în câmpul Datatype: alegeţi Lookup Wizard.
3. în prima cutie de dialog a expertului alegeţi prima opţiune, prin
care specificaţi că doriţi ca datele să fie luate dintr-o tabelă
sau interogare. Apăsaţi butonul Next.
4. în cea de-a doua cutie de dialog, selectaţi din listă tabela Curs
şi apăsaţi Next
5. în cea de-a treia cutie de dialog specificaţi din care coloane ale
tabelei Curs doriţi să fie luate datele. Selectaţi coloana Denumire
şi apăsaţi Next.
6. cea de-a patra cutie de dialog vă permite să ajustaţi lăţimea
coloanelor selectate. De asemenea, în căsuţa de validare Hyde key
column, specificaţi dacă doriţi să apară şi coloana care face
legătura între cele două tabele (IdCurs). Cum nu dorim acest lucru,
lăsaţi căsuţa validată şi apăsaţi Next.
7. în ultima cutie de dialog introduceţi numele pe care doriţi să-l
aibă noua coloană în modul Datasheet View sau în formulare
(„Curs”). Apăsaţi butonul Finish.
8. Lookup Wizard va salva tabela cu noile modificări şi va stabili
relaţia între tabela Curs şi Curs_Student (care este de tipul 1:m).
9. observaţi în fereastra Table Design noile valori ale
proprietăţilor din pagina Lookup (vezi figura). Proprietatea Caption
din pagina general are acum valoarea Curs.
Fig. 2.7. Utilitarul “Lookup Wizard”
Pentru a vedea rezultatele acestor acţiuni, treceţi în modul Table
Datasheet View. Selectaţi coloana Curs şi apăsaţi butonul din
parteadreaptă a câmpului. Va apărea o listă a tuturor cursurilor
din tabela Curs (fig. 2.8). dacă selectaţi un nume din listă, acesta
va fi afişat în câmp. Deşi ceea ce vedeţi este denumirea cursului,
în tabela Curs_Student este stocat doar IdCurs, astfel încât
regulile de integritate referenţială să poată fi păstrate. Astfel,
în cazul în care denumirea unui curs în tabela Curs se modifică,
această modificare să se reflecte şi în tabela Curs_Student, fără
ca ea să trebuiască să fie făcută manual.
Fig. 2.8. Creearea tabelei Curs_Student
În continuare, vom descrie procedeul prin care valorile stocate în
câmpul Curs al tabelei Curs_Student să poată fi selectate dintr-o
listă definită de dumneavoastră.
1. în modul Table Design, alegeţi pentru coloana Curs: tipul Lookup
Wizard, ca mai înainte.
2. în prima cutie de dialog a lui Lookup Wizard alegeţi cea de-a doua
opţiune, prin care specificaţi faptul că veţi introduce
dumneavoastră valorile dorite. Apăsaţi butonul Next.
3. cea de-a doua cutie de dialog vă permite să specificaţi numărul
de coloane ce vor fi afişate şi valorile lor. În câmpul Number of
Columns, introduceţi cifra 2. În partea de jos a cutiei de dialog,
vor apărea două coloane, în care introduceţi, de exemplu, datele
din tabelul următor. Apoi, apăsaţi Next.
Col. 1 Col.2
1 Programare
2 Engleză
3 Franceză
4 Germană
4. în cea de-a treia cutie de dialog, specificaţi care dintre cele
două coloane va avea datele stocate în tabela Curs_Student. Alegem
Col1, datele din Col2 vor fi doar afişate, ajutând utilizatorul la
alegerea lor. Astfel, datele stocate în tabelă vor ocupa mai puţin
spaţiu. Apăsaţi butonul Next.
5. dialogul final vă cere să introduceţi denumirea coloanei. Aceasta
este Curs. Apăsaţi butonul Finish.
Acum, în pagina Lookup a ferestrei Table Design, puteţi modifica
unele proprietăţi, cum ar fi lăţimea coloanelor (Column Widths) sau
puteţi specifica dacă utilizatorul poate introduce în câmpul Curs
Numai valori din listă sau şi alte valori (prin proprietatea Limit to
List).
2.2.7 Value List
Puteţi beneficia de facilităţile coloanelor de tip Lookup (de
căutare) şi fără a apela la Lookup Wizard (deşi aceasta este cea
mai comodă cale). De exemplu, pentru a specifica o listă de valori
aveţi grijă ca, în funcţie de tipul valorilor ce vor fi stocate în
tabelă, să alegeîi în câmpul Data Type tipul Text, Number sau
Yes/No. În cazul exemplului nostru, tipul este Number (dacă aţi fi
dorit să stocaţi în tabelă denumirile, ar fi trebuit să alegeţi
tipul Text). Apoi, în pagina Lookup, pentru proprietatea Display
Control stabiliţi valoarea Combo Box sau List Box, iar pentru
proprietatea Row Source Type, alegeţi valoarea Value List. În câmpul
proprietăţii Row Source introduceţi valorile din tabel, parcurse pe
linii, sub formă de listă, separate prin punct şi virgulă, ca în
figura. (datele de tip text este bine să le introduceţi între
ghilimele).
Fig. 2.9. Alcatuirea unei liste derulante
Dacă doriţi ca valorile pentru coloana de căutare să fie luată
dintr-o tabelă, va trebui să folosiţi Query Builder, un alt
instrument util pus la dispoziţie de Access, ce vă va permite să
specificaţi coloanele din care să fie luate datele prin intermediul
unei interogări. Despre interogări şi Query Builder vom vorbi în
capitolele următoare.
2.2.8 Definirea cheilor primare şi a indecşilor
Un index reprezintă o cale rapidă de localizare şi sortare a
înregistrărilor dintr-o tabelă prin gruparea tuturor
înregistrărilor pentru un anumit atribut sau grup de atribute.
Indexarea este utilizată în două scopuri principale:acce¬lerarea
căutărilor în baza de date şi asigurarea unicităţii
înregistrărilor.
De exemplu, dacă vă interesează anumite nume de familie în tabela
Student, puteţi crea un index pentru coloana NumeSt, pentru a regăsi
mai rapid studenţii cu un anumit nume de familie.
Cheia primară a unei tabele este indexată automat. Nu pot fi
indexate coloanele de tipul Memo, Hyperlink sau OLE Object.
Utilizarea unui index are sens doar dacă se vor face interogări
frecvente relativ la coloana indexată. Deşi accelerează procesul de
regăsire a datelor, indecşii îngreunează serios actualizarea lor.
După fiecare operaţie de actualizare a datelor (inserare, modificare
sau ştergere) trebuie să verificaţi şi să actualizaţi şi
indecşii. De aceea, folosurea lor trebuie să fie bine întemeiată,
deoarece, altfel, ei pot mări timpul de răspuns al sistemului şi
ocupă spaţiu suplimentar pe disc.
Pentru a crea cheia primară a unei tabele, treceţi în modul Design
View al acelei tabele. Selectaţi coloana sau grupul de coloane ce va
servi drept cheie primară şi apoi apăsaţi butonul Primary Key de
pe bara cu instrumente sau alegeţi comanda Edit | Primary Key.
Notă: Pentru a selecta un câmp în Table Design View, faceţi clic
în coloana cea mai din stânga a ferestrei Table Design. Pentru a
selecta mai multe câmpuri, ţineţi apăsată tasta Ctrl în timp ce
efectuaţi operaţia de mai sus pentru fiecare câmp.
Când o coloană face parte din cheia primară a unei tabele,
proprietatea Indexed are valoarea o coloană face parte din cheia
primară a unei tabele, proprietatea Indexed are valoarea Yes (No
Duplicates), adică Access indexea¬ză acea coloană şi duplicatele
nu sunt permise. Proprietatea Required primeşte valoarea Yes, deoarece
cheia primară nu poate conţine valoarea null.
Să presupunem că se fac frecvente căutări în tabela Student,
după numele complet (NumeSt+PrenumeSt). Pentru a crea un index pe
aceste două coloane, procedaţi astfel:
deschideţi tabela Student în Table Design View.
apăsaţi butonul Indexes de pe bara de instrumente sau alegeţi
comanda View | Indexes. Va apărea fereastra Indexes pentru tabela
Student (fig.). Observaţi că ea conţinde deja o intrare pentru cheia
primară a tabelei, NrMatricol, deci există un index de pe coloana
NrMatricol, numit Primary Key.
Fig. 2.10. Stabilirea indecşilor
1. deoarece sortarea studenţilor se va face după nume şi prenume,
vom crea şi un index pe aceste coloane. Pentru aceasta, introduceţi
în primul câmp liber al coloanei Index Name denumirea indexului:
să-i spunem Nume.
2. faceţi clic în coloana Field Name a aceleiaşi linii şi alegeţi
din lista derulantă coloana NumeSt. Cum de cele mai multe ori vom dori
ca studenţii să fie sortaţi în ordine alfabetică, lăsaţi în
coloana Sort Order valoarea Ascending.
3. lăsaţi necompletat câmpul din linia următoare a coloanei Index
Name (am precizat deja numele indexului) şi alegeţi în câmpul Field
Name coloana PrenumeSt. Ordinea sortării va fi tot crescătoare.
Astfel am creat indexul Nume pe coloanele NumeSt şi PrenumeSt.
Proprietăţile fiecărui index le puteţi vedea în partea de jos a
ferestrei Indexes dacă faceţi clic în celula în care aţi
specificat numele indexului (nume şi, respectiv, Primary Key).
Proprietăţile pentru noul index creat le puteţi vedea în figură.
Fig. 2.11. Crearea celui de-al doilea index
2.2.9 Crearea unei tabele folosind experţii Access.
Pînă acum am discutat despre cel mai complicat mod de a crea o
tabelă. Acesta este şi modul care vă oferă cel mai mult control
asupra tabelelor create şi proprietăţilor lor. Access vă pune la
dispoziţie şi trei experţi: Table Wizard, Import Table Wizard şi
Linking Table Wizard.
Primul vă ajută să creaţi o tabelă pe baza unei tabele
predefinite. Table Wizard vă dă posibilitatea să alegeţi tabela
care să vă servească drept model, să selectaţi coloanele dorite,
să le redenumiţi, să spuneţi dacă doriţi ca Access să creeze o
cheie primară, să stabiliţi relaţii între noua tabelă şi alta
existentă. O dată tabela creată, puteţi folosi modul Table Design
pentru a-i modifica proprietăţile sau Table Datasheet pentru a
introduce datele. Table Wizard este util mai ales pentru aceia dintre
dumneavoastrp care nu au mai lucrat cu Access. Cei cu experienţă vor
găsi că este mai simplu să pornească direct cu Table Design View.
Expertul Import Table Wizard vă permite să importaţi obiecte şi
date din surse externe, cum ar fi: tabele Excel, dBase, Fox Pro,
fişiere text, documente HTML, orice sursă ODBC disponibilă în
sistemul dumneavoastră sau din alte baze de date Access.
Link table Wizard creează legături între baza de date curentă şi
tabele dintr-un fişier extern (oricare din cele specificate mai sus).
Puteţi vizualiza şi modifica datele dintr-o tabelă legată de baza
dumneavoastră de date, să le modificaţi anumite proprietăţi, să
stabiliţi relaţii. Dacă ştergeţi o tabelă legată din baza de
date curentă, se şterge doar legătura, nu şi tabela din baza de
date sursă.
2.3 Stabilirea relaţiilor între tabele
Posibilitatea de a crea şi de a folosi relaţiile dintre tabelele
unei baze de date este punctul forte al bazelor de date relaţionale
şi al sistemelor de administrare a bazelor de date relaţionale, cum
este şi Microsoft Access.
Pentru a stabili relaţii între tabele, bazele de date relaţionale
folosesc coloane cheie care sunt comune tabelelor pe care le leagă.
2.3.1. Fereastra Relationships
Relaţiile pot fi definite fie în timpul creării unei tabele noi,
fie după aceea. Pentru a defini o relaţie, ambele tabele trebuie să
existe în baz ade date.
În primul caz, în care relaţia este definită în timpul creării
unei tabele, veţi folosi pentru definirea relaţiei ori expertul Table
Wizard, ori coloanele de căutare. Table Wizard vă permite acest lucru
într-una dintre cutiile sale de dialog. Cea de-a doua modalitate este
să definiţi coloane de tip lookup (despre care am mai vorbit în
cadrul acestui capitol). Prin crearea unei coloane de tip lookup (de
căutare) care să-şi ia datele din altă tabelă, se stabileşte şi
o relaţie între cele două tabele.
Nu este necesar ca relaţiile să fie create o dată cu tabelele. De
fapt, cel mai simplu mod de a crea o relaţie între două tabele este
folosirea ferestrei Relationships. Aceasta poate fi deschisă fie prin
comanda Tools | Rela¬tion¬ships, fie apăsând butonul Relationships
de pe bara cu instrumente.
Notă: înainte de a folosi fereastra Relationships pentru crearea sau
modificarea unei relaţii, este bine să închideţi orice fereastră
Datasheet View pentru că nu pot fi impuse regulile de integritate
referenţială dacă tabelele implicate sunt deschise într-unul din
cele două moduri amintite.
Dacă fereastra Relationships este deschisă pentru prima dată pentru
baza de date curentă sau dacă a mai fost folosită, dar relaţiile nu
au fost salvate, ea va apărea pe ecran goală, împreună cu cutia de
dialog Show table.
Fig. 2.12. Vizualizarea tabelelor pentru stabilirea de relaţii
Dacă pentru baza de date curentă există relaţii salvate, cutia de
dialog Show table nu va apăre ci, în fereastra, vor fi afişate
tabelele şi relaţiile dintre acestea. Relaţiile sunt prezentate sub
forma unei linii continue ce leagă câmpurile cheie ale tabelelor ce
participă la o relaţie.
Pentru a adăuga o tabelă sau o interogare la fereastra
Relationships, faceţi dublu clic pe numele ei în cutia de dialog Show
Table. Astfel, ea va apărea în fereastra Relationships împreună cu
toate relaţiile la care participă. Pentru a vedea toate relaţiile
care au fost definite pentru o anume tabelă, adăugaţi tabela la
fereastra Relationships, închideţi cutia de dialog Show Table şi
alegeţi comanda Relationships | Show Direct. Access va adăuga automat
în fereastra Relationships toate tabelele care participă la relaţii
cu tabela aleasă, precum şi relaţiile respective. Figura prezintă
relaţiile la care participă tabela Curs_Student.
Fig. 2.13. Relaţiile petru tabela Curs_Student
Pentru a putea vedea relaţiile stabilite între toate tabelele bazei
de date curente, alegeţi comanda Relationships | Show All. Pentru a
înlătura o tabelă din fereastra Relationships fără a şterge
vreuna din relaţiile la care participă, selectaţi tabela făcând
clic pe oricare dintre câmpurile ei şi apoi alegeţi comanda
Relationships | Hide Table sau Edit | Delete. (aveţi grijă să
selectaţi o tabelă şi nu o relaţie). Pentru a înlătura toate
tabelele din fereastra Relationships fără a şterge relaţiile dintre
ele, folosiţi comanda Edit | Clear Layout.
Din fereastra Relationships puteţi accesa modul Table Design View
pentru o tabelă. Pentru aceasta, faceţi clic pe unul dintre
câmpurile tabelei şi din meniul derulant alegeţi comanda Table
Design. (După ce terminaţi lucrul în fereastra Table Design View,
închideţi-o.)
2.3.2 Crearea relaţiilor dintre tabele.
Acum, după ce aţi aflat cum să adăugaţi şi să înlăturaţi o
tabelă din fereastra Relationships, este timpul să învăţaţi cum
se poate stabili o relaţie între două tabele. Vom crea o relaţie
între tabelele Profesor şi Titlu. Pentru aceasta, procedaţi astfel:
1. adăugaţi ambele tabele la fereastra Relationships.
2. faceţi clic pe câmpul IdTitlu din tabela Titlu şi, ţinănd
mouse-ul apăsat, trageţi câmpul peste câmpul IdTitlu din tabela
Profesor.
Fig. 2.14. Stabilirea relaţiilor petru tabela Curs_Student
3. va apărea cutia de dialog Relationships (fig.) apăsaţi butonul
Create pentru a accepta valorile propuse de Access. Acum, în fereastra
Relationships relaţia este figurată printr-o linie ce uneşte
câmpurile IdTitlu din cele două tabele.
Fig. 2.15. Stabilirea relaţiilor între tabelele Profesor şi Titlu
De cele mai multe ori, pentru a crea o relaţie 1:m între două
tabele va trebui să deplasaţi cheia primară (afişată îngroşat) a
uneia dintre tabele peste câmpul corespunzător (cheie străină) din
cealaltă tabelă. Cele două câmpuri trebuie să aibă acelaşi tip
de date. Câmpurile de tip Autonumber, pentru care valoarea New Value
are valoarea Increment, pot fi puse în relaţie cu coloane de tipul
Number, pentru care Proprietatea Field Size este stabilită la Long
Integer. Dacă ambele câmpuri sunt de tipul Number, proprietatea Field
Size trebuie să aibă aceeaşi valoare.
2.3.3 Proprietăţile relaţiilor
Cutia de dialog Relationships vă permite să stabiliţi
proprietăţile relaţiilor. Aici puteţi adăuga câmpuri pentru a
defini o relaţie, făcând clic într-o celulă goală a grilei şi
alegând câmpul dorit din lista derulantă. (Dacă adăugaţi un
câmp, trebuie să alegeţi un câmp corespunzător din cealaltă
tabelă.)
Dacă doriţi să schimbaţi câmpul unei tabele care participă la
relaţie, faceţi clic în celula care îl conţine şi alegeţi noul
câmp ca mai înainte.
Tot aici puteţi stabili tipul de asociere (join) pe care Access îl
va folosi când veţi crea o interogare bazată pe cele două tabele.
Acest lucru îl realizaţi apăsând butonul Join Type. Se va deschide
cutia de dialog Join Properties (fig.2.16). despre tipurile de asociere
vom vorbi în secţiunea următoare.
De asemenea, puteţi decide dacă Access va impune regulile de
inte¬gritate referenţială asupra tabelelor care participă la
relaţie, problemă asupra căreia vom reveni.
2.3.4. Tipuri de asociere
Tipul de asociere (join) al unei relaţii specifică modul în care
sunt regasite informaţiile din două tabele corelate şi nu afectează
relaţia însăşi. Cele trei tipuri principale sunt: inner join, outer
join şi self-join. Tipul outer join poate fi, la rândul său, left
outer join şi right outer join. Rezultatul unei interogări bazate pe
două tabele corelate poate fi interpretat ca o tabelă în care
fiecare linie este o combinaţie a unei linii luate din prima tabelă
şi a uneia din cea de-a doua tabelă.
O asociere de tipul inner join este aceea în care liniile celor două
tabele sunt concatenate şi adăugate la rezultatul unei interogări
numai dacă valorile câmpurilor de legătură sunt egale. Acest tip de
asociere este util atunci când doriţi numai înregistrările care au
valori în câmpurile corelate. Tipul inner join mai este cunoscut şi
sub numele de equi-join şi este opţiunea implicită propusă de
Access.
Tipul outer join este opusul lui inner join. El permite adăugarea
unei linii la rezultatele unei interogări chiar dacă nu există o
linie corespunzătoare în tabela corelată. De exemplu, dacă doriţi
să vedeţi numai cursurile pentru care a optat cel puţin un student,
folosiţi un inner join. Dacă doriţi să regăsiţi cursurile
indiferent dacă au fost alese sau nu de cel puţin un student,
folosiţi un outer join.
O asociere de tipul left outer join (sau left join) vă dă
posibilitatea să includeţi în rezultatele interogării toate
înregistrările din tabela din partea stângă a operatorului LEFT
JOIN, iar din tabela din partea dreaptă, doar înregistrările care au
corespondent în tabela din stânga. Pentru a ilustra cele mai de sus,
vă prezentăm interogarea ce regăseşte toate cursurile disponibile
şi numerele matricole ale studenţilor care s-au înscris la cel
puţin un curs:
SELECT Denumire, NrMatricol
FROM Curs LEFT JOIN Curs_Student
ON Curs.IdCurs = Curs_Student.IdCurs
O asociere de tip right outer join (right join) va include în
rezultatele interogării toate înregistrările din tabela din partea
dreaptă a operatorului TIGHT JOIN, iar din tabela din partea stângă
a operatorului doar înregistrările care au un corespondent din tabela
din dreapta. Observaţi că cei doi operatori, LEFT JOIN şi RIGHT JOIN
pot produce aceleaşi efecte dacă sunt schimbaţi între ei şi dacă
se modofică ordinea tabelelor. Astfel, interogarea următoare va avea
acelaşi efect ca şi cea de mai sus:
SELECT Denumire, NrMatricol
From Curs_Student RIGHT JOIN Curs
On Curs.IdCurs = Curs_Student.IdCurs
Notă: nu există nici o legătură între poziţionarea tabelelor în
fereastra Relationships (una la stânga celeilalte) şi poziţionarea
lor în stânga sau în dreapta operatorului LEFT JOIN sau RIGHT JOIN.
În cazul în care între două tabele există definită o relaţie, la
creareea interogării Access va considera că tabela care conţine
cheia primară este tabela din stânga operatorului.
După ce aţi selectat o asociere de tipul outer join, Access o va
repre¬zenta printr-o linie cu săgeată la unul din capete. Reţineţi
că sensul în care este orientată săgeata este dinspre tabela din
care se vor include toate înregistrările către tabela din care se
vor include doar înregistrările ce au un corespondent.
O asociere de tip self-join este între două copii ale aceleiaşi
tabele şi o puteţi crea prin corelarea a două câmpuri ale
aceleiaşi tabele.
Access vă dă posibilitatea de a opta doar pentru inner join, left
outer join sau right outer join. Pentru relaţia Profesor/Titlu,
alegeţi în cutia de dialog Join Properties opţiunea cu nunărul unu,
inner join.
2.3.5 Asigurarea integrităţii referenţiale
Access va asigura în mod automat integritatea referenţială pentru
două tabele corelate dacă veţi valida caseta de validare Enforce
Referential Integrity din cutia de dialog Relationships. Astfel, dacă
în tabela Profesor există o valoare pentru câmpul IdTitlu, va trebui
ca acea valoare să existe şi în tabela Titlu. De asemenea, nu veţi
putea şterge o înregistrare din tabela Titlu dacă tipul respectiv
este atribuit unui profesor din tabela Profesor. Dacă veţi încerca
să introduceţi date sau să le modificaţi astfel încât să fie
încălcată integritatea referenţială, Access va afişa o cutie de
dialog în care vă va spune că acţiunea dorită nu se poate
finaliza. De asemenea, vă va spune şi care dintre tabelele corelate
cauzează violarea integrităţii referenţiale.
Access vă dă şi posibilitatea de a specifica în ce mod doriţi să
fie rezol¬vate problemele legate de integritatea referenţială.
Astfel, puteţi alege ca mo¬di¬ficările sau ştergerile dintr-o
tabelă să se reflecte şi în tabela corelată, pentru ca
integritatea referenţială să nu fie afectată.
Prima opţiune vă este oferită prin intermediul casetei de validare
Cas¬cade Update Related Fields. Această opţiune vă asigurăcă
orice modi¬ficare a valorilor din cheia primară a unei tabele va duce
automat la modificarea corespunzătoare a valorilor din cheia străină
a tabelei corelate. Astfel, dacă modificaţi o valoare a coloanei
IdTitlu din tabela Titlu, Access va modifica, în consecinţă, toate
apariţiile acelei valori în coloana IdTitlu a tabelei Profesor.
2.3.6. Modificarea relaţiilor existente
Pentru a modifica o relaţie existentă între două tabele,
adăugaţi tabelele respective în fereastra Relationships. Apoi
faceţi dublu clic pe linia ce reprezintă relaţia pe care doriţi să
o modificaţi. Va apărea cutia de dialog Relationships, în care
puteţi efectua modificările dorite.
Pentru a şterge o relaţie, selectaţi-o făcând clic pe linia care
o reprezintă şi apoi apăsaţi tasta Delete.
2.4.1 Importul datelor
Pentru a importa un fişier în Access, selectaţi comanda File | Get
External Data | Import sau faceţi clic dreapta în fereastra Database
şi alegeţi din meniul derulant comanda Import. Va apărea cutia de
dialog Import (fig.2.17).
Fig. 2.17. Importul datelor
Aici puteţi alege fişierul pe care doriţi să-l importaţi. În
funcţie de formatul de fişier ales, Access, va prezenta cutiile de
dialog corespunzătoare, în care veţi putea specifica opţiunile
dumneavoastră.
2.4.2 Exportul datelor
Access vă dă posibilitatea de a exporta toate tipurile de obiecte
dintr-o bază de date. Totuşi, există câteva reguli de care este
bine să ţineţi cont:
• puteţi exporta o tabelă sau o interogare fie salvând-o într-un
fişier nou, fie într-o nouă tabelă sau interogare din baza de date
curentă.
• puteţi exporta un formular sau un raport în unul din formatele:
Access, Excel, text şi RTF (Rich Text Format). În toate cazurile în
afară de formatul Access , veţi exporta şi datele ce creează
formularul sau raportul.
• Puteţi exporta un modul numai în formatul Access sau text.
Pentru a exporta un obiect din baza de date curentă, selectaţi-l în
fereastra Database şi alegeţi comanda File | Save As | Export. Va
apărea o cutie de dialog care vă va întreba dacă doriţi să
salvaţi obiectul într-un fişier extern sau în baza de date
curentă. Dacă selectaţi prima opţiune, va apărea cutia de dialog
prezentată în fig. .
Fig. 2.17. Exportul datelor
Aici puteţi alege tipul de fişier extern în care doriţi să
salvaţi obiectul şi locaţia acestuia. În funcţie de formatul ales,
Access va prezenta diferite interfeţe.
2.4.3. Formate standard
Access vă pune la dispoziţie peste unsprezece formate pentru
exportul datelor şi peste nouă formate pentru import. De asemenea,
aveţi la îndemână şi trei experţi : Import Text Wizard, care vă
ajută să importaţi date din formatul text, Import Spreadsheet
Wizard, pentru importul tabelelor Excel sau lotus şi Export Text
Wizard, pentru exportul datelor în format text.
• Microsoft FoxPro (.DBF): puteţi importa sau exporta date în
format FoxPro, versiunile de la 2.0 la 3.0.
• DBase (.DBF): puteţi importa sau exporta date în format dBase,
versiunile III, IV şi V.
• Paradox (.DB): puteţi importa sau exporta date în formatul
Paradox, versiunile 3.x, 4.0 şi 5.0.
• Baze de date ODBC: pentru a importa sau exporta date din sau în
Microsoft SQL Server, Sybase SQL Server, Oracle Server sau alte
formate, trebuie să aveţi instalat un driver ODBC.
• Microsoft Excel (.XLS): puteţi importa sau exporta date în format
Excel, versiunile 3.0 – 7.0 şi 97.
• Lotus: puteţi importa sau exporta date în format Lotus 1-2-3.
• Text: formatele text în care puteţi importa sau exporta date
sunt: .TXT, .CSV, .TAB, .ASC. În plus, puteţi exporta în formatul
.RTF (Rich Text Format).
• Access: formatele Access în care puteţi importa sau exporta date
sunt: .MDB, .MDW, .MDA şi .MDE.
• HTML: formatele disponibile pentru importul şi exportul datelor
sunt .HTML şi .HTM. Puteţi ataşa ieşirea unui obiect la un mesaj
e-mail.
CAP:3. Interogări
Interogările sunt una dintre cele mai puternice componente din Access
97. Ele vă permit să regăsiţi anumite informaţii stocate în baza
de date. Abilitatea de a crea interogări este considerată a fi
„creierul” unui sistem de baze de date relaţional, deoarece nu
contează doar faptul că puteţi stoca informaţii, ci mai ales faptul
că puteţi regăsi exact informaţia de care aveţi nevoie la un
moment dat.
În Access, interogările deţin un rol foarte important (ele pot fi
sursa unui raport, formular sau a listei de valori posibile pentru o
coloană de căutare). Există două modalităţi de creare a
interogărilor în Access: folosirea ferestrei QBE (Query by Example),
numită şi Query Design, sau introducerea directă de comenzi
SQL.indiferent pe care dintre cele două moduri le folosiţi, intern,
interogarea va fi definită tot ca o instrucţiune SQL. Access SQL este
dialect care diferă substanţial de standardul ANSI.
3.1. Folosirea ferestrei QBE
După cum puteţi observa din fig.3.1, fereastra QBE este compusă din
două părţi. Partea de sus (pe care o vom numi şi panou) prezintă
tabelele pe care se bazează interogarea şi relaţiile dintre ele.
Partea de jos, numită şi grila QBE, precizează câmpurile tabelelor
şi criteriile pe baza cărora este definită interogarea. Deşi are
limitările sale, folosirea ferestrei QBE este un mod simplu şi
intuitiv de a crea o interogare.
Fig. 3.1. Fereastra QBE (Query by Example)
3.1.1. Specificarea surselor de date
Puteţi specifica sursele de date pe care se bazează o
interogare(tabele sau alte interogări) fie în timpul creării
interogării, fie după aceea prin intermediul cutiei de dialog Show
Table. Aceasta va apărea automat la crearea unei noi interogări sau
dacă alegeti comanda Query | Show Table. Aici puteţi selecta tabelele
sau interogările ce se vor servi drept sursă de date pentru
interogarea curentă. O altă cale prin care puteţi adăuga tabele sau
interogări la interogarea curentă este de a le plasa din fereastra
Database în panoul ferestrei QBE.
Pentru a defini o interogare,trebuie să aveţi cel puţin o tabelă
sau o interogare în panoul ferestrei QBE, şi cel puţin un câmp în
grila ferestrei QBE. După cum spuneam, rezultatele unei interogări
sunt prezentate sub forma unei tabele virtuale, ale cărei câmpuri
sunt cele specificate în grila QBE. Datele acestei tabele sunt
selectate din câmpurile din grila QBE pe baza unor criterii.
Dacă doriţi ca rezultatul interogării să conţină anumite
câmpuri ale unei tabele sau interogării din panoul ferestrei QBE,
introduceţi-le în grila QBE în felul următor: selectaţi-le în
tabela sau interogarea respectivă (făcând clic pe ele) şi
deplasaţi-le peste grila QBE. Pentru a introduce în grilă toate
câmpurile unei tabele, sau interogări din panou, selectaţi
asteriscul care apare imediat sub bara de titlu şi deplasati-l peste
grilă. Chiar dacă rezultatul interogării va conţine toate
câmpurile din tabelă (rezultatul îl puteţi vedea în modul
Datasheet View, în care treceţi cu comanda View | Datasheet View),
în grila QBE va apărea doar asteriscul. Dacă doriţi să stabiliţi
anumite criterii pe baza cărora datele unui câmp să fie incluse în
rezultatul interogării, câmpul trebuie să fie vizibil în grilă,
aşa că va trebui să-l introduceti separat.
O altă cale de a introduce în grila QBE un câmp este să faceţi
clic în prima celulă liberă din linia Field a grilei şi să
apăsaţi butonul don dreapta. Se va deschide o listă cu toate
câmpurile tavelelor şi interogărilor din panoul QBE. O dată
selectat un câmp, se va completa automat şi celula corespunzătoare
din linia Table.
3.1.2. Proprietăţile interogărilor
Când vorbim despre proprietăţile unei interogări ne referim de
fapt la proprietăţile mai multor obiecte: ale interogării ca obiect
în sine, ale tabelelor, ale câmpurilor acestora şi relaţiilor.
Dacă selectaţi o interogare din pagina Queries a ferestrei Database
şi apoi apăsaţi butonul Properties de pe bara cu instrumente, se va
deschide cutia de dialog prezentată în figură:
Fig. 3.2. Proprietăţile interogăriilor
Pentru fiecare obiect puteţi introduce o descriere de maximum 255 de
caractere. Pe lângă descriere, cutia de dialog Properties vă arată
când a fost creat obiectul, când a fost modificat ultima dată şi
cine este proprietarul lui. Dacă validaţi caseta Hidden, obiectul nu
va mai apărea în fereastra Database (aceasta este o măsură de
securitate). Cea de-a doua casetă de validare vă lasă să
specificaţi dacă obiectul este replicabil.
Pentru a vedea şi obiectele cu proprietatea Hidden (ascunse),
alegeţi comanda Tool | Options şi, în pagina View, validaţi caseta
Hidden Objects.
Pentru a vedea pagina de proprietăţi a ferestrei QBE, faceţi
dublu-clic în panou. Aceasta este o pagină detaliată de
proprietăţi a interogării.
În continuare, vom prezenta în detaliu aceste proprietăţi:
• Description: aici puteţi introduce o descriere de maximum 255 de
caractere a interogării.
• Output All Fields: valoare Yes va introduce în rezultatele
interogării toate câmpurile tabelelor/interogărilor din panoul QBE.
• Top Values: returnează numai primele n sau n% înregistrări.
• Unique Values: dacă valoarea sa este Yes, returnează numai
înregistrările unice pentru câmpurile din grila QBE. De exemplu,
dacă în grilă se află numai câmpul IdCurs al tacelei Curs_Stud,
vom vedea numai valorile unice a lui IdCurs.
• Unique Records: dacă valoarea sa este Yes, returnează numai
înregistrările unice în cadrul sursei de date (tabelă sau
interogare).
• Run Permissions: specifică dacă interogarea rulează cu
drepturile proprietarului (owner’s) sau a utilizatorului (user’s).
Astfel, puteţi da unui utilizator permisiunea de a efectua o acţiune
pe care, altfel, nu ar avea drept să o execute.
• Source Database: puteţi specifica o bază de date externă care
conţine tabelele şi interogările sursă. Valoarea implicită este
baza de date curentă.
• Source Connect String: numele şi versiunea aplicaţiei în care a
fost creată baza de date externă, urmate de punct şi virgulă (ex:
dBase IV;).
• Record Locks: această proprietate este utilă pentru sistemele
multiuser şi specifică modul în care sunt blocate datele în timpul
execuţiei interogării.
• ODBC Timeout: timpul, în secunde, în care se întrerupe execuţia
interogării dacă serverul ODBC nu răspunde.
• Filter: funcţionează asemănător cu opţiunea Criteria a grilei
QBE. Este completat automat în timpul rulării interogării dacă în
modul Datasheet View veţi folosi comentile Filter by Form, Filter by
Selection sau Advanced Filter/Sort din meniul Records. Vă permite să
selectaţi anumite înregistrări din rezultatul interogării.
• Order By: funcţionează asemănător cu secţiunea Sort a grilai
QBE. Este completat automat în timpul rulării interogării dacă în
modul Datasheet View selecteţi o coloană (sau două) şi apoi
apăsaţi butonul Sort Ascending sau ort Descending de pe bara cu
instrumente.
Acestea au fost proprietăţile unei interogări privite ca întreg. Pe
lângă acestea, puteţi stabili şi unele proprietăţi ale obiectelor
ce compun interogarea: tabele, alte interogări şi
câmpuri.Proprietăţile lor le puteţi vedea în modul Design View
selectându-le şi, apoi, alegând comanda View | Properties.
Cele două proprietăţi disponibile pentru tabele sunt următoarele:
• Alias: Vă dă posibilitatea să specificaţi un nume alternativ,
temporar pentru o tabelă. Este util în cazul în care interogarea se
bazează pe o asociere self-join.
• Source: Este asemănătoare cu proprittăţile Source Database sau
Source Connect String ale unei interogări. Sacă interogarea
foloseşte tabele din mai multe baze de date externe, stabiliţi
acestă proprietate pentru fiecare tabelă în parte.
Fiecare câmp din grila QBE are proprietaţile sale. Cutia de dialog
Properties pentru un câmp are două pagini: General şi Lookup. Iată
care sunt aceste proprietăţi:
• Descriptions: Conţine o descriere a câmpului, de maximum 255 de
caractere.
• Format: Vă permite să specificaţi modul în care vor fi afişate
şi tipărite datele din câmpul respectiv.
• Imput Mask: Funcţionează ca şi proprietatea Format, cu
diferenţa că aici puteţi preciza un format pentru introducerea
datelor. Dacă apăsaţi butonul din dreapta câmpului Imput Mask, va
porni un wizard care vă va ajuta să specificaţi modul în care
vreţi să arate datele.
• Decimal Places: Pentru câmpurile numerice, precizează numărul de
zecimale care vor fi afişate.
• Caption:Titlul sub care va apărea câmpul în modul Datasheet View
sau pe un formular.
• Display Control: Tipurile de control folosite pentru afişarea
datelor câmpului respectiv în modul Datasheet View sau pe un formular
sunt: text box, list box sau combo box. Acestea sunt disponibile numai
pentru câmpuri numerice, text şi de tip yes/no. Dacă celectaţi list
box sau combo box, vor apărea atributele corespunzătoare.
Notă: pentru acelaşi câmp, puteţi stabili calităţi diferite în
interogări diferite. Dacă un formular este bazat pe o tabelă,
atributele câmpurilor sunt cele specificate în tabelă. Dacă
formularul se bazează pe o interogare, atributele câmpurilor sunt
cele specificate în interogare.
3.2. Tipuri de interogări
Există interogări pentru regăsirea datelor (cele de tip selectare)
şi pentru modificarea datelor (inserare, ştergere şi actualizare).
Până acum am vorbit numai despre interogări simple de tip selectare.
Pentru a crea o astfel de interogare nu trebuie decât să folosiţi
fereastra QBE pentru a specifica sursele datelor pe care doriţi să le
aflaţi şi, eventual, tipul de asociere. Rezultatele interogării le
puteţi vedea intrând în modul Datasheet pentru acea interogare.
Pentru aceasta, alegeţi comanda Query | Run sau apăsaţi butonul Run
de pe bara cu instrumente.
În afară de interogările de tip selectare simple, Acces vă mai
oferă un tip de interogări pentru regăsirea datelor: interogările
agregat.
3.2.1. Interogări agregat
Interogările agregat vă dau posibilitatea de a analiza datele,
calculând sume, extreme, medii, dispersii etc. Ele vă pot fi foarte
utile la întocmirea rapoartelor statistice sau a graficelor. Cele
două tipuri de interogări agregat pe care Access le pune la
dispoziţie sunt Totals şi Crosstab.
3.2.2. Interogări de tip totals
Să presupunem că doriţi să aflaţi numărul de studenţi
înscrişi în fiecare curs opţional. Interogarea care vă va furniza
aceste informaţii este prezentată în fig. în modul Design View şi
în fig. 3.3 în modul Datasheet View (rezultatele).
Fig. 3.3. Mod de realizare a interogărilor de tip Total
Pentru a crea o interogare de tip totals, procedaţi astfel:
1. creaţi o nouă interogare de tip select şi adăugaţi tabelele
necesare la panoul ferestrei Qbe.
2. introduceţi în grila ferestrei QBE coloanele pentru care doriţi
să calculaţi totalul, media, extremele etc.
Fig. 3.4. Mod de realizare a interogărilor de tip Medie
3. schimbaţi tipul interogării în Totals, alegând comanda View |
Totals sau apăsând butonul Totals de pe bara cu instrumente.
Observaţi că în câmpul Total al grilei QBE va apărea în dreptul
coloanelor selectate opţiunea Group By.
4. selectaţi în grila QBE coloana în funcţie de care doriţi să
aflaţi totalul, suma media etc. coloanelor cu opţiunea Group By. În
câmpul Total corespunzător acestei coloane alegeţi una dintre
funcţiile agregat, care să efectueze operaţia dorită.
5. stabiliţi eventuale criterii şi rulaţi interogarea.
În continuare, vom vorbi mai pe larg despre opţiunile unei
interogări de tip Totals. Fiecare coloană selectată în grila
ferestrei QBE trebuie să aibă specificată o opţiune în câmpul
Total. Iată care pot fi aceste opţiuni:
• Group By: folosită pentru a defini grupurile de înregistrări
pentru care doriţi să calculaţi totalurile. Dacă în grila QBE
selectaţi o singură coloană, cu opţiunea Group By, interogarea va
returna o linie pentru fiecare valoare unică a coloanei respective.
Dacă selectaţi mai multe câmpuri cu opţiunea Group By, rezultatele
interogării vor conţine câte o linie pentru fiecare combinaţie
unică de valori ale câmpurilor respective.
• Count: funcţie agregat folosită pentru a număra înregistrările
dintr-un grup ale căror valori sunt diferite de null.
• Sum: funcţie agregat folosită pentru a calcula suma valorilor
unui câmp, pentru fiecare grup definit de opţiunea Group By.
• Min: funcţie agregat ce calculează valoarea minimă a unui câmp
pentru fiecare grup. Valorile null nu sunt luateîn considerare.
• Max: funcţie agregat ce calculează valoarea maximă a unui câmp
pentru fiecare grup. Valorile null nu sunt luateîn considerare.
• First: funcţie agregat folosită pentru a afla prima valoare
(într-o anumită ordine) a unui câmp pentru fiecare grup. Valorile
null nu sunt luate în considerare.
• Last: funcţie agregat folosită pentru a afla ultima valoare
(într-o anumită ordine) a unui câmp pentru fiecare grup. Valorile
null nu sunt luate în considerare.
• Avg: funcţie agregat ce calculează media valorilor unui unui
câmp pentru fiecare grup definit prin opţiunea Group By. Valorile
null nu sunt luate în considerare.
• StDev: funcţie agregat ce calculează deviaţia standard a
valorilor unui unui câmp pentru fiecare grup. Deviaţia standard este
un estimator statistic al dispersiei distribuţiei valorilor unui
câmp. Valorile null nu sunt luate în considerare.
• Var: funcţie agregat ce calculează dispersia valorilor unui unui
câmp pentru fiecare grup. Dispersia este pătratul deviaţiei
standard. Valorile null nu sunt luate în considerare.
• Expression: folosită pentru a calcula alte totaluri decât cele
oferite de funcţiile agregat, prin intermediul unei expresii introduse
de dum¬neavoastră. O expresie poate fi orice combinaţie de
oparatori, contante, nume de coloane, funcţii agregat, etc., prin
evaluarea căreia obţinem o singură valoare. O astfel de expresie
este Count(*), ce calculează numărul total de înregistrări dintr-un
grup, incluzând inregistrările care conţin valoarea null.
• Where: clauză folosită pentru specificarea unor criterii care să
limiteze rezultatele interogării. Când folosiţi această opţiune,
devalidaţi caseta din linia Show a grilei QBE corespunzătoare
coloanei asupra cărei impuneţi limitările.
3.2.2.1 Sortarea rezultatelor unei interogări de tip totals
Access vă dă posibilitatea de a sorta crescător sau descrescător
rezul¬tatele unei interogări, alegând în câmpul Sort al grilei QBE
opţiunea Ascending sau Descending. Dacă folosiţi mai multe coloane
cu opţiunea Group By, Access va sorta automat datele, întâi în
funcţie de prima coloană din grila QBE, apoi în funcţie de a doua,
etc., de la stânga spre dreapta. În exemplul din figura.,
înregistrările sunt sortate crescător, întâi în funcţie de
numele studentului şi apoi de prenume. Dacă am fi dorit ca
interogările să fie sortate întâi în funcţie de prenume şi apoi
în funcţie de nume (ca în figura), nu ar fi trebuit decât să
trecem în grila QBE coloana PrenumeSt în stânga coloanei NumeSt.
Access urmează următoarele reguli pentru sortarea rezultatelor unei
interogări de tip Totals:
• Dacă în câmpul Sort al grilei QBE corespunzător coloanelor cu
opţiunea Group By alegeţi Not sorted, adică nu specificaţi modul
în care să fie sortate datele, Access va sorta crescător aceste
coloane, precedenţa fiind de la stânga spre dreapta.
• Dacă în câmpul Sort al grilei QBE corespunzător coloanelor cu
opţiunea Group By specificaţi opţiunea Ascending sau Descending,
Access va sorta crescător respectiv descrescător aceste coloane,
precedenţa fiind de la stânga spre dreapta.
• Dacă specificaţi ordinea de sortare numai pentru anumite coloane
(pentru unele dintre coloanele cu opţiunea Group By, pentru coloanele
agregat sau pentru o combinaţie de coloane agregat şi Group By),
Access va sorta numai coloanele pentru care aţi specificat ordinea
respectând precedenţa de la stânga spre dreapta.
3.2.2.2 Stabilirea criteriilor
Să presupunem că doriţi să aflaţi care sunt studenţii al căror
nume începe cu litera „P” şi a căror medie este peste 7. Figura
prezintă interogarea care vă furnizează aceste informaţii în modul
Design View.
Fig. 3.5.Exemplu de realizare a interogărilor
Primul criteriu este deci aplicat unei coloane având opţiunea Group
By, NumeSt, iar cel de-al doilea criteriu este aplicat unei coloane
agregat. Criteriile impuse asupra coloanelor având opţiunea Group By
sau Where sunt luate în considerare înainte ca datele să fie
grupate, în timp ce criteriile asupra coloanelor agregat sunt impuse
după ce datele au fost grupate şi s-au aplicat funcţiile agregat.
Dacă doriţi totuşi să impuneţi limitări şi asupra datelor ce
vor fi supuse operaţiilor de agregare, puteţi face acest lucru prin
intermediul opţiunii Where. Să presupunem că dorim să aflăm media
cursurilor la care studenţii al căror nume începe cu „P” au luat
peste nota 7. acest lucru îl puteţi realiza dacă ştergeţi
criteriul „>7” impus coloanei agregat Media şi îl aplicaţi
coloanei Nota având opţiunea Where, ca în fig. 3.6.
Fig. 3.6.Exemplu de realizare a interogărilor
Notă: criteriile asupra coloanelor agregat sau cu opţiunea Group By
sunt specificate în SQL cu ajutorul clauzei HAVING, iar criteriile
asupra coloanelor cu opţiunea Where sunt implicate în SQL în cadrul
clauzei WHERE.
3.2.3. Interogări de tip Crosstab
Interogările de tip Crosstab se aseamănă cu cele de tipul Totals
prin faptul că vă permit aplicarea operaţiilor de agregare asupra
datelor. Ceea ce le deosebeşte este modul de afişare a rezultatelor.
Rezultatele unei interogări Crosstab sunt prezentate sub forma unei
tabele în care atât coloanele, cât şi liniile, au titluri.
Să presupunem că dorim să aflăm, pentru fiecare catedră, numărul
de profesori din fiecare categorie (preparatori, asistenţi, lectori,
etc.).Ar fi convenabil ca datele să fie afişate într-un tabel având
catedrele drept capete de linii şi titlurile drept capete de coloane.
Pentru aceasta, veţi crea o interogare Crosstab (pe care o puteţi
numi Total_Profesori_Crt), în felul următor:
1. Creaţi o nouă interogare de tip select şi adăugaţi tabelele
necesare.
2. Introduceţi în grila QBE cele două câmpuri de valori care vor
defini grupurile (de exemplu, Catedra şi Titlu).
3. Schimbaţi tipul interogării în Crosstab, alegând comanda Query |
Crosstab Query. În câmpul Total al grilei QBE corespunzător celor
două coloane va fi selectată opţiunea Group By.
4. Alegeţi care dintre cele două câmpuri va da numele liniilor şi
care pe cele ale coloanelor în cadrul tabelei cu rezultatele
interogării, selectând opţiunea Row Heading, respectiv Column
Heading în celula corespunzătoare din câmpul Crosstab al grilei QBE.
5. În funcţie de datele pe care doriţi să le aflaţi, introduceţi
într-o nouă coloană a grilei QBE opţiunile dumneavoastră. Pentru
exemplul nostru, introduceţi în câmpul Field expresia IdProf:
Count(*), în câmpul Total selectaţi Expression, iar în câmpul
Crosstab selectaţi opţiunea Value.
6. Stabiliţi eventuale criterii şi rulaţi interogarea.
Figura prezintă interogarea în modul Design View.
Câmpul care dă numele coloanelor din tabela cu rezultatele
interogării poartă numele de pivot. În cazul interogării prezentate
în figura câmpul pivot este Titlu iar în următoarea este prezentat
rezultatul.
Fig. 3.7. Exemplu de realizare a interogărilor de tip Crosstab
3.2.3.1 Crearea totalurilor pe linii
Puteţi crea o coloană care să arate totalul valorilor pe o linie,
adăugând la grila QBE un duplicat al coloanei care are opţiunea
Value. Duplicatul trebuie să aibă un alias(pe care îl puteţi
introduce in câmpul Field corespunzător, înaintea expresiei şi
urmat de două puncte) şi să aibă opţiunea Row Heading în câmpul
Crosstab.
Fig. 3.8. Exemplu de realizare a totalurilor pe linie pentru
interogărilor de tip Crosstab
3.2.3.2 Limitările intergărilor Crosstab
După cum aţi observat, într-o interogare de tip Crosstab numele
co¬loanelor sunt luate dintre valorile coloanei cu opţiunea Column
Heading. De aceea, ele ar putea să încalce regulile impuse numelor
de coloane. De exemplu, dacă o coloană de tip text, conţinând,
printre altele şi unele valori precum ON, AS sau alte cuvinte
rezervate, va da numele coloanelor într-o interogare crosstab, acea
interogare nu va putea fi folosită ca sursă de date pentru un raport,
grafic sau altă interogare. De regulă, puteţi rezolva această
problemă incluzând numele ilegale între paranteze drepte ([ON]).
În al doilea rând, în interogările crosstab nu puteţi impune
criterii asupra câmpurilor cu opţiunea Value. De exemplu, dacă vom
dori ca interogarea Total_Profesori_Crt să ne dea catedrele care au
mai mult de 2 profesori din fiecare categorie (titlu), nu vom putea
specifica „>=2” în câmpul Criteria al coloanei de tip Value.
Puteţi înlătura acest inconvenient cu ajutorul unei interogări de
tip Totals, pe care o vom folosi în interogarea Crosstab. Creaţi deci
o interogare de tip Totals, numită Total_Profesori, bazată pe
tabelele Profesor şi Titlu, în care câmpurile Catedra şi Titlu să
aibă opţiunea Group By, iar pentru agregare să se folosească
expresia: Count (*) (ca în fig. ), pentru care puteţi impune şi
criteriul „>=2”. Daţi câmpului agregat numele TotalPr.
Apoi, creaţi interogarea Cross_Total_Profesori, de tip Crosstab şi
bazaţi-o pe Total_Profesori, în care catedra va fi Row Heading, Titlu
va fi Column Heading şi TotalPr va avea opţiunea Value. Deoarece
datele din coloana TotalPr a interogării Total_Profesori_Crt au fost
agregate o dată, alegeţi în câmpul Total al grilei QBE
corespunzător lui TotalPr o funcţie agregat care, aplicată unei
singure valori, să de ca rezultat acea valoare (Sum, Min, Max, Avg,
First, Last).
Valori NULL în coloane Row Heading sau Column Heading
Să presupunem că în tabela Profesor există şi înregistrări
pentru care câmpul IdTitlu are valoarea NULL. În acest caz,
rezultatele interogării Total_Profesor_Crt vor conţine şi o coloană
al cărui nume va fi „<>”.
Această problemă poate fi rectificată prin două metode. Prima ar
fi să nu luăm în considerare înregistrările care conţin valoarea
Null în câmpul IdTitlu. Acest lucru îl putem realiza introducând
criteriul „Is Not Null” în câmpul Criteria corespunzător
coloanei Titlu. În acest mod, rezultatele interogării nu vor da nici
un fel de informaţii despre profesorii pentru care titlul nu a fost
specificat.
Dacă totuşi, nu ne putem lipsi de aceste informaţii, vom face în
aşa fel încât în locul semnului „<>”, pentru numele coloanei
să apară un text dorit de noi în cazul în care valoarea este NULL.
Pentru aceasta, vom introduce în câmpul Field al grilei QBE
corespunzător coloanei cu opţiunea Column Heading (care conţine
valorile null şi dă numele coloanelor tabelei cu rezultate),
expresia:
IIf (IsNull([Titlu]), „Nespecificat”, [Titlu])
Expresia de mai sus se traduce astfel: „Dacă valoarea câmpului
Titlu este Null, atunci pentru titlul coloanei din tabela de rezultate
se va afişa „Nespecificat”; altfel, se va afişa valoarea din
câmpul Titlu”.
3.2.4. Interogări pentru definirea şi modificarea datelor
Interogările pentru definirea şi modificarea datelor vă dau
posibilitatea de a actualiza eficient, printr-o singură operaţie, mai
multeînregistrări. Cele 4 tipuri de interogări care pot efectua
diferite acţiuni asupra datelor sunt: interogări de tipul Make Table,
Update, Append şi Delete.
3.2.4.1. Interogări de tip Make Table
Interogările de tip Make Table vă ajută să creaţi tabele noi
furnizate cu tabele existente sau alte interogări. Ele vă pot fi
utile dacă doriţi să faceţi o copie de siguranţă a unei tabele
sau să exportaţi date către alte baze de date Access sau ODBC.
Pentru a crea o interogare de tipul Make Table, deschideţi o nouă
interogare şi introduceţi în panoul ferestrei QBE tabelele (sau
interogările) care vor furniza datele pentru noua tabelă. Apoi
selectaţi în grila QBE coloanele care vor compune noua tabelă şi,
eventual, specificaţi criterii pentru limotarea datelor. Dacă veţi
dori ca în noua tabelă coloanele să aibă alte nume, introduceţi
aceste nume în câmpul Field al grilei QBE, înaintea numelor
coloanelor existente şi urmate de două puncte (de exemplu, Nume
Profesor: Nume). Pe urmă, alegeţi comanda Query | Make Table Query
sau apăsaţi butonul Query Type de pe bara cu instrumente şi alegeţi
Make Table Query. Va apărea cutia de dialog Make Table, în care va
trebui să specificaţi numele tabelei pe care vreţi să o creaţi
şi, în cazul încare tabela va face parte dintr-o bază de date
externă, numele acesteia cu calea completă. Dacă baza de date
externă nu este Access, introduceţi între ghilimele şi urmat de
punct şi virgulă numele aplicaţiei în care a fost creată (de
exemplu: c:\my documents\dbl „Paradox;”).
Puteţi vedea noua tabelă înainte ca ea să fie creată, trecând
în modul Datasheet View. Dacă rezultatele sunt corecte, rulaţi
interogarea şi noua tabelă va fi creată; dacă nu, întoarceţi-vă
în modul Design View şi efectuaţi modificările necesare.
Dacă, ulterior, veţi dori să actualizaţi datele din tabela creată
astfel, pentru ca ele să reflecte modificările din tabela de bază,
nu va trebui decât să rulaţi din nou interogarea respectivă.
3.2.5. Interogări de tip Append
Pentru aceasta, vom crea o nouă interogare de tip Append (numită
AppendProf), alegând comanda Query | Append Query. Va apărea cutia de
dialog Append, în care va trebui să specificaţi numele tabelei în
care vor fi introduse dateleşi baza de date în care se află această
tabelă (interogarea nu va putea fi executată dacă tabela nu există
deja). Apoi, cu ajutorul ferestrei Qbe, veţi preciza tabelele şi
câmpurile acestora din care vor proveni datele, precum şi câmpurile
tabelei destinaţie. După cum puteţi observa în fig., grila QBE a
unei interogări de tip Append conţine şi linia Append To, în care,
pentru fiecare câmp-sursă selectat în grilă, puteţi alege câmpul
destinaţie (cu condiţia ca cele 2 câmpuri să aibă acelaşi tip de
date).
Notă: în cazul încare câmpurile sursă şi destinaţie au acelaşi
nume, Access va alege automat câmpul destinaţie, în momentul
selectării câmpului sursă în grila QBE.
Acum, tot ce vă rămâne de făcut este să rulaţi interogarea şi
să deschideţi tabela ProfMate în modul Datasheet View pentru a vedea
noile înregistrări.
3.2.6 Interogări de tip Update
Interogările de tip Update vă sunt utile atunci când doriţi să
modificaţi mai multe înregistrări o dată. Să presupunem că toate
salariile mai mici de 1.000.000 lei se majorează cu 15%. Pentru a
actualiza în consecinţă datele din tabela Titlu, vom crea tabela
Majorare_Salariu, de tip Update. Pentru aceasta, creaţi o nouă
interogare, introduceţi tabela Titlu în panoul ferestrei QBE şi
schimbaţi tipul interogării în Update, alegând comanda Query |
Update. În grila ferestrei QBE va apărea o nouă linie, Update To,
în care veţi introduce regula pe baza căreia se va face actualizarea
(în acest caz, [Salariu] + [Salariu]*.15). în câmpul Criteria al
grilei QBE vom limita înregistrările ce vor fi actualizate la cele
pentru care salariul este 1.000.000.
Interogările de tip Update au anumite limitări care fac să nu
poată fi executate uneori. Înaceste situaţii, Access va da un mesaj
de eroare. Iată care sunt cele mai frecvente situaţii în care o
interogare de tip Update nu va putea fi executată:
• interogarea este bazată pe altă înterogare de tip Crosstab,
Union sau care conţine totaluri;
• interogarea este bazată pe 2 tabele între care există o relaţie
de tipul 1:m (integritatea referenţială ar putea fi violată);
• interogarea încearcă să scrie un text într-un câmp de tip
Number;
• interogarea încalcă regulile de validare impuse asupra datelor
unui câmp la nivel de tabelă.
3.2.7 Interogări de tip Delete
Folosind o interogare de tip Delete, puteţi şterge dintr-o tabelă
mai multe înregistrări o dată.
Notă: înainte de a executa o interogare de tip Delete, este bine să
creaţi pe aceleaşi criterii o interogare de tip Select care să
regăsească datele pe care doriţi să le ştergeţi. Dacă ele sunt
corecte, puteţi rula interogarea Delete fără grijă.
3.2.8 Interogări cu parametri
Puteţi crea interogări care să permită utilizatorului specificarea
unui criteriu în timpul rulării interogării. Pentru a crea o astfel
de, interogare va trebui să :
• introduceţi în câmpul Criteria corespunzător coloanei asupra
căreia vor fi impuse limitările un text prin care să cereţi
utilizatorului specificarea criteriului (textul va fi inclus între
paranteze drepte, ca în figura )
• folosiţi comanda Query / Parameters pentru a specifica tipul
datelor ce vor fi introduse de utilizator în timpul rulării
interogării (figura)
3.3. Expresii şi funcţii în interogări
Expresiile sunt instrumente folosite de programatori pentru a spori
performanţele aplicaţiilor. Ele sunt formate dintr-o combinaţie de
operatori, constante, variabile şi funcţii care au ca rezultat o
numită valoare. Expresiiloe pot fi folosite în interogări,
formulare, rapoarte, proprietăţi ale câmpurilor tabelelor sau ale
controalelor din formulare şi rapoarte, în funcţii macro şi module.
Ele pot fi folosite pentru a stabili criterii, ca reguli de validare
sau ca bază pentru coloanele calculate. De exemplu, dacă într-o
interogare introduceţi următoara expresie în câmpul Criteria
corespunzător unei coloane de tip Date/Time (tip folosit pentru
stocarea datelor şi orelor), ea va returna numai înregistrările mai
vechi de 3 zile:
<Now () + 3.
3.3.1. Părţile componente ale expresiilor
Expresiile pot fi privite ca nişte propoziţii matematice, în
componenţa cărora pot intra:
• operatori: simboluri matematice;
• constante: valori numerice sau şiruri de caractere ce nu îşi
schimbă valoarea;
• funcţii: proceduri ce returnează o valoare (de exemplu, funcţia
Now returnează data curentă);
• nume de câmpuri: de obicei sunt introduse între paranteze drepte
Operatori
Operatorii joacă un rol important în cadrul expresiilor. Există mai
multe tipuri de operatori pe care vi le prezentăm în cele ce
urmează.
Operatori aritmetici
Sunt folosiţi pentru a efectua calcule matematice cu 2 sau mai multe
valori numerice.
• ^ ridică un număr la o putere (de exemplu 2^3=23)
• * înmulţeşte 2 numere
• / împarte 2 numere şi returnează un număr real
• \ împarte 2 numere şi returnează un număr întreg
• MOD returnează restul împărţirii a 2 numere
• + adună 2 numere
• - scade 2 numere
Operatori de concatenare
Sunt folosiţi pentru a lega 2 şiruri de caractere.
• & concatenează 2 şiruri de caractere
• + adună valorile a 2 câmpuri numerice. Poate fi folosit şi
pentru a concatena şiruri de caractere.
Operatori de comparaţie
Sunt folosiţi pentru a compara valorile a 2 sau mai multe câmpuri
şi/sau expresii.
• = verifică egalitatea a 2 valori
• <> verifică dacă 2 valori sunt diferite
• < verifică dacă o valoare este strict mai mică decât alta
• > verifică dacă o valoare este strict mai mare decât alta
• <= verifică dacă o valoare este mai mică sau egală cu alta
• >= verifică dacă o valoare este mai mare sau egală cu alta
Operatori logici
Efectuează operaţii logice.
• Not introduce o negaţie (de exemplu, Not T* introdus într-o
inte¬rogare în câmpul Criteria al coloanei Nume va regăsi toţi
studenţii ale căror nume nu încep cu litera T)
• And efectuează conjuncţia a 2 valori
• Or efectuează disjuncţia a 2 valori
• Xor efectuează disjuncţia exclusivă a 2 valori
• Eqv verifică echivalenţa a 2 valori
• Imp operatorul „implică”
Precedenţa operatorilor
De multe ori, a calcula valoarea unei expresii implică efectuarea mai
multor operaţii. Aceste operaţii se efectuează într-o anumită
ordine predefinită, care este şi ordinea în care au fost prezentaţi
operatorii mai sus.
Dacă doriţi o schimbare în această ordine (de exemplu să
efectuaţi întâi o operaţie de adunare şi apoi o ridicare la
putere) folosiţi parantezele pentru a preciza care operator va fi
aplicat primul.
Constante
Constantele sunt un fel de cuvinte rezervate, în sensul că valoarea
lor nu se schimbă pe parcursul rulării aplicaţiei. Ele se împart
în 3 grupe, pe care vi le prezentăm în continuare.
Constante predefinite
Acestea sunt definite de programator, de obicei în module.
Declaraţia unei constante predefinite începe cu cuvântul cheie
CONST. De exemplu:
CONST Pi = 3.14
După ce au fost declarate, ele pot fi folosite oriunde.
Constante intrinsece
Sunt constante furnizate de Visual Basic (cum ar fi VbString sau
VarType) şi nu trebuie să fie declarate separat. Programatorul nu
poate defini o constantă care să aibă acelaşi nume ca o constantă
intrinsecă. Constantele intrinseci se pot folosi numai în module.
Constante sistem
Yes, No, On, Off şi Null sunt cele 5 componente sistem. Ele pot fi
folosite în orice obiect din baza de date, mai puţin în module.
Funcţii
Funcţiile pot intra în componenţa expresiilor. Ele acţionează ca
şi operatorii, dar nu sunt reprezentate prin simboluri. De exemplu,
operatorul + şi funcţia Sum efectuează aceeaşi operaţie: cea de
adunare. Diferenţa este aceea că funcţia Sum poate fi aplicată mai
multor valori o dată. Access vă pune la dispoziţiepeste 160 de
funcţii, dintre care câteva le puteţi vedea în câmpul Totals al
grilei QBE a unei interogări de tip Totals.
3.4. Lucrul cu date şi ore
În Access, expresiile pot conţine date sau ore. Acestea sunt stocate
ca numere reale pe 64 de biţi. Intervalul maxim pentru date este 1 Ian
100 şi 31 Dec 9999, iar cel pentru ore, între 0:00:00 şi 23:59:59.
După ce o dată/oră a fost introdusă într-o expresie, Access
parcurge expresia şi recunoaşte formatul respectiv, incluzând data
(ora) între 2 caractere diez ().
Access vă pune la dispoziţie aproximativ 22 de funcţii pentru
lucrul cu date şi ore. De exemplu, în interogarea Vechime,
prezentată în figura., am folosit funcţiile Yes şi Now pentru a
calcula câţi ani au trecut de la angajarea unui profesor şi până
în prezent. Funcţia Year () returnează numai anul dintr-o dată
completă, iar funcţia Now () returneazădata (şi ora) curentă.
Există câteva formate predefinite pentru afişarea datelor/orelor
în formulare, rapoarte, în modul Datasheet View al unei tabele sau
interogări etc. tabelul vă prezintă o listă cu aceste formate, pe
care o puteţi vedea şi în câmpul proprietăţii Format a unei
coloane de tip Date/Time a unei tabele (în modul Table Design).
Format Afişare (exemplu)
General 01/01/98 12:00:00 AM
Short date 01/01/98
Medium date 1-Jan-98
Long date Thursday, January, 1, 1998
Short time 00:00:00
Medium time 12:00 AM
Long time 12:00:00 AM
Prin intermediul expresiilor puteţi să personalizaţi modul cum vor
fi afişate datele/orele. În tabel sunt descrise diferite formate pe
care le puteţi folosi în acest scop.
Format Afişare (exemplu)
d Ziua din lună, între 1 şi 31
dd Ziua din lună, între 01 şi 31
ddd Ziua săptămânii (primele 3 litere din ziua săptămânii; de
exemplu, Monday pentru luni, Tuesday pentru marţi etc)
dddd Ziua săptămânii din limba engleză (întreg cuvântul; de
exemplu, Monday pentru luni, Tuesday pentru marţi etc)
w Ziua săptămânii, între 1 şi 7
ww Săptămâna din an, între 1 şi 52
m Luna anului, între 1 şi 12
mm Luna anului, între 01 şi 12
mmm Primele 3 litere din luna anului în engleză (de exemplu, Jan
pentru ianuarie, Feb pentru februarie, etc)
Mmmm Luna anului în limba engleză (întreg cuvântul; de exemplu, Jan
pentru ianuarie, Feb pentru februarie, etc)
q Trimestrul anului, între 1 şi 4
y Ziua din an, între 1 şi 365
yy Anul, între 00 şi 99
yyyy Anul, între 0100 şi 9999
h Ora, între 1 şi 23
hh Ora, între 01 şi 23
n Minutul, între 1 şi 59
nn Minutul, între 01 şi 59
s Secunda, între 1 şi 59
ss Secunda, între 01 şi 59
AM/PM AM pentru ore între miezul nopţii şi miezul zilei; PM pentru
ore între miezul zilei şi miezul nopţii
am/pm am pentru ore între miezul nopţii şi miezul zilei; pm pentru
ore între miezul zilei şi miezul nopţii
A/P A pentru ore între miezul nopţii şi miezul zilei; P pentru ore
între miezul zilei şi miezul nopţii
Semnul slash (/) este folosit, de obicei, ca separator pentru dată,
iar două puncte (:), ca separator pentru oră.
Folosind aceste formate, puteţi crea expresii care să returneze
valori de genul:
Luna angajării este Feb
Pentru aceasta, introduceţi în câmpul Field al grilei QBE expresia:
Luna: “Luna angajării este “ & Format ([Data Angajării],
“mmm”) , unde:
• Luna: este numele coloanei care va conţine, în tabela de
rezultate, valorile expresiei;
• “Luna angajării este “ este textul care va apărea înaintea
lunii angajării;
• Format ([Data Angajării], “mmm”) converteşte valoarea
stocată în câmpul Data Angajării la formatul mmm.
Funcţia Now () returnează data şi ora curentă în funcţie de
ceasul sistemului. O funcţie asemănătoare este Date (), care
returnează doar data curentă.
Notă: dacă observaţi că informaţiile returnate sunt eronate,
verificaţi data şi ora sistemului (în Control Panel, la secţiunea
Date/Time), deoarece funcţiile Now () şi Date () se bazează pe
acestea.
3.5. Funcţia IIF în expresii
Sintaxa funcţiei IIF este următoarea:
IIF (<Expresie>, valoare1, valoare2)
Unde:
• este o expresie a cărei valoare de adevăr este evaluată pentru
fiecare înregistrare în parte.;
• valoare1 este valoarea returnată dacă <expresie> este
adevărată;
• valoare2 este valoarea returnată dacă <expresie> este falsă.
Astfel, să presupunem câmpul pentru fiecare student dorim să aflăm
dacă a promovat sau nu oate cursuriile opţionale la care s-a înscris
(adică, dacă nota minimă obţinută este sau nu mai mare sau egală
cu 5). În tabela cu rezultatele interogării vom avea o coloană,
numită Situaţia, care va avea valoarea “promovat” sau
“Nepromovat”. Expresia care dă valorile acestei coloanea este
următoarea:
Situaţia: IIf (Min ( [ Nota ] )>= 5, “promovat”, “nepromovat”
3.6. Strategii de parcurgere a tabelelor de bază
Access Jet Engine poate alege una dintre următoarele 3 strategii
pentru parcurgerea datelor din tabelele de bază:
• Parcurgerea secvenţială: este, de obicei, cea mai puţin rapidă
metodă, deoarece sunt citite toate înregistrările din tabela de
bază, şi, pentru fiecare înregistrare sunt verificate restricţiile.
Această metodă este aleasă pentru tabele mici şi neindexate.
• Parcurgerea pe indecşi: Această metodă este aleasă atunci cînd
există restricţii asupra unei coloane indexate dintr-o tabelã de
bază. După ce subnt selectate doar înregistările pentru care sunt
verificate aceste restricţii, aceste înregistrări vor fi supuse şi
restului de restricţii (dacă există). Această metodă este
eficientă atunci când tabelele de bază sunt mari, astfel încât,
deşi se vor citi aceleaşi înregistrări de mai multe ori, timpul
total este mai mic decât cel necesar pentru a citi întraga tabelă.
• Tehnica restricţionării Rushmore: este aplicată atunci când
există restricţii asupra mai multor coloane indexate. Prin folosirea
mai multor indecşi, motorul Jet reduce considerabil numărul de
înregistrări ce trebuie citite. În funcţie de tipul restricţiei,
Jet engine va efectua una dintre următoarele 3 operaţii:
• intersecţia indecşilor: pentru restricţii de forma:
unde col1 şi col2 sunt coloane indexate. Pentru fiecare restricţie
este creată câte o mulţime de rezultate, care apoi sunt intersectate
pentru a găsi înregistrările ce verifică ambele restricţii.
• reuniunea indecşilor: pentru restricţii de forma:
• col1 = <exp> OR col2 = <exp>
• unde col1 şi col2 sunt coloane indexate. Pentru fiecare
restricţie este creată câte o mulţime de rezultate, care apoi sunt
reunite pentru a găsi înregistrările ce verifică ce verifică cel
puţin una dintre cele 2 restricţii.
• numărarea indecşilor: pentru interogări ce returnează numărul
înregistrprilor ce verifică o anumită mulţime de restricţii:
• SELECT Count (*) FROM Tabela
• WHERE col1 = <exp> AND col2 = <exp>
• Pentru astfel de interogări, Jet Engine nu trebuie decât să
citească paginile cu indecşi.
3.7. Greşeli frecvente
În continuare, vă prezentăm câteva dintre greşelile cel mai des
întâlnite la crearea interogărilor şi care pot duce la mărirea
semnificativă a timpului de execuţie.
• Expresii în coloanele rezultat: motorul Jet Engine nu poate
optimiza interogările care conţin expresii de tip IIF pentru
coloanele rezultat. Folosiţi expresiile la nivelul controalelor din
rapoartele sau formularele care vor folosi rezultatele interogării.
• Prea multe coloane cu clauza GROUP BY: când creaţi o interogare
de tip Totals, impuneţi clauza Group By asupra cât mai puţinor
coloane. Astfel, timpul de execuţie va fi mai redus.
• Indexarea coloanei de asociere pentru o singură tabelă: când
folosiţi o asociere între 2 tabele, indexaţi c-mpurile de asociere
din ambele tabele.
• Folosirea insuficientă a indecşilor: dacă nu se efectuează
modificări frecvente asupra datelor, este bine să folosiţi indecşi
pentru coloanele de asociere sau pentru coloanele asupra cărora se
impun restricţii. Altfel, indecşii pot îngreuna sensibil operaţiile
de actualizare a datelor.
3.8. Importanţa compactării
Compactarea unei baze de date este o operaţie asemănătoare
defrag¬mentării discurilor fizice. Pe măsură ce ştergeţi obiecte
sau înregistrări din baza de date, vor rămâne spaţii nefolosite
care măresc dimensiunile fişierului şi scad performanţele
acţiunilor. Singurul mod în care pot fi eliminate aceste spaţii este
comanda Database Utilities | Compact Database. Astfel, vor fi reînoite
statisticile asupra tabelelor, vor fi reordonate înregistrările din
tabele, iar spaţiul liber va putea fi folosit. În consecinţă, vor
creşte şi performanţele interogărilor, despre care am mai spus că
sunt cel mai important instrument pus la dispoziţia programatorilor
şi fără de care bazele de date nu şi-ar mai afla utilitatea.
CAP: 4. Crearea şi lucrul cu formularele
Formularele oferă unei baze de date o interfaţă prietenoasă şi
elegantă, prin care programatorul poate controla acţiunile
utilizatorului. Un formular are peste 70 de proprietăţi, la care se
adaugă cele ale controalelor, între 38 şi 58 pentru fiecare.
Principalul rol al formularelor este introducerea datelor, dar ele pot
folosi şi la regăsirea datelor sau afişarea meniurilor, a ecranelor
de tip splash etc.
Sursele de înregistrări ale formularelor indică de unde provin sau
unde vor fi stocate datele şi sunt specificate printre proprietăţile
formularelor.
Pentru a vedea pagina de proprietăţi a unui formular deschis în
modul Design View, faceţi clic pe butonul selector care se află în
colţul din stânga-sus al formularului şi apoi selectaţi comanda
View Properties sau apăsaţi butonul Properties pe bara cu
instrumente.
Notă: Pentru a vedea pagina de proprietăţi a unui control al
formularului, faceţi clic pe el pentru a-l aduce în prim plan şi
apoi alegeţi comanda View Properties sau apăsaţi butonul
Properties de pe bara cu instrumente.
4.1 Sursele de înregistrări ale formularelor
Sursa de înregistrări a unui formular poate fi o tabelă, o
interogare sau o instrucţiune SQL, specificată în proprietatea
Record Source a formularului respectiv.
Figura 4.1.
În figura 4.1 observaţi că în dreapta câmpului proprietăţii
Record Source se află două mici butoane. Dacă faceţi clic pe primul
(cel reprezentat de o săgeată), se va deschide o listă cu toate
tabelele şi interogările din baza de date curentă, dintre care veţi
selecta sursa de înregistrări. Pentru a modifica sursa de date a unui
formular apăsaţi cel de al doilea buton din dreptul proprietăţii
Record Source (cel reprezentat prin trei puncte…) care va deschide
fereastra SQL Ouery Builder (figura 4.2). Aceasta se aseamănă cu
fereastra QBE atât ca aspect, cât şi ca funcţionare.
Figura IV.2.
Dacă formularul se bazează pe o interogare, modificările aduse
acesteia în fereastra SQL Builder se vor reflecta şi în interogarea
propriu-zisă.
După cum am arătat în capitolele precedente, există două tipuri
de interogări: pentru regăsirea datelor şi pentru definirea şi
modificarea datelor. Dintre acestea, numai interogările pentru
regăsirea datelor (de tip SELECT) pot servi drept sursă de
înregistrări pentru un formular.
Dacă vă întrebaţi ce să alegeţi ca sursă de date pentru un
formular dintre o interogare salvată şi o instrucţiune SQL,
răspunsul este următorul: dacă interogarea este complexă,
salvaţi-o şi apoi alegeţi-o în câmpul proprietăţii Record
Source; dacă este simplă, introduceţi instrucţiunea SQL
corespunzătoare direct în câmpul proprietăţii Record Source a
formularului. Formularele bazate pe interogări salvate sunt mai
rapide, dar aceste interogări sporesc numărul de obiecte din baza de
date, făcând-o să ocupe mai mult spaţiu.
4.2. Crearea unui formular simplu
Access vă pune la dispoziţie două componente pentru crearea
formularelor simple: AutoForm Wizard, pentru crearea automată a
formularelor şi Form Wizard, ce îi dă programatourlui mai multă
libertate de decizie. Pe lângă acestea, puteţi crea formulare şi
singuri, pornind de la zero, în modul Design View.
Formularele create automat cu ajutorul vrăjitorului AutoForm wizard,
conţin câte un control (câmp) pentru fiecare coloană a tabelei sau
a interogării pe care sunt bazate. În partea dreaptă a fiecărui
câmp există o denumire (etichetă) care este dată de valoarea
prorietăţii Label a coloanei respective. Controlul corespunzător
unei coloane este cel specificat în proprietatea Display Control a
coloanei respective şi poate fi Text Box, Combo Box, List Box sau
Check Box, în funcţi de tipul de date.
Figura 4.3. prezintă formularul DetaliiProfesor, creat automat şi
care se bazează pe interogarea DetaliiProf din figura 4.2.
Figura IV.3.
Puteţi alge tiparul, adică fundalul implicit şi fontul şi culoarea
implicită a etichetelor folosite de AutoForm Wizard la crearea
automată a formularelor. Pentru aceasta, deschideţi formularul în
modul Design View, efectuaţi modificările dorite şi alegeţi comanda
AutoFormat.
Spre deosebire de vrăjitorii pentru crearea automată a formularelor
(AutoForm Columnar Wizard, AutoForm Tabular Wizard şi AutoForm
Datasheet Wizard, care diferă prin modul în care sunt prezentate
datele în formular), vrăjitorii de tip Form Wizard (Form Wizard,
Chart Wizard şi Pivot Table Wizard) îi dau programatorului
posibilitatea de a specifica tabelel sau interogările pe care se va
baza formularul, câmpurile acestora care vor apărea pe formular,
ordinea de sortare a datelor, fundalul etc.
Notă: Dacă folosiţi mai multe tabele şi interogări ca sursă de
înregistrări pentru un formular, între acestea trebuie să fie
stabilite relaţii.
Apăsând butonul „Create form by using wizard” din pagina Forms a
ferestrei Database Container, se va deschide fereastra de dialog
(figura 4.4), în care veţi alege vrăjitorul care vreţi să vă
ajute la crearea unui nou formular.
Figura 4.4.
După ce aţi ales opţiunea Form Wizard, acest vrăjitor vă va
prezenta succesiv patru cutii de dialog, în care veţi putea alege
câmpurile dorite din una sau mai multe tabele sau interogări din baza
de date (între care trebuie să existe relaţii), modul cum vor fi
prezentate datele (pe o singură coloană (Columnar), sub formă de
tabel (Tabular), ca în modul Datasheet View (Datasheet) sau aliniate
atât la stânga cât şi la dreapta formularului (Justified)),
fundalul şi, în final, numele formularului.
Dacă doriţi să creaţiun formular pornind de la zero, fără nici
un ajutor, în cutia de dialog New Form alegeţi opţiunea „Create
Form in Design View”. Astfel, se va deschide un formular fără nici
un control, urmând ca dumneavoastră să adăugaţi controalele
dorite, folosind cutia de instrumente (Toolbox).
4.3. Secţiunile unui formular
Un formular Access poate avea între una şi cinci secţiuni. Iată
care sunt acestea (prezentate şi în figura 4.5):
Figura IV.5
• Detail – Această secţiune conţine datele din fiecare
înregistrare a sursei de date. Pentru a trece de la o înregistrare la
alta veţi folosi butoanele de navigare ale formularului.
• Form Header – Această secţiune apare întotdeauna în partea de
sus a formularului. Aici puteţi include informaţii care nu se
schimbă în funcţie de fiecare înregistrare, cum ar fi un antet sau
un control ce nu are legătură cu înregistrarea curentă, precum şi
o casetă combinată folosită pentru filtrarea înregistrărilor.
• Form Footer - Această secţiune apare în partea de jos a unui
formular. Aici puteţi include informaţii despre data şi ora la care
a fost creat formularul sau totalurile coloanelor unui formular
tabelar.
• Page Header – Această secţiune apare între Form Header şi
Detail. Formularele care conţin un număr mare de controale pot fi
împărţite cu ajutorul unui control de tip Page Break în două sau
mai multe pagini, pentru a fi afişate pe rând. Secţiunile Page
Header şi Page Footer vor rămâne nemodificate când se trece de la o
pagină la alta a formularului.
• Page Footer – Această secţiune apare între Detail şi Form
Footer şi se aseamănă cu secţiunea Page Header.
4.4. Lucrul cu formularele
Un formular o dată creat poate fi deschis în mai multe feluri: din
pagina Forms a ferestrei Database Container, din alt formular (cu
ajutorul unui buton), dintr-un macro sau cu ajutorul limbajului VBA.
Principalul rol al formularelor este acela de a împiedeca utilizatorul
să interacţioneze direct cu tabelele sau cu tabelele de rezultate ale
interogărilor din baza de date. De aceea, pentru a reduce cât mai
mult contactul utilizatorului cu fereastra Database Container şi cu
obiectele sale, cel mai elegant mod de a deschide un formular este prin
intermediul unui buton din alt formular. Astfel, un exemplu clasic de
formular folosit pentru a lansa alte formulare este acela al unui meniu
ce conţine mai multe butoane, prin intermediul cărora utilizatorul
putea deschide diferite alte formulare.
Indiferent de cum a fost deschis un formular, veţi putea face
trecerea la oricare dintre cele trei moduri în care poate fi văzut
formularul: Design View (pentru a lucra cu controalele formularului),
Datasheet View (pentru a avea acces numei la datele pe care se bazează
formularul) sau Form View (pentru a vedea formularul în forma sa
finală), alegând una dintre aceste comenzi din meniul View.
Într-un formular puteţi naviga atât între controale, cât şi
între înregistrări. Cu ajutorul tastei Tab puteţi trece de la un
control la altul. Pentru a stabili ordinea în care se face această
trecere, alegeţi comanda View Tab Order.
Pentru a trece la înregistrarea următoare, treceţi la ultimul
control de pe formular şi apoi apăsaţi tasta Enter. Un alt mod de a
trece de la o înregistrare la lata este prin folosirea tastelor Page
Up şi Page Down. Mult mai simplu este însă să folosiţi butoanele
pentru navigarea printre înregistrări. Aceste butoane apar în
colţul din stânga jos al unui formular, dacă în pagina de
proprietăţi a acestuia proprietatea Navigation Buttons are valoarea
Yes.
Tot în pagina de proprietăţi a unui formular veţi găsi şase
proprietăţi ce vă permit să controlaţi acţiunile utilizatorului
asupra datelor pe care se bazează formularul:
• Allows Edits: Dacă are valoarea Yes, utilizatorul va putea
modifica înregistrările; dacă are valoarea No, aceasta nu va putea
schimba în nici un fel datela afişate în formular.
• Allow Deletions: Dacă are valoarea Yes, utilizatorul va putea
şterge înregistrări, cu condiţia ca integritatea referenţială să
nu fie violată.
• Allow Additions: Dacă are valoarea Yes, utilizatorul va putea
introduce noi înregistrări prin intermediul formularului.
• Data Entry: dacă are valoarea Yes, formularul deschide automat o
înegistrare nouă, fără date. Utilizatorul nu are acces la
înregistrările existente. Dacă proprietatea Alow Additions are
valoare No, iar Data Entry are valoarea Yes, va rezulta o eroare.
• Recordset Type: Poate fi Dynaset, Dynaset (Inconsistent Updates)
sau Snapshot. Se referă la formularele ce au mai multe tabele ca
sursă de date. Dacă valoarea este Dynaset, datele din controalele
asociate câmpurilor vor putea fi editate de către utilizator, ceea ce
nu este valabil în cazul valorii Snapshot.
• Record Locks: Se referă la aplicaţii multiuser. Dacă are
valoarea No Locks, mai mulţi utilizatori vor putea modifica aceleaşi
înregistrări în acelaşi timp, fiind luate în considerare numai
modificările care au fost salvate primele. Opţiunea Edited Records
împiedică ceilalţi utilizatori de a opera schimbări asupra unei
înregistrări care este deja în curs de modificare. Opţiunea All
Records blochează toate înregistrările din formular şi din tabelele
de bază atâta timp cât un utilizator editează orice înregistrare
din tabelă.
O dată ce au fost făcute modificări asupra unei înregistrări
dintr-un formular, acestea vor fi salvate fie când se trece la
înregistrarea următoare, fie când se închide formularul.
Proprietăţile din pagina Format a ferestrei de proprietăţi a
formularului controlează aspectul acestuia. Printre ele se numără:
• Caption: Păstrează textul ce va fi afişat în bara de titlu a
formularului.
• Default View: Stabileşte dacă formularul va fi afişat în modul
Single Form (cel mai des folosit), Continuos Form sau Datasheet.
• Views Allowed: Stabileşte dacă utilizatorul poate trece din modul
Form View în modul Datsheet View.
• ScrollBars: Stabileşte dacă formularul are bare de derulare
verticale şi/sau orizontale.
• RecordSelectors: Dacă valoarea sa este Yes, pe latura din stânga
a secţiunii Detail va apărea un selector pentru înregistrări.
• NavigationButtons: Dacă valoarea este Yes, formularul va fi dotat
cu butoane pentru parcurgerea înregistrărilor.
• RecordDividers: Dacă valoarea este Yes, în modul Continuos va
apărea o linie de separare între înregistrări.
• AutoResize: Dacă valoarea este Yes, fereatra formularului va fi
dimensionată corespunzător la fiecare deschidere a acestuia.
• AutoCenter: Dacă valoarea este Yes, la deschidere formularul va
apărea centrat pe ecran.
• ControlBox: Dacă valoarea este Yes, caseta de control va apărea
în partea din stânga a barei de titlu.
• MaxMinButtons: Precizează dacă butoanele Minimize şi Maximize
vor fi incluse în bara de titlu. În acest caz, valoarea
proprietăţii WhatsThisButton trebuie să fie No.
• CloseButton: Dacă valoarea este Yes, butonul (X) pentru
închiderea formularului va fi inclus în partea dreaptă a barei de
titlu.
• WhatsThisButton: Dacă valoarea este Yes, butonul (?) va apărea
în partea din dreapta a barei de titlu în cazul în care şi
CloseButton are valoarea Yes.
Pe lângă acestea, ar fi mai interesant să menţionăm două dintre
cele mai importante proprietăţi din pagina Other a ferestrei
Properties:
• Pop Up: Dacă valoarea sa este Yes, formularul va fi afişat
deasupra altor ferestre, putând fi mutat şi în afara ferestrei
Access.
• Modal: Dacă valoarea sa este Yes, alte ferestre deschise nu pot
primi controlul până când formularul nu este închis.
4.5. Despre controale
Fiecare element de pe un formular este un control de un anumit tip.
Puteţi adăuga controale la un formular deschis în modul Design View
folosind cutia de instrumente Toolbox, pe care o puteţi vedea alegând
comanda View Toolbox sau apăsând butonul Toolbox de pe bara de
instrumente. Majoritatea butoanelor din Toolbox reprezintă un tip de
control ce poate fi plasat pe un formular. Figura V.6 prezintă cutia
de instrumente Toolbox şi descrie componentele sale.
Pentru a plasa un control din Toolbox pe un formular, faceţi clic pe
butonul corespunzător tipului de control dorit, după care faceţi
clic pe formular. O dată adăugat, controlul poate fi redimensionat
în funcţie de necesităţi. Puteţi selecta un control sau un grup de
controale cu ajutorul săgeţii din cutia cu scule. Alegeţi săgeata
şi apoi trasaţi un dreptunghi în jurul controalelor pe care doriţi
să le selectaţi. O altă metodă ar fi să ţineţi tasta Shift
apăsată în timp ce faceţi clic pe controalele respective.
Pentru a stabili proprietăţile şi comportamentul unui control,
Access vă pune la dispoziţie vrăjitorul control Wizard, care va fi
activat atunci când controlul este plasat pe formular, dacă butonul
Control Wizard din cutia de scule este apăsat (ca în figura 4.6).
Figura IV.6
4.5.1. Tipuri de controale
Există trei tipuri de controale ce pot fi plasate pe un formular:
ataşate, neataşate şi calculate.
Controale neataşate
Un control este folosit pentru a furniza sau primi de la utilizator
informaţii ce nu sunt sau nu vor fi stocate în baza de date. Iată
câteva exemple de astfel de controale:
• O etichetă ce descrie alt control;
• Un buton prin care se deschide un alt formular;
• Un bitmap ce face formularul mai atractiv etc.
Controale ataşate
Controalele ataşate sunt folosite pentru a afişa sau edita
informaţii din baza de date şi lor le corespunde câte un câmp
dintr-o tabelă sau un câmp returnat de o interogare sau instrucţiune
SQL. Orice control poate fi ataşat, cu excepţia dreptelor,
dreptunghiurilor, sfârşitului de pagină, etichetelor şi cadrelor
pentru imagini.
Un control ataşat va moşteni multe dintre proprietăţile câmpului
corespunzător (cum ar fi Caption, Description, Input Mask, Format),
dar aceste proprietăţi pot fi modificate prin intermediul paginii de
proprietăţi a controlului.
Pentru a plasa un control ataşat pe un formular procedaţi astfel:
1. Alegeţi comanda View Field List pentru a afişa câmpurile
sursei de date pe care se bazează formularul.
2. Selectaţi un câmp sau un grup de câmpuri din această listă.
3. Faceţi drag & drop cu selecţia pe formular. Astfel, pentru fiecare
câmp selectat va apărea pe formular un control şi o etichetă ce va
afişa textul din proprietatea Caption a câmpului corespunzător.
Puteţi transforma un control neataşat într-unul ataşat folosind
proprietatea Control Source a controlului respectiv, în care să
specificaţi câmpul corespunzător.
Controale calculate
Controalele calculate folosesc expresii pentru a-şi obţine datele.
Deşi casetele text sunt cel mai frecvent întâlnite controale de
acest tip, orice alt fel de control ce are proprietatea Control Source
poate fi calculat. Orice expresie trebuie să înceapă cu semnul egal
(=). De exemplu, dacă în formularul DetaliiProfesor dorim să avem un
câmp ce calculează impozitul din salariul afişat în controlul
Salariu, expresia folosită va fi:
=[Salariu]*0.12
Această expresie poate fi introdusă direct în control dacă acesta
este o casetă text sau în câmpul proprietăţii Control Source a
controlului.
4.5.2. Casete combinate, casete listă şi grupuri de opţiuni
În continuare, vă vom arăta cum puteţi să profitaţi de ajutorul
oferit de vrăjitorul Control Wizard pentru lucrul cu controalele de
tip casetă combinată, casetă listă şi grup de opţiuni. Dacă
butonul Control Wizard din cutia de instrumente este apăsat, prin
plasarea pe formular a unui control de tipul celor enumerate anterior,
se va activa vrăjitorul corespunzător (Combo Box Wizard, List Box
Wizard sau Option Group Wizard).
Vrăjitorii pentru casete combinate şi casete listă sunt foarte
asemănători cu vrăjitorul Lookup Wizard, care vă ajută să creaţi
într-o tabelă o coloană ale cărei valori proveaneau din altă
tabelă sau dintr-o listă specificată de dumneavoastră. Pentru a
ilustra lucrul cu ei, ne vom întoarce la formularul DetaliiProf care
trebuie să fie deschis în modul Design View. Să presupunem că în
locul casetei text Titlu vom introduce o casetă combinată din care
utilizatorul să poată alege una dintre valorile din coloana Titlu a
tabelei cu acelaşi nume. Ştergeţi aşadar controlul Titlu de pe
formular (faceţi clic pe el pentru a-l selecta şi apoi apăsaţi
tasta Del) şi adăugaţi un control de tip Combo Box. În prima cutie
de dialog a vrăjitorului Combo Box Wizard alegeţi prima opţiune,
prin care specificaţi că valorile controlului vor proveni dintr-o
tabelă sau interogare. În a doua cutie de dialog va trebui să
alegeţi tabela sau interogarea respectivă, în speţă, tabela Titlu.
În cea de-a treia cutie de dialog veţi alege câmpurile din tabela
Titlu ce vor da valorile din caseta combinată. Deoarece în listă
dorim să fie afişate titlurile din coloana Titli, dar în tabela
Profesor se vor stoca doar identificatorii din coloana IdTitlu, aici
vom selecta atât coloana Titlu, cât şi IdTitlu. În cea de-a patra
cutie de dialog veţi ajusta, eventual, lăţimea listei şi veţi
lăsa validată caseta Key Column, deoarece nu doriţi ca în listă
să apară şi valorile coloanei IdTitlu. Cea de-a cincea cutie de
dialog vă întreabă dacă valorile selectate în caseta combinată
vor fi memorate pentru a fi folosite ulterior sau vor fi stocate în
baza de date. Alegeţi a doua opţiune şi specificaţi că valorile
vor fi stocate în coloana IdTitlu. Ultima cutie de dialog vă lasă
să introduceţi textul etichetei plasat în dreptul casetei combinate.
Scrieţi “Titlu” şi apăsaţi butonul Finish pentru a închide
vrăjitorul şi a crea controlul. Treceţi apoi în modul Form View şi
testaţi formularul (figura 4.7).
Figura IV.7
Să privim pagina de proprietăţi a casetei combinate Titlu pentru a
înţelege ce a făcut Combo Box Wizard (figura 4.8). În câmpul
proprietăţii Row Source Type este selectată valoarea Table / Query,
deoarece valorile din lista casetei combinate provin dintr-o tabelă,
interogare sau instrucţiune SQL. Proprietatea Row Source specifică
această instrucţiune:
SELECT DINCTINCROW [Titlu].[IdTiltu], [Titlu].[Titlu] FROM [Titlu];
Proprietatea Control Source specifică exact coloana din care provin
datele din caseta combinată: IdTitlu. Atunci când veţi dori să
introduceţi în tabela Profesor date despre un nou profesor prin
intermediul acestui formular, în coloana IdTitlu a tabelei Profesor va
fi stocată valoarea lui IdTitlu din tabela Titlu, în funcţie de
alegerea dumneavoastră din caseta combinată.
Figura IV.8
În continuare, vom adăuga formularului DetaliiProf un grup de
opţiuni cu ajutorul vrăjitorului Option Group Wizard. Pentru aceasta,
va trebui să adăugăm o nouă coloană la tabela Profesor şi anume
Statut, de tip Number (FieldSize=Integer) şi care va avea valoarea 1
dacă profesorul este titular sau 0 dacă este suplinitor. De asemenea,
va trebui să modificăm şi sursa de date a formularului (interogarea
DetaliiProf) astfel încât ea să conţină şi această coloană.
Deschideţi din nou formularul DetaliiProf în modul DesignView şi,
din cutia de instrumente selectaţi controlul de tip grup de opţiuni.
Dacă butonul Control Wizard din cutia de instrumente este apăsat,
când veţi plasa controlul pe formular, se va activa vrăjitorul
Option Group Wizard. În prima cutie de dialog a vrăjitorului veţi
specifica etichetele fiecărui buton de opţiune: “Titular” şi
“Suplinitor”. În următoarea cutie de dialog veţi alege care
dintre cele două opţiuni să fie implicită: alegeţi opţiunea
Titular. În cea de-a treia cutie de dialog veţi introduce valorile
corespunzătoare opţiunilor, valori ce vor fi stocate în tabelă: 1
pentru Titular şi 0 pantru Suplinitor. Următoarea cutie de dialog ne
cere să specificăm dacă valorile vor fi stocate într-o tabelă, şi
dacă da, în ce câmpuri. Alegeţi aici coloana Statut şi apăsaţi
Next. Următoarea cutie de dialog ne propune diferite tipuri de
controale ce pot apărea într-un grup de opţiuni. Selectându-le, le
veţi putea vedea în partea stângă a cutiei de dialog. Acceptaţi,
de exemplu, varianta implicită şi treceţi la ultima cutie de dialog
în care va trebui să introduceţi denumirea grupului de opţiuni
(să-i spunem “Statutul”). Pentru a vedea funcţionarea grupului de
opţiuni treceţi în modul Form View şi testaţi formularul. El va
arăta ca în figura 4.9.
Pentru ca la introducerea datelor să nu poată apărea neconcordanţe
între caseta combinată Titlu şi câmpul IdTitlu al formularului,
daţi proprietăţii Locked a casetei text IdTitlu valoarea Yes, astfel
încât valorile sale să nu poată fi modificate direct de către
utilizator.
Figura IV.9
Să vedem acum ce a făcut Option Group Wizard. Observaţi că grupul
conţine două butoane de opţiune, ale căror etichete sunt
“Titular” şi “Suplinitor”. Din pagina de proprietăţi a
grupului de opţiuni (figura IV.10), merită să remarcăm valoarea
proprietăţii Control Source, şi anume coloana Statut. De asemenea,
proprietatea Default Value are valoarea 1, corespunzătoare opţiunii
Titular (aşa cum am specificat în cea de-a doua cutie de dialog a
vrăjitorului). Din pagina de proprietăţi a primului buton de
opţiune, Titlu, remarcăm doar că valoarea 1 pe care o specificasem
în cea de-a treia cutie de dialog a vrăjitorului se regăseşte în
valoarea proprietăţii Option Value. Analog, valoarea 0
corespunzătoare opţiunii Suplinitor se regăseşte în valoarea
proprietăţii Option Value a celui de-al doilea buton de opţiune.
Figura IV.10
4.6. Subformulare
Atunci când avem două tabele între care există o relaţie de tip
1:m, poate fi avantajos să putem lucra cu amândouă prin intermediul
unui singur formular. De exemplu, tabelele Profesor şi Titlu sunt
legate printr-o astfel de relaţie, coloana de legătură fiind
IdTitlu. Ar fi interesant ca, atunci când obţinem informaţii despre
titlul de lector, să putem vedea şi toţi profesorii care au acest
titlu.
Pentru aceasta, vom crea un formular ce va conţine un subformular.
Formularul părinte va lucra cu datele din tabela aflată în partea
(1) a relaţiei, iar subformularul, cu cele ale tabelei din partea (m).
Access recunoaşte faptul că între cele două tabele este definită o
relaţie şi, pentru o anumită înregistrare din tabela Titlu,
limitează înregistrările din subformular la cele pentru care
valorile câmpului de legătură din cele două tabele sunt egale.
Puteţi avea maximum două niveluri de imbricare a subformularelor şi
oricâte subformulare pe acelaşi nivel de imbricare. Access 97 vă
pune la dispoziţie un instrument foarte prietenos pentru crearea de
formulare cu subformulare: Form Wizard. Paşii pe care trebuie să-i
parcurgeţi pentru aceasta sunt următorii:
1. În pagina Forms a ferestrei Database alegeţi butonul New şi apoi,
din cutia de dialog New Forms, alegeţi Form Wizard.
2. În prima cutie de dialog a Vrăjitorului, selectaţi din caseta
combinată Tables/Queries tabela Profesor şi apoi, din lista Available
Fields alegeţi coloanele Nume, Catedra şi Data Angajării. Selectaţi
apoi din caseta combinată rabela Titlu şi coloanele Titlu şi
Salariu.
3. Pe baza datelor pe care le-aţi selectat, Access îşi dă seama că
doriţi să creaţi un formular bazat pe două tabele între care
există o relaţie de tip1:m şi vă pune la dispoziţie trei moduri de
a vizualiza aceste date. Dacă în cea de-a doua cutie de dialog din
Wizard alegeţi ca datele să fie prezentate în funcţie de tabela
Profesor, atunci formularul va fi de tip Single Form, adică datele din
cele două tabele vor fi afişate într-un singur formular. Dacă
alegeţi ca datele să fie prezentate în funcţie de tabela Titlu,
atunci puteţi opta între 2 posibilităţi: Linked Forms (formulare
legate) (în acest caz vor fi create două formulare separate, cel care
se bazează pe tabela din partea (1) a relaţiei având un buton, pe
care dacă apăsaţi se va deschide formularul bazat pe tabela din
partea (m) a relaţiei) şi Form with subform(s) (formular cu
subformulare). Alegeţi această ultimă posibilitate.
4. Următoarele cutii de dialog din Wizard se ocupă cu
caracteristicile grafice ale formularului.
Pentru a înţelege legătura dintre formularul părinte şi
subformular, să le privim în modul Design View. Observaţi,că
formularul părinte, Titlu_Profesori are, în plus faţă de casetele
text Titlu şi Salariu şi etichete corespunzătoare acestora, un
control de tip Subform/Subreport. Legătura între cele două formulare
se face prin intermediul a două proprietăţi ale controlului de tip
Subform/Subreport: Link Child Fields şi Link Master Fields care
specifică numele coloanelor de legătură ce formează cheia străină
în tabela din partea (m) şi, respectiv, ale coloanelor ce formează
cheia primară a tabelei din partea (1) a relaţiei. Mai observaţi
faptul că proprietatea Source Object are ca valoare numele
subformularului (Profesori Subform).
Un subformular poate fi adăugat unui formular părinte şi fără
ajutorul lui Form Wizard. Nu trebuie decât să trageţi numele
subformularului din pagina Forms a ferestrei Database Container peste
formularul principal deschis în modul Design View şi apoi să
stabiliţi proprietăţile Link Child Fields şi Link Master Fileds ale
controlului de tip Subform/Subreport care va conţine subformularul.
Altă metodă ar fi să selectaţi din cutia de instrumente un control
de tip Subform/Subreport şi să-i stabiliţi în mod corespunzător
proprietăţile Link Child Fields, Link Master Fileds şi Source
Object.
CAP: 5. Modelul orientat pe evenimente
Microsoft Access vă permite dezvoltarea de aplicaţii orientate pe
evenimente. Un astfel de eveniment este o acţiune pe care aplicaţia o
recunoaşte (cum ar fi apăsarea unei taste, efectuarea unui clic cu
mouse-ul, deschiderea unui formular sau raport etc.) şi care
generează un anumit răspuns. Răspunsul poate fi executarea unei
macrocomenzi, a unei proceduri VBA sau evaluarea unei expresii.
Evenimentele sunt declanşate de acţiunile utilizatorului. Obiectele
supuse evenimentelor sunt formularele, rapoartele şi controalele
acestora. Astfel, aplicaţiile Access trebuie să fie proiectate în
aşa fel încât să răspundă evenimentelor declanşate de
utilizator.
Pentru a răspunde unui anumit eveniment, trebuie să îi atribuiţi o
macrocomandă, o procedură sau o expresie. Acest lucru îl puteţi
face în pagina Event a ferestrei Properties a obiectului respectiv
(figura 5.1).
Ordinea în care se execută codul aplicaţiei este astfel
determinată de ordinea în care sunt invocate evenimentele prin
acţiunile utilizatorului. Aceasta este esenţa programării orientate
pe evenimente: utilizatorul este cel care efectuează anumite acţiuni,
iar aplicaţia răspunde în consecinţă, prin intermediul codului
scris de programator. La acest lucru trebuie să vă gândiţi mereu
atunci când creaţi o aplicaţie Access (sau o aplicaţie Windows în
general). Cu alte cuvinte, programatorul trebuie să facă o serie de
presupuneri pentru a determina comportamentul aplicaţiei. Spre
exemplu, puteţi presupune că utilizatorul va trebui să introducă o
valoare într-o casetă de text înainte de a putea să apese pe un
buton. Pentru aceasta, va trebui să dezactivaţi butonul respectiv
înainte ca utilizatorul să introducă o valoare în caseta de text.
Fig. 5.1
5.1. Tipuri de evenimente în Access
Access îi pune programatorului la dispoziţie mai multe tipuri de
evenimente ce pot fi declanşate de acţiunile utilizatorului şi
tratate de aplicaţie. În cele ce urmează, vom vorbi despre
evenimentele cel mai des întâlnite.
5.1.1. Evenimente generate de accesarea datelor
Aceste evenimente au loc ori de câte ori utilizatorul adaugă,
modifică sau şterge datele dintr-un formular ori control sau când
trece de la o înregistrare la alta.
• Current – Are loc la deschiderea unui formular sau când se trece
de la o înregistrare la alta.
• Delete – Are loc atunci când utilizatorul efectuează o
operaţie de ştergere a datelor, înainte ca datele să fie efectiv
şterse. Procedura pentru tratarea acestui eveniment are un parametru:
Cancel care, dacă are valoarea True, ştergerea nu va fi efectuată,
iar dacă are valoarea False, vor avea loc următoarele evenimente, în
ordine: Delete, Current (pentru accesarea înregistrării următoare),
BeforeDelConfirm, afişarea unei casete de mesaj pentru confirmarea
ştergerii, AfterDelConfirm.
• BeforeDelConfirm – Are loc după ce utilizatorul a şters una sau
mai multe înregistrări şi înainte ca sistemul să afişeze caseta
de mesaj pentru confirmare. Procedura pentru tratarea acestui eveniment
are doi parametri: Cancel şi Response. Dacă parametrul Cancel are
valoarea True, înregistrările nu vor mai fi şterse şi caseta de
mesaj nu va mai apărea. Dacă el are valoarea False, iar parametrul
Response are valoarea 0, ştergerea va fi efectuată fără a mai
apărea caseta de mesaj, iar dacă Response are valoarea 1, caseta de
mesaj va apărea.
• AfterDelConfirm – Are loc după confirmarea şi/sau ştergerea
înregistrărilor. Procedura pentru tratarea acestui eveniment are un
argument, Status, care poate avea valorile 0,1 sau 2. Valoarea 0 spune
că ştergerea a fost efectuată cu succes, 1 că Access a anulat-o şi
2 că utilizatorul a anulat-o.
• BeforeInsert – Are loc numai atunci când utilizatorul introduce
primul caracter al unei înregistrări noi, dar înainte ca
înregistrarea să fie inserată în tabelă. Procedura pentru tratarea
acestui eveniment are un argument, Cancel, care, dacă are valoarea
True, acţiunea de inserare va fi abandonată.
• AfterInsert – Are loc după inserarea unei înregistrări noi
într-o tabelă.
• BeforeUpdate – Apare înainte ca datele dintr-un control sau
dintr-o înregistrare să fie modificate efectiv. Procedura pentru
tratarea acestui eveniment are un argument, Cancel, care, dacă are
valoarea True, modificarea nu se va mai efectua.
• AfterUpdate – Are loc după ce au fost modificate datele dintr-un
control sau dintr-o înregistrare. Controalele ataşate au o anumită
proprietate, Old Value, care păstrează valoarea controlului dinaintea
modificării până după ce acest eveniment a avut loc. Astfel, aveţi
posibilitatea ca în procedura pentru tratarea acestui eveniment să
redaţi controlului vechea valoare astfel:
FORMS!formular!control = FORMS!formular!control.OldValue
• Change – Apare atunci când se efectuează o modificare într-o
casetă de text sau în câmpul de editare al unei casete combinate.
• NotInList – Este un eveniment specific casetelor combinate şi
poate apărea numai dacă proprietatea LimitToList a unui astfel de
control are valoarea Yes. Astfel, evenimentul are loc dacă
utilizatorul introduce în câmpul de editare al casetei combinate o
valoare care nu se regăseşte în lista acestuia. Procedura pentru
tratarea acestui eveniment are două argumente: NewData, care
păstrează valoarea nou introdusă de utilizator şi Response, care
poate avea valorile 0,1 sau 2. Valoarea 0 îi indică lui Access să
afişeze un mesaj standard pentru a înştiinţa utilizatorul că a
introdus o valoare care nu se află în lista casetei combinate, 1 îi
indică lui Access să nu afişeze masajul standard şi nici să nu
introducă noua valoare în listă (dându-vă posibilitatea de a
afişa un mesaj propriu), iar valoarea 2 îi indică lui Access să nu
afişeze mesajul standard şi să introducă noua valoare în listă.
În acest ultim caz, va trebui să introduceţi noua valoare şi în
sursa de date a casetei combinate.
• Updated – Are loc atunci când au fost modificate datele unui
obiect OLE şi este specific controalelor cadru pentru obiecte OLE
ataşate sau neataşate. Procedura pentru tratarea acestui eveniment
are un parametru, Code, care poate avea valorile 0, 1, 2 sau 3.
Valoarea 0 îi indică lui Access că datele obiectului au fost
modificate, 1 că datele au fost salvate de aplicaţia care a creat
obiectul, 2 că fişierul ce conţine obiectul OLE a fost închis de
aplicaţia care l-a creat, iar 3 că fişierul ce conţine obiectul a
fost redenumit de aplicaţia care l-a creat.
5.1.2. Evenimente legate de focus
Acestea apar atunci când un control, formular sau raport primeşte
sau pierde focusul (sau când devine activ sau inactiv).
• Enter – Are loc înainte ca un control să primească focusul de
la un alt control al aceluiaşi formular sau la deschiderea
formularului, pentru primul control al acestuia. Evenimentul apare
înaintea lui GotFocus şi după Current.
• Exit – Are loc înainte ca un control să piardă focusul în
favoarea altui control de pe formular, înaintea evenimentului
LostFocus.
Notă:Spre deosebire de evenimentele GotFocus şi LostFocus,
evenimentele Enter şi Exit nu vor avea loc dacă focusul trece la un
alt formular sau raport. Ele pot fi folosite pentru a afişa mesaje
înaintea actualizării controalelor sau pentru a schimba ordinea în
care se trece cu tasta Tab de la un control al formularului la altul.
• GotFocus – Apare atunci când un control de pe un formular
primeşte focusul sau când un formular primeşte focusul, dacă toate
controalele lui sunt dezactivate. Un control nu poate primi focusul
dacă este dezactivat sau dacă nu este vizibil. Acest eveniment are
loc după evenimentul Enter.
• LostFocus – Are loc atunci când un formular sau un control de pe
un formular pierde focusul, după apariţia evenimentului Exit (care
poate să aibă loc sau nu).
• Activate – Are loc atunci când un formular sau un raport
primeşte focusul şi devine activ. Aceasta se întâmplă la
deschiderea formularului sau a raportului, când se face clic pe un
control al său sau când este apelată procedura Visual Basic
SetFocus. Formularul sau raportul trebuie să fie vizibil pentru ca
evenimentul să aibă loc.
• Deactivate – Apare atunci când un formular sau raport pierde
focusul în favoarea altei ferestre (cum ar fi fereastra Database,
fereastra unei tabele, a unei macrocomenzi, a unui modul sau alt
formular sau raport). Acest eveniment nu are loc dacă focusul trece
către o cutie de dialog sau către altă aplicaţie.
5.1.3. Evenimente legate de tastatură
Acestea au loc la apăsarea unei taste sau ca rezultat al
instrucţiunii SendKeys.
• KeyDown – Apare de câte ori este apăsată o tastă atunci când
un control sau un formular are focusul.
• KeyUp – apare de câte ori o tastă care a fost apăsată se
relaxează (când un control sau formular are focusul).
Procedurile ce tratează aceste evenimente au două argumente: KeyCode
şi Shift. KeyCode are ca valoare un întreg ce reprezintă tasta care
a fost apăsată. Valoarea 0 nu corespunde nici unei taste. Argumentul
Shift are ca valoare un întreg ce arată dacă tastele Shift, Ctrl sau
Alt au fost apăsate în combinaţie cu alte taste. Valoarea 0 arată
că aceste taste nu au fost apăsate, 1 că a fost apăsată tasta
Shift, 2 pentru Ctrl, 4 pentru Alt. Dacă este apăsată o combinaţie
a acestor taste, valoarea parametrului Shift este suma valorilor
corespunzătoare.
• KeyPress – Apare atunci când o tastă sau o combinaţie de taste
ce corespund unui caracter ce poate fi tipărit este apăsată şi apoi
relaxată, pentru un control sau formular. El nu are loc la apăsarea
tastelor funcţionale (F1 – F12), a tastelor pentru navigare
(săgeţi, Home, End, Page Up, Page Down) sau Shift, Ctrl şi Alt.
Procedura pentru tratarea acestui eveniment are un argument, KeyAscii,
ce are ca valoare un întreg reprezentând codul caracterului
respectiv.
Notă: Folosiţi aceste evenimente cu precauţie, deoarece dacă o
tastă este ţinută apăsată, evenimentele KeyDown şi KeyPress au
loc repetat, ceea ce poate duce la terminarea resurselor sistemului.
Pentru a urmări acţiunile utilizatorului, puteţi folosi în schimb
evenimentele generate de accesarea datelor, cum ar fi Change şi
Updated.
5.1.4. Evenimente legate de activitatea cu mouse-ul
Apar atunci când se efectuează anumite acţiuni cu mouse-ul asupra
unui control sau formular.
• Click – Are loc atunci când se efectuează un clic cu mouse-ul
pe un formular sau pe un control ori pe o secţiune a unui formular.
Atunci când se face clic pe un control aflat în cadrul unui grup de
opţiuni, acest eveniment nu este al controlului respectiv, ci al
grupului. Acest eveniment mai apare şi în următoarele situaţii
(când nu se face clic cu mouse-ul):
- când este selectată o valoare din lista unei casete combinate cu
ajutorul săgeţilor şi este apăsată tasta Enter pentru a plasa
valoarea în câmpul de editare al casetei combinate;
- dacă este apăsată tasta Space atunci când o casetă de validare,
un buton de comandă sau un buton de opţiune are focusul;
- dacă se apasă tasta Enter pentru un formular care are un buton a
cărui proprietate Default are valoarea Yes sau dacă se apasă tasta
Esc pentru un formular cu un buton a cărui proprietate Cancel are
valoarea Yes;
- dacă se accesează un buton de comandă cu ajutorul comenzii sale
prescurtate (Alt + litera subliniată dintitlul butonului).
• DblClick– Are loc atunci când se face clic de două ori la rând
cu mouse-ul pe un formular, pe un control al lui sau pe o secţiune a
acestuia. Atunci când se face clic pe un control aflat în cadrul unui
grup de opţiuni, acest eveniment nu este al controlului respectiv, ci
al grupului. Procedura pentru tratarea acestui eveniment are un
argument, Cancel, care, dacă are valoarea True, evenimentul este
anulat.
• MouseMove – Apare atunci când utilizatorul mişcă mouse-ul.
Procedura pentru tratarea acestui eveniment are patru argumente: Button
(care arată care dintre butoanele mouse-ului a fost apăsat), Shift
(arată dacă au fost apăsate tastele Shift, Ctrl sau Alt), X şi Y
(care dau coordonatele curente ale cursorului mouse-ului). Argumentul
Button poate lua valorile: 0 dacă nu a fost apăsat nici unul dintre
butoanele mouse-ului, 1 dacă a fost apăsat butonul din stânga, 2
pentru cel din dreapta şi 4 pentru cel din mijloc. Dacă au fost
apăsate mai multe butoane o dată, valoarea lui Button va fi suma
valorilor corespunzătoare. Valorile argumentului Shift sunt aceleaşi
ca la procedurile pentru tratarea evenimentelor de la tastatură.
• MouseDown şi MouseUp – Au loc atunci când un buton al
mouse-ului este apăsat sau relaxat, în timp ce cursorul se află
deasupra unui formular, control al lui sau secţiune a acestuia.
Procedura pentru tratarea acestui eveniment are aceleaşi argumente ca
şi cea pentru tratarea lui MouseMove, cu diferenţa că argumentul
Button poate avea valorile: 1 (pentru butonul din stânga), 2 (pentru
butonul din dreapta) sau 4 (pentru butonul din mijloc). Dacă au fost
apăsate mai multe butoane o dată, vor avea loc tot atâtea evenimente
MouseDown şi MouseUp.
5.1.5. Evenimente legate de tipărire
Acestea au loc pentru fiecare secţiune a unui raport atunci când
acesta este tipărit sau este formatat pentru a fi tipărit.
• Format – Apare înainte ca Access să formateze fiecare secţiune
a unui raport, dar după ce datele au fost selectate. Pentru secţiunea
Detail, acest eveniment se produce pentru fiecare înregistrare în
parte. Procedura pentru tratarea acestui eveniment are două argumente:
Cancel şi FormatCount. Dacă argumentul Cancel are valoarea True, se
renunţă la formatarea secţiunii curente şi se trece la următoarea
secţiune. FormatCount reprezintă numărul de evenimente Format
produse pentru secţiunea curentă.
• Retreat – Apare atunci când Access trebuie să revină la o
secţiune anterioară a unui raport în timpul formatării. El are loc
după evenimentul Format şi înaintea evenimentului Print, pentru a
vă da posibilitatea de a modifica formatările făcute deja.
• Print – Are loc după formatare şi înainte de afişare sau
tipărire. Ca şi evenimentul Format, acest eveniment are loc pentru
fiecare secţiune în parte. Procedura de tratare are două argumente:
Cancel şi PrintCount. Dacă argumentul Cancel are valoarea True,
secţiunea sau înregistrarea curentă nu va mai fi tipărită.
PrintCount reprezintă numărul de apariţii ale acestui eveniment
pentru înregistrarea curentă. Astfel, puteţi afla dacă o
înregistrare va fi tipărită pe mai mult de o pagină şi puteţi
renunţa la ea.
5.1.6. Evenimentele ferestrelor
Acestea se produc atunci când o fereastră a unui formular sau raport
este deschisă, redimesionată sau închisă.
• Open – Se produce la deschiderea unui formular sau raport şi
înainte ca prima înregistrare a formularului să fie afişată sau ca
raportul să fie afişat sau tipărit. Procedura pentru tratarea
evenimentului are un argument, Cancel, care dacă are valoarea True,
formularul sau raportul respectiv nu va mai fi deschis. Acest eveniment
se produce înaintea evenimentului Load.
• Close – Are loc atunci când un formular sau un raport este
închis sau nu mai este vizibil pe ecran, după evenimentul Unload.
• Load – Apare la deschiderea unui formular şi la afişarea
înregistrărilor, înaintea evenimentului Current al primei
înregistrări sau al primului control al formularului, dar după
evenimentul Open.
• Unload – Apare la închiderea unui formular (dar înainte ca
acesta să dispară de pe ecran), înaintea evenimentului Close.
Procedura pentru tratarea evenimentului are un argument, Cancel, care,
dacă are valoarea True, formularul nu va mai fi închis.
Notă: Atenţie! Dacă daţi argumentului Cancel valoarea True,
formularul nu va mai fi închis sau ştrs de pe ecran. Astfel, dacă nu
îi daţi explicit mai târziu valoarea False, nu veţi mai putea
închide formularul decât închizând aplicaţia.
• Resize – Apare la deschiderea unui formular sau la redimesionarea
sa. Astfel, aveţi posibilitatea să redimensionaţi şi controalele
formularului.
5.1.7. Evenimente generate de erori
• Error – Are loc atunci când apare o eroare de execuţie la
rularea aplicaţiei. Astfel, aveţi posibilitatea de a intercepta
mesajele de eroare ale lui Access şi de a afişa propriile
dumneavoastră mesaje. Procedura pentru tratarea acestui eveniment are
două argumente: DataErr, care reprezintă codul de eroare returnat de
funcţia Err ce se apelează de câte ori apare o eroare şi Response,
care determină dacă trebuie să fie afişat un mesaj de eroare
standard. Dacă Response are valoarea 0, Access nu mai afişa mesajul
de eroare, putând astfel să afişaţi un mesaj personalizat, iar
dacă are valoarea 1, Access va afişa mesajul standard.
5.1.8. Evenimentele legate de timer
• Timer – Apare la intervale de timp regulate, dacă aţi stabilit
proprietatea TimerInterval a unui formular. Dacă această proprietate
are valoarea 0, evenimentul nu se va produce. Pentru valori cuprinse
între 0 şi 65536, evenimentul va avea loc la intervalul stabilit,
valoarea reprezentând mărimea intervalului în milisecunde.
5.2. Ordinea producerii evenimentelor în Access
După ce aţi făcut cunoştinţă cu câteva dintre evenimentele ce
pot apărea într-o aplicaţie Access, este important să înţelegeţi
ordinea în care acestea se succed, pentru ale putea folosi la
stabilirea comportamentului aplicaţiei.
5.2.1. Ordinea producerii evenimentelor legate de controale
Când un control primeşte focusul, au loc următoarele evenimente:
Când introduceţi sau modificaţi datele dintr-un control şi apoi
treceţi focusul altui control, ordinea producerii evenimentelor este
următoarea:
Notă: Dacă în câmpul de editare al unei casete combinate este
introdusă o valoarea care nu se regăseşte în lista acestuia, după
evenimentul KeyUp apar evenimentele NotInLst şi Error.
5.2.2. Ordinea producerii evenimentelor legate de lucrul cu
înegistrările unui formular
Evenimentele ce se produc atunci când sunt afişate înregistrările
unui formular, sunt diferite de cele ale controalelor care afişează
date ale înregsitrărilor respective.
Dacă modificaţi o înregistrare prin intermediul controalelor unui
formular şi treceţi apoi la următoarea înregistrare, se vor
produce, în ordine, următoarele evenimente:
La ştergerea unei înregistrări, ordinea producerii evenimentelor
este următoarea:
Când treceţi focusul pe o înregistrare nouă (ce nu conţine încă
date), vor apărea evenimetele:
5.2.3 Ordinea producerii evenimentelor legate de formulare
Lucrul cu un formular implică generarea unor evenimente legate de
închidere, deschidere, trecerea de la un formular la altul şi lucrul
cu datele formularului.
De exemplu, dacă deschideţi formularul f1, apăsaţi pe un buton al
său pentru a deschide formularul f2 şi apoi treceţi din nou la
formularul f1, vor avea loc, în ordine, evenimentele:
Observaţi că evenimentul Deactivate al formularului f1 apare după
evenimentele Open, Load şi Resize ale lui f2. Astfel, dacă în timpul
deschiderii celui de-al doilea formular apare o eroare, îl puteţi
închide şi pune focusul pe primul formular.
Când lucraţi cu subformulare, ordinea producerii evenimentelor este
următoarea:
5.2.4. Ordinea producerii evenimentelor legate de tastatură şi mouse
După cum am mai spus, aceste evenimente apar atunci când un formular
sau un control al unui formular primeşte focusul. Ordinea producerii
evenimentelor generate de apăsarea unei taste este:
Ordinea evenimentelor generate de apăsarea unui buton al mouse-ului
este:
Dacă de efectuează un dublu clic, evenimentul DblClick va apărea
după evenimentul Click.
5.2.5. Ordinea producerii evenimentelor rapoartelor
Evenimentele unui raport sunt generate de tipărirea, afişarea sau de
închiderea raportului respectiv. Astfel, când deschideţi un raport
pentru a-l tipări sau afişa şi apoi îl închideţi, vor apărea,
în ordine, evenimentele:
Evenimentul Open are loc înainte ca înregistrarea pe care se bazează
raportul să fie executată. Dacă interogarea nu generează nici o
înregistrare, se produce evenimentul NoData.
5.3. Tratarea evenimentelor
După ce aţi decis ce acţiuni doriţi să fie efectuate ca răspuns
la anumite evenimente, nu mai trebuie decât să le scrieţi codul
Visual Basic corespunzător procedurilor pentru tratarea evenimentelor
respective. Figura VII.1 prezintă pagina Event a ferestrei Properties
a unui formular. Făcând clic pe săgeata din dreapta câmpului unui
eveniment, se va deschide o listă din care veţi putea alege o
macrocomandă. Pentru a crea procedura pentru tratarea unui eveniment
şi a-i scrie codul VBA, procedaţi astfel:
1. Deschideţi formularul sau raportul în modul Design. Dacă doriţi
să trataţi un eveniment al unui control sau al unei secţiuni,
selectaţi controlul sau secţiunea respectivă.
2. Deschideţi fereastra Properties a formularului, raportului,
secţiunii sau controlului respectiv şi selectaţi pagina Event.
3. Din lista corespunzătoare evenimentului pe care doriţi să îl
trataţi, alegeţi opţiunea [Event Procedure] şi apăsaţi butonul
Build (…) pentru a deschide fereastra modului în care se va afla
procedura.
4. Access va scrie automat scheletul procedurii, care va arăta astfel:
Sub nume_procedura ()
…
End Sub
5. Alegeţi comanda Debug | Compile Loaded Modules pentru a compila
procedura.
6. Salvaţi modulul.
Astfel, de câte ori va avea loc evenimentul respectiv, această
procedură va fi apelată şi executată.
Despre procedurile VBA vom vorbi pe larg mai tîrziu. Aţi observat că
în acest capitol am insistat mai mult pe folosirea procedurilor VBA
decât a macrocomenzilor pentru tratarea evenimentelor. Aceasta pentru
că procedurile sunt mai rapide în execuţie, mai flexibile şi mai
uşor de întreţinut. Spre deosebire de macrocomenzi, ele vă dau
posibilitatea de a intercepta şi a trata erorile cu ajutorul
evenimentului Error şi a funcţiei OnError. Cu toate acestea, există
şi câteva macrocomenzi care nu au corespondent în VBA: AutoKeys,
Autoexec şi AddMenu.
CAP:6. Macrocomenzi
Macrocomenzile reprezintă o metodă simplă de a efectua anumite
acţiuni într-o aplicaţie Access, fără a avea prea multe
cunoştinţe de programare. Mai precis, o macrocomandă este o
înşiruire de acţiuni, programată să se execute în cazul
producerii unui anumit eveniment.
Macrocomenzile sunt, aşadar, nişte instrumente utile, care vă
permit să programaţi acţiuni simple, de la deschiderea şi
închiderea unui formular ori raport sau stabilirea unor opţiuni,
până la emiterea unui semnal sonor, totul în doar câteva secunde.
Pe de altă parte, macrocomenzile au dezavantajele lor, care îi
determină pe cei mai mulţi programatori Access să prefere modulele
şi codul VBA. Access vă dă chiar posibilitatea de a transforma o
macrocomandă în codul VBA echivalent. Pe lângă faptul că
macrocomenzile sunt mai lente în execuţie decât procedurile, ele mai
au dezavantajul că nu oferă programatorului posibilitatea de a
intercepta şi trata corespunzător erorile.
Există însă şi unele acţiuni care pot fi efectuate numai prin
intermediul macrocomenzilor:
• Definirea comenzilor rapide de la tastatură pentru diferite
acţiuni. Spre exemplu, dacă veţi dori ca tasta F3 să deschidă un
anumit formular, nu veţi putea stabili acest lucru decât cu ajutorul
macrocomenzii AutoKeys.
• Rularea anumitor acţiuni la deschiderea bazei de date.
• Crearea şi utilizarea meniurilor şi a barelor cu instrumente
personalizate.
6.1. Crearea unei macrocomenzi
Pentru a înţelege mai bine cum se creează o macrocomandă, vom
descrie în cele ce urmează paşii necesari creării unei macrocomenzi
care să afişeze o casetă de mesaj cu un text de salut.
1. Deschideţi pagina Macros a ferestrei Database şi apăsaţi butonul
New. Se va deschide fereastra Macro Builder (figura 6.1).
2.
Fig. 6.1
3. Faceţi clic pe prima linie a coloanei Action şi apoi apăsaţi pe
săgeata din partea dreaptă a câmpului. Se va deschide o listă cu
toate acţiunile. Selectaţi acţiunea MsgBox.
4. După ce aţi selectat o acţiune, în partea de jos a ferestrei
Macro Builder vor apărea argumentele corespunzătoare acţiunii
respective. În acest caz, ele sunt: Message (mesaj), Beep (semnal
sonor), Type (tipul casetei de mesaj) şi Title (titlul casetei de
mesaj). Figura 6.1 prezintă valorile pe care le-am ales pentru aceste
argumente.
5. Salvaţi macrocomanda cu ajutorul comenzii File | Save. Va apărea o
cutie de dialog cerându-vă un nume pentru noua macrocomandă (să-i
spunem “Salut”).
6. Pentru a rula macrocomanda, apăsaţi butonul Run de pe bara cu
instrumente sau alegeţi comanda Run | Run. Caseta de mesaj va arăta
ca în figura 6.2.
Fig. 6.2
Notă: Este bine ca pentru fiecare acţiune a unei macrocomenzi să
introduceţi un scurt comentariu care să descrie ce anume face
acţiunea respectivă. Folosiţi pentru aceasta liniile coloanei
Comment. Dacă veţi converti ulterior macrocomanda la codul VBA
corespunzător, aceste comentarii nu se vor pierde.
După cum v-aţi putut da seama, pentru a crea o macrocomandă care
să îndeplinească o anumită cerinţă, este important să
cunoaşteţi atât acţiunile disponibile, cât şi argumentele
acestora..
6.2. Grupuri de macrocomenzi
Grupurile de macrocomenzi sunt, după cum le spune şi numele,
colecţii de macrocomenzi simple, salvate separat, dar cuprinse în
aceeaşi comandă globală. Fiecare macrocomandă din grup trebuie să
aibă un nume propriu, pe care îl introduceţi în coloana Macro Name
a ferestrei Macro Builder (această coloană va fi afişată dacă
selectaţi comanda View | Macro Names). Într-un grup, macrocomenzile
componete trebuie să fie separate prin linii goale (ca în figura
6.3).
Fig. 6.3
Grupurile de macrocomenzi sunt utile, de exemplu, atunci când doriţi
să păstraţi toate macrocomenzile unui formular în acelaşi obiect,
astfel încât numărul obiectelor din pagina Macro a ferestrei
Database să fie mai mic. Pe de altă parte, o macrocomandă poate
apela altă macrocomandă în cadrul unei condiţii, caz în care veţi
prefera să le includeţi pe amândouă în acelaşi obiect, pentru a
fi mai simplu de depanat.
O macrocomandă din grup poate fi executată utilizând numele
grupului, urmat de un punct şi de numele macrocomenzii:
nume_grup.nume_macro
Execuţia unei macrocomenzi din grup se opreşte la întâlnirea
următoarei linii libere din coloana Action.
O altă utilizare frecventă a grupurilor de macrocomenzi o
reprezintă crearea meniurilor personalizate, în care fiecărui
control îi corespunde o macrocomandă din grup.
6.3. Macrocomenzi imbricate
În Access puteţi crea şi macrocomenzi compuse, în care o
macrocomandă să fie apelată de alta. Cel mai simplu mod de a realiza
acest lucru este folosirea acţiunii RunMacro. Figura 6.4 prezintă
macrocomanda care apelează macrocomanda Mac1.
Fig. 6.4
O altă situaţie în care se folosesc macrocomenzi imbricate este
atunci când veţi dori să controlaţi execuţia unei macrocomenzi
impunând o condiţie. Despre condiţii în macrocomenzi vom vorbi în
secţiunea următoare.
6.3.1. Condiţii în macrocomenzi
Access vă pune la dispoziţie un mod rudimentar de a controla firul
de execuţie al macrocomenzilor, prin intermediul coloanei Condition a
ferestrei Macro Builder. Pentru a vedea această coloană, selectaţi
comanda View | Conditions.
Dacă introduceţi o expresie în coloana Condition, acţiunea aflată
pe aceeaşi linie în coloana Action se va executa numai dacă expresia
este adevărată. Dacă expresia este falsă, Access nu va executa
acţiunea de pe aceeaşi linie cu condiţia şi va trece la următoarea
acţiune. Dacă introduceţi trei puncte de suspensie (…) în coloana
Condition pe linia de sub o condiţie existentă, Access va considera
acţiunea de pe aceeaşi linie cu punctele de suspensie ca fiind pusă
aceleiaşi condiţii.
6.4. Macrocomenzi speciale
În cele ce urmează, vom discuta despre două macrocomenzi ce merită
o atenţie specială: AutoKeys şi AutoExec.
6.4.1. Macrocomanda AutoKeys
Macrocomanda AutoKeys vă permite să atribuiţi comenzi rapide de la
tastatură acţiunilor pe care le poate efectua aplicaţia
dumneavoastră. De exemplu, ar fi util ca, de câte ori utilizatorul
foloseşte combinaţia de taste Ctrl+P, să fie tipărit raportul
curent. Astfel, puteţi atribui orice combinaţie de taste oricărei
acţiuni (sau grup de acţiuni) care poate fi executată prin
intermediul unei macrocomenzi. Pentru a nu crea confuzii, evitaţi
totuşi atribuirea combinaţiilor de taste predefinite în Access (cum
ar fi Ctrl +V pentru comanda Edit | Paste) deoarece, în astfel de
cazuri, Access va executa macrocomanda dumneavoastră în locul
comenzii predefinite.
Nu puteţi atribui o macrocomandă unei singure taste alfanumerice sau
unei taste folosite, în general, în combinaţie cu alte taste (precum
Ctrl sau Alt). Tastelor funcţionale (F1-F12) şi tastelor Insert şi
Delete le puteţi atribui macrocomenzi.
Pentru a atribui o combinaţie de taste unei acţiuni, procedaţi
astfel:
1. Creaţi o nouă macrocomandă, apăsând butonul New din pagina
Macros a ferestrei Database.
2. Alegeţi comanda View | Macro Names pentru a afişa coloana Name a
ferestrei Macro Builder. Introduceţi aici combinaţia de taste pe care
doriţi să o atribuiţi, urmând instrucţiunile din tabelul 6.5.
3. Introduceţi în coloana Action corespunzătoare acţiunea
atribuită combinaţiei de taste din coloana Name. Dacă doriţi să
atribuiţi mai multe acţiuni unei combinaţii de taste, nu trebuie
decât să le introduceţi pe linii consecutive ale coloanei Action
(fără a lăsa linii libere între ele).
4. Închideţi macrocomanda şi salvaţi-o cu numele “AutoKeys”.
Este important ca acesta să fie numele macrocomenzii, deoarece altfel
Access nu va efectua atribuirile.
5. Închideţi baza de date (cu comanda File | Close) şi deschideţi-o
din nou pentru a activa macrocomanda AutoKeys.
Pentru a specifica o anumită combinaţie de taste, trebuie să
folosiţi o sintaxă specială, descrisă în tabelul 6.5, în care
tastei din coloana Tasta îi corespund, în coloana Name a ferestrei
Macro Buider, caracterele din coloana Corespondent a tabelului. Coloana
Exemplu vă arată concret ce aţi putea introduce în coloana Name a
ferestrei Macro Builder.
Tasta Corespondent Exemplu
Ctrl ^ ^Z (pentru Ctrl+Z)
Tastă funcţională { } {F8} (pentru tasta F8)
Shift + +{F8} (pentru Shift+F8)
Insert {INS} sau {INSERT} {INS} (pentru tasta Insert)
Delete {DEL} sau {DELETE} {DEL} (pentru tasta Delete)
Combinaţii de taste Folosiţi caracterele de mai sus +^{F8} (pentru
combinaţia Shift+Ctrl+F8)
Tabelul 6.5
În figura 6.6 este prezentată macrocomanda AutoKeys care atribuie
acţiunii de tipărire a primelor două pagini ale obiectului curent
combinaţia de taste Ctrl+P.
Figura 6.6
6.4.2. Macrocomanda AutoExec
Dacă doriţi ca anumite ca anumite acţiuni să aibă loc ori de
câte ori se deschide o bază de date, puteţi crea o macrocomandă
care să efectueze acţiunile respective şi pe care să o salvaţi cu
numele “AutoExec”. Cea mai frecventă utilizare a macrocomenzii
AutoExec este ascunderea ferestrei Database şi deschiderea unui
formular care să joace rolul de meniu principal al aplicaţiei sau de
spalsh-screen.
În Access 97 vă puteţi lipsi de această macrocomandă, deoarece
există o cutie de dialog în care puteţi alege formularul care va fi
afişat la deschiderea bazei de date. Pentru a deschide această cutie
de dialog alegeţi comanda Tools | StartUp.
Ţinând tasta Shift apăsată, utilizatorul va putea, totuşi, să
împiedice rularea macrocomenzii AutoExec la deschiderea bazei de date.
Figura 6.7 prezintă macrocomanda AutoExec care deschide formularul
„Student” ori de câte ori este deschisă baza de date
Optionale.mdb.
Figura 6.7
6.5. Crearea meniurilor şi a barelor cu instrumente personalizate
În versiunile anterioare lui Access 97, se foloseau macrocomenzi
pentru crearea barelor de meniuri personalizate pentru aplicaţii.
Aceste bare de meniuri înlocuiau bara de meniu standard Access, pentru
a limita acţiunile utilizatorului la cele specifice aplicaţiei sau
pentru a simplifica efectuarea unor acţiuni prin rularea de
macrocomenzi. Aceste versiuni anterioare de Access furnizau un
instrument specializat pentru crearea de astfel de meniuri, numit Menu
Builder şi care vă ajuta să scrieţi macrocomenzile
corespunzătoare.
Access 97 nu mai include instrumentul Menu Builder, ci tratează
barele de meniuri şi barele cu instrumente unitar, numindu-le bare de
comandă. Introducem totuşi această discuţie aici, deoarece până
la versiunea Access 97, meniurile şi barele cu instrumente erau create
cu ajutorul macrocomenzilor. Şi în Access 97 mai pot fi folosite
macrocomenzile în acest scop, dar există şi o modalitate mai
simplă, pe care o prezentăm în continuare.
Pentru a crea sau a modifica o bară cu instrumente sau o bară de
meniuri în Access 97, procedaţi astfel:
1. Alegeţi comanda View | Toolbars | Customize. Se va deschide cutia
de dialog Customize (figura 6.8).
2. Apăsaţi butonul New din pagina Toolbars pentru a crea o nouă
bară cu instrumente. Se va deschide cutia de dialog Toolbar Name, în
care va trebui să introduceţi un nume pentru bara cu instrumente.
După ce apăsaţi butonul OK, va apărea pe ecran noua bară, ce nu
conţine nici un buton şi nici un meniu.
Pentru a adăuga butoane la o bară cu instrumente existentă,
selectaţi-o în lista din pagina Toolbars a cutiei de dialog Customize
şi treceţi la pagina Commands. Dacă doriţi ca butonul să fie
asociat deschiderii unui obiect din baza de date (tabelă, interogare,
formular sau raport) sau rulării unei macrocomenzi, selectaţi din
lista Categories una dintre opţiunile All Tables, All Queries, All
Forms, All Reports sau, respectiv, All Macros. În funcţie de
opţiunea aleasă, în lista Commnads vor apărea toate obiectele din
baza de date curentă care fac parte din categoria respectivă.
Selectaţi şi executaţi drag & drop cu obiectul dorit pe bara cu
instrumente la care doriţi să îl adăugaţi. După ce închideţi
fereastra Customize, nu trebuie decât să apăsaţi pe noul buton
pentru a se efectua acţiunea pe care i-aţi atribuit-o.
Figura VIII.8
Pentru a adăuga un meniu la o bară cu instrumente existentă,
procedaţi ca şi pentru butoane, cu diferenţa că din lista
Categories trebuie să alegeţi opţiunea New Menu. Selectaţi apoi
articolul New Menu din lista Commands şi faceţi drag & drop cu el
peste bara respectivă. Faceţi apoi clic dreapta pe meniul nou
adăugat, pentru a afişa un meniu derulant. În caseta Name a acestui
meniu derulat, scrieţi numele noului meniu şi apăsaţi tasta Enter.
Acum, meniul există, dar nu are nici un articol de meniu. Pentru a
adăuga comenzi unui meniu, procedaţi la fel ca pentru adăugarea
butoanelor la o bară cu instrumente, cu diferenţa că trebuie să
faceţi drag & drop cu obiectele selectate din lista Commands pe meniul
respectiv. Exact în acelaşi mod puteţi adăuga submeniuri la
meniurile existente.
Pentru a şterge un meniu sau un buton al unei bare cu instrumente,
selectaţi bara respectivă din lista din pagina Toolbars a cutiei de
dialog Customize. Faceţi apoi clic dreapta pe butonul sau pe meniul
respectiv şi alegeţi din meniul derulant comanda Delete. Pentru a
şterge o bară cu instrumente cu totul, selectaţi-o în pagina
Toolbars a cutiei de dialog Customize şi apăsaţi butonul Delete.
6.6. Rularea şi depanarea macrocomenzilor
Există mai multe modalităţi de rula o macrocomandă în Access:
1. Făcând dublu-clic pe numele macrocomenzii în pagina Macros a
ferestrei Database.
2. Prin intermediul codului VBA dintr-un modul, folosind metoda
RunMacro a obiectului DoCmd:
DoCmd.RunMacro nume_macrocomanda
3. Dintr-o altă macrocomandă sau prin intermediul barelor
personalizate de meniuri sau de instrumente.
4. La deschiderea bazei de date, dacă numele macrocomenzii este
AutoExec.
Vă puteţi da seama dacă o macrocomandă nu funcţionează când
vedeţi cutia de dialog (figura 6.9) aceasta vă prezintă numele
macrocomenzii care a eşuat, acţiunea care a produs eroarea şi
argumentele acţiunii respective. Apăsaţi butonul Halt pentru a
depana macrocomanda.
Fig. 6.9
Puteţi depana o macrocomandă rulând-o acţiune cu acţiune, în
felul următor:
• Deschideţi macrocomanda în fereastra Macro Builder.
• Apăşaţi butonul Single Step de pe bara cu instrumente sau
alegeţi comanda Run | Single Step.
• Dacă macrocomanda începe pe prima linie a ferestrei Macro
Builder, puteţi apăsa butonul Run de pe bară pentru a porni
execuţia. Dacă depanaţi o macrocomandă dintr-un grup, va trebui să
rulaţi codul care apelează macrocomanda respectivă.
Când macrocomanda începe să ruleze, pe ecran apare cutia de dialog
Macro Single Step, care prezintă acţiunea în curs de rulare şi
valorile parametrilor acesteia. Această cutie de dialog vă oferă
trei opţiuni: rularea acţiunii următoare (cu butonul Step), oprirea
execuţiei macrocomenzii (cu butonul Halt) şi continuarea
neîntreruptă a execuţiei (cu butonul Continue).
De asemenea, puteţi opri de la tastatură execuţia unei macrocomenzi
la un moment dat, apăsând Ctrl + Break. Atunci, va apărea cutia de
dialog Macro Single Step, ce vă va permite rularea pas cu pas a
macrocomenzii.
CAP:7. Visual Basic for Applications (VBA)
După cum v-aţi putut da seama, în Access puteţi realiza multe
lucruri fără a avea prea multe calităţi de programator. Totuşi,
dacă doriţi să creaţi o aplicaţie dotată cu o interfaţă
inteligentă şi prietenoasă, va trebui să învăţaţi să scrieţi
codul necesar pentru a controla aplicaţia.
Obiectul acestui capitol este limbajul VBA (Visual Basic for
Applications), care este un limbaj de programare complex, ce vă
permite dezvoltarea de aplicaţii atât în Access, cât şi în
Microsoft Excel, Microsoft Project şi, bineînţeles, Microsoft Visual
Basic. Interceptarea şi tratarea erorilor, un control mai bun asupra
interfeţei cu utilizatorul, mai multă rapiditate în execuţie,
posibilitatea de a interacţiona cu alte aplicaţii şi de a apela
funcţii Windows API sunt numai câteva dintre avantajele programării
în VBA.
7.1 Mediul de programare Access
Access păstrează codul procedurilor scrise de dumneavoastră în
aşa-numitele module. Acestea se împart în trei categorii: module
standard, module pentru clase şi module pentru formulare şi rapoarte.
Modulele standard sunt obiecte de sine stătătoare şi sunt folosite
pentru a crea şi stoca proceduri ce nu sunt legate de un anumit
formular sau raport. Le puteţi crea şi vedea în pagina Modules a
ferestrei Database folosind butoanele New şi, respectiv, Design.
Modulele pentru clase sunt folosite pentru a crea şi a defini obiecte
cărora le puteţi apoi crea instanţe (vom reveni asupra lor în
secţiunea 7.6). Modulele pentru formulare şi rapoarte se deosebesc de
celelalte tipuri de module prin faptul că nu sunt obiecte
independente, ci sunt incluse în formularul sau raportul
corespunzător. Ele conţin procedurile pentru tratarea evenimentului
formularului sau raportului respectiv şi pot fi deschise cu ajutorul
comenzii View | Code, atâta timp cât sunteţi în modul Design View.
Ce conţin modulele
Aţi văzut deja cum puteţi accesa un modul. Atunci când un modul
este deschis, în partea de sus a ferestrei asociate veţi vedea două
casete combinate. Acestea vă ajută să găsiţi diferitele proceduri
stocate în modulul respectiv. Cel din stânga vă permite să alegeţi
obiectul al cărui cod doriţi să-l vedeţi sau să-l editaţi. În
cazul modulelor standard, singura opţiune este General, deoarece
acestea nu conţin obiecte, în timp ce în cazul unui modul al unui
formular sau raport, această casetă combinată va afişa lista
tuturor obiectelor pe care le conţine. După ce aţi selectat un
obiect, în caseta combinată din dreapta veţi putea alege un
eveniment al acelui obiect.
Fig. 7.1
(General)
(General) nu este un obiect, ci mai degrabă o secţiune în cadrul
unui modul. Aici veţi putea pune tot ce ţine de modulul respectiv,
în general: opţiuni, declaraţii, proceduri care nu tratează
evenimente (în cazul modulelor standard, toate procedurile se vor afla
aici).
Opţiuni
Orice modul are un set de opţiuni, pe care le puteţi stabili cu
ajutorul cuvântului cheie Option şi pe care vi le prezentăm în
continuare:
1. Option Base – vă permite să stabiliţi indicele cel mai mic
pentru elementele unei matrice (array). Implicit, acesta este zero.
2. Option Compare – determină modul în care Access va compara două
şiruri de caractere (lucru util, de exemplu, pentru sortări).
3. Option Compare Binary – Access va folosi reprezentarea binară a
caracterelor pentru comparaţiile făcute în cadrul modulului.
4. Option Compare Database – opţiune implicită, ce face ca Access
să folosească ordinea de sortare a bazei de date pentru efectuarea
comparaţiilor între şiruri de caractere. Această ordine poate fi
schimbată cu ajutorul comenzii Tools | Options, dacă în pagina
General a cutiei de dialog ce se va deschide veţi selecta o altă
valoare în caseta combinată New Database Sort Order.
5. Option Compare Text – similară cu Option Compare Database, cu
deosebire că la efectuarea comparaţiilor între şiruri de caractere
nu se face diferenţă între literele mari şi mici.
6. Option Explicit – Dacă specificaţi această opţiune, toate
variabilele vor trebui să fie declarate înainte de a fi folosite în
cadrul modulului.
7. Option Private – Dacă stabiliţi această opţiune, codul aflat
în interiorul modulului nu va putea fi accesat dintr-un alt modul.
Declaraţii (Declarations)
Tot la secţiunea (General) a unui modul mai puteţi declara
proceduri, variabile şi constante ce pot fi folosite în întregul
modul.
Proceduri pentru tratarea evenimentelor
Modulele pentru formulare şi rapoarte pot conţine şi alte
secţiuni, în afară de (General). Acestea corespund controalelor şi
secţiunilor formularului sau raportului respectiv şi conţin
procedurile pentru tratarea evenimentelor legate de ele.
7.2 Proceduri
O procedură este o înşiruire de linii de cod, care ca scop
îndeplinirea unui anumit obiectiv. În Access, procedurile pot fi de
două tipuri: subrutine şi funcţii.
O subrutină este, pur şi simplu, un bloc de cod care are un nume.
Blocul de cod ce compune subrutina poate fi folosit prin apelarea
numelui. O funcţie este ceva asemănător unei subrutine, cu
diferenţa că ea returnează o valoare.
Programatorul poate comunica informaţii unei proceduri prin
intermediul argumentelor. Acestea sunt variabile ale căror valori au
fost deja stabilite şi care transmit procedurilor datele necesare
efectuării operaţiilor specifice.
Chiar dacă pe moment lucrurile nu sunt foarte clare, este important
să înţelegeţi faptul că o procedură este un mod de a aduna mai
multe linii de cod laolaltă, astfel încât de câte ori veţi dori
să efectuaţi o anumită operaţie, să nu trebuiască să scrieţi
decât o singură linie de cod, conţinând numele procedurii.
7.2.1 Declararea procedurilor
Declararea unei proceduri trebuie să conţină următoarele
informaţii: tipul procedurii (subrutină sau funcţie), numele
procedurii, numele şi tipul argumentelor (dacă acestea există),
tipul informaţiei returnate (dacă procedura este o funcţie).
De exemplu, iată cum ar putea să arate (schematic) declararea unei
subrutine care tipăreşte un şir de caractere:
Sub Tiparire(strText As String)
Debug.Print strText
End Sub
Numele subrutinei este Tiparire şi ea are un singur argument,
strText, de tip String (şir de caractere). Subrutina va putea fi
apelată astfel:
Call Tiparire (“Salut!”)
Iată acum declararea unei funcţii care returnează rezultatul
împărţirii a două numere reale:
Function Cat (db1Nr1 As Double, db1Nr2 As Double) As Double
If db1Nr2 = 0 Then Cat = 0
Else Cat = db1Nr1 / db1Nr2
End If
End Function
Pentru a apela funcţia, vom scrie:
db1Rez = Cat (n1, n2)
unde n1 şi n2 sunt variabile ale căror valori au fost stabilite
anterior. Observaţi facptul că, pentru ca rezultatul să fie corect,
este importantă ordinea în care sunt date argumentele. Există şi o
modalitate de a furniza argumentele unei funcţii în altă ordine
decât cea în care acestea au fost date la declararea funcţiei: în
faţa argumentului efectiv, specificaţi numele argumentului din
declaraţie, urmat de două puncte şi egal, ca în exemplul de mai
jos.
db1Rez = Cat (db1Nr2:= n2, db1Nr1:= n1)
În general, pentru ca apelul unei proceduri să se poată compila,
trebuie să fi fost furnizate toate argumentele din declaraţie.
Puteţi însă modifica acest comportament, dacă în cadrul
declaraţiei veţi specifica înaintea numelui unui argument cuvântul
cheie Optional. Astfel, la apelul procedurii, nu va mai trebui
neapărat să daţi valoarea efectivă a acelui argument. De exemplu,
funcţia Cat poate fi declarată ca:
Function Cat (Optional db1Nr1 As Double, db1Nr2 As Double) As Double
şi apoi apelată astfel:
db1Rez = Cat (, n2)
sau
db1Rez = Cat (db1Nr2:= n2)
Atunci când apelaţi o procedură fără să furnizaţi unele dintre
argumentele opţionale, trebuie ca în locul lor să puneţi o virgulă
sau să specificaţi pentru argumente neopţionale, numele acestora din
declaraţie. De aceea, este bine ca la declararea unei proceduri să
lăsaţi la urmă argumentele opţionale, pentru ca la apelare să nu
mai trebuiască să includeţi virgule sau nume. Astfel, putem să
declarăm funcţia Cat aşa:
Function Cat (db1Nr2 As Double, Optional db1Nr1 As Double) As Double
şi o putem apela:
db1Rez = Cat (n2)
Notă: Atât folosirea argumentelor opţionale cât şi a celor complet
specificate (cu ajutorul numelui din declaraţie) este recomandată mai
ales atunci când procedura are un număr mare de argumente.
7.2.2. Lucrul cu argumente opţionale
Cum putem afla dacă un argument declarat ca opţional a fost sau nu
furnizat la apelul procedurii? Pentru aceasta există o funcţie Access
predefinită, IsMissing, care returnează valoarea True dacă
argumentul lipseşte şi False dacă acesta a fost furnizat. Putem
rescrie funcţia Cat astfel încât, dacă deîmpărţitul lipseşte,
să returneze valoarea zero:
Function Cat (db1Nr1 As Double, Optional db1Nr1 As Double) As Double
If IsMissing (db1Nr1) Then Cat = 0
Else If db1Nr2 = 0 Then Cat = 0
Else Cat = db1Nr1 / db1Nr2
End If
End If
End Function
7.2.3. Funcţii predefinite
IsMissing este una dintre funcţiile predefinite pe care Access vi le
pune la dispoziţie. Există funcţii predefinite pentru toate tipurile
de activităţi: lucrul cu texte şi date numerice, comunicarea cu alte
aplicaţii, lucrul cu fişiere şi directoare, cu date şi ore etc.
Puteţi faceţi cunoştinţă cu funcţiile predefinite dacă lucraţi
cu Expression Builder. Pentru a vă bucura de facilităţile oferite de
aceste funcţii, nu trebuie decât să le apelaţi în codul
dumneavoastră.
7.3. Variabile
Variabilele sunt utilizate pentru a stoca date folosite în subrutine
sau funcţii (asemeni unor containere). Puteţi atribui o valoarea unei
variabile şi apoi să efectuaţi calcule cu valoarea respectivă prin
intermediul variabilei. Folosind variabila şi nu direct valoarea,
daţi flexibilitate codului pe care îl veţi putea apoi refolosi şi
pentru alte valori.
Spuneam mai înainte că variabilele sunt nişte “containere”
folosite pentru a stoca date. Însă, până acum, aţi văzut că în
Access datele sunt stocate în tabele, deci ce nevoie mai avem de
variabile? Există o diferenţă esenţială între aceste două
mijloace de stocare a datelor: spre deosebire de tabele, variabilele
sunt folosite pentru a stoca o informaţie temporară, ce ne ajută să
obţinem un anumit rezultat şi apoi va fi uitată. Tabelele sunt
folosite pentru a stoca informaţii pentru o perioadă mai lungă de
timp.
7.3.1 Tipuri de date
Tipurile de date sunt folosite pentru a specifica ce fel de
informaţie va fi păstrată într-o variabilă astfel încât Access
să ştie cum să stocheze şi cum să manipuleze această informaţie.
Tabelul 7.2 prezintă toate tipurile de date pe care Access 97 vi le
pune la dispoziţie.
Tipul de date Domeniul Exemplu
String Şir de caractere Dim strText As String
Dim strText$
Integer Numere întregi între –32768 şi 32767 Dim intNr As Integer
Dim intNr%
Long Numere întregi între –2147483648 şi 2147483647 Dim lngNr As
Long
Dim lngNr&
Single Numere reale pozitive sau negative cu maximum 7 zecimale, cu
valoare absolută între 1.401298*10-45 şi 3.402823*1038 Dim sngNr As
Single
Dim sngNr!
Double Numerele reale pozitive sau negative cu maximum 15 zecimale, cu
valoare absolută între 4.94065645842147*10-324 şi
1.79769313486231*10308 Dim db1Nr As Double
Dim db1Nr#
Currency Număr cu 4 zecimale între –922337203685477.5808 şi
922337203685477.5807, folosit mai ales în domeniul bancar Dim crnNr As
Currency
Dim crnNr@
Boolean Pentru variabile care pot avea numai valorea True sau False Dim
bNr As Boolean
Date Date între 1 Jan 100 şi 31 Dec 9999 şi ore între 00:00:00 şi
23:59:59 Dim datData As Date
Byte Valori întregi între 0 şi 25 Dim bytNr As Byte
Object Orice tip de obiecte, nu numai obiecte Access 97 Dim objObiect
As Object
Variant Folosit pentru a stoca diferite tipuri de date Dim varOrice As
Variant
Hyperlink Stochează date de tip text ce reprezintă adrese de
hiperlegături Dim hypPag As Hyperlink
Tabelul 7.2
7.3.2 Declararea variabilelor
Dacă la secţiunea (General) (Declarations) a unui modul aţi
stabilit opţiunea Option Explicit, înainte de aputea atribui o
valoare unei variabile, trebuie să-I indicaţi lui Access două
lucruri: numele variabilei şi tipul datelor pe care aceasta le va
stoca; cu alte cuvinte, trebuie să declaraţi variabila. Acest lucru
îl veţi face prin intermediul instrucţiunii Dim şi a clauzei As
Type:
Dim intNumar As Integer
Prin linia de cod de mai sus am declarat variabila intNumăr de tip
Integer. Atunci când alegeţi numele pentru o variabilă, trebuie să
ţineţi cont de următoarele reguli:
• Trebuie să înceapă cu o literă
• Poate să conţină doar litere, cifre şi caracterul underscore
(_)
• Poate avea cel mult 40 de caractere
• Nu poate fi un cuvânt rezervat
Dacă nu v-aţi hotărât de la început ce tip de date va stoca
variabila dumneavoastră, o puteţi face ulterior folosind tipul de
date Variant.
7.3.2.1 Tipul Variant
Într-o variabilă de acest tip puteţi stoca text, date numerice sau
orice alt tip de date predefinit în Access. Spre exemplu:
Dim varOrice As Variant
VarOrice = 32
VarOrice = varOrice & “ este un numar intreg”
În prima linie de cod declarăm variabila varOrice ca fiind de tipul
Variant, apoi îi atribuim valoarea 32. În cea de-a 3-a linie de cod
am folosit caracterul & pentru a concatena 32 cu un şir de caractere.
Astfel, variabila noastră conţine şirul de caractere “32 este un
numar intreg”. Access a făcut implicit conversia de la tipul întreg
la şir de caractere. Iată un alt exemplu:
varOrice = “2.5”
varOrice = varOrice + 10
Cea de-a doua linie de cod va face ca valoarea lui varOrice să fie
12.5, prin conversia şirului de caractere “2.5” la numărul real
2.5. Acelaşi efect îl vor avea şi următoarele linii de cod:
varOrice = 2.5
varOrice = varOrice + “10”
De această dată, şirul “10” va fi convertit la numărul întreg
10.
Atunci când lucraţi cu variabile de tipul Variant, este bine să
ştiţi următoarele:
• Access va converti variabila la tipul de date corespunzător
valorii atribuite;
• Atunci când doriţi să concatenaţi două şiruri de caractere,
folosiţi operatorul & în loc de +;
Când folosiţi operatorul + pentru lucrul cu variabile de tip Variant,
Access va acţiona astfel:
• Dacă ambele valori sunt numerice, se va efectua o adunare;
• Dacă ambele conţin şiruri de caractere, ele vor fi concatenate;
• Dacă una este o valoare numerică şi cealaltă este un şir de
caractere, Access va încerca s-o convertească în valoare numerică
şi să facă adunarea. Dacă nu reuşeşte, va rezulta o eroare.
Pentru a determina ce tip de date conţine o variabilă de tip Variant
la un moment dat, apelaţi la funcţia predefinită VarType. Aceasta va
returna una dintre valorile prezentate în tabelul 7.3.
Valoarea returnată Tipul de date Constanta intrinsecă
0 vid (variabila este neiniţializată) vbEmpty
1 Null vbNull
2 Integer vbInteger
3 Long vbLong
4 Single vbSingle
5 Double vbDouble
6 Currency vbCurrency
7 Date vbDate
8 String vbString
9 Object vbObject
10 eroare vbError
11 Boolean vbBoolean
12 Variant (numai pentru matrice) vbVariant
13 obiect DAO vbDataObject
14 Decimal vbDecimal
17 Byte vbByte
8192 matrice vbArray
Tabelul 7.3
Notă: În ultima coloană a tabelului am specificat constanta
intrinsecă ce corespunde valorii returnate. Despre constante
intrinseci vom vorbi în secţiunea 7.3.3.
Atunci când o variabilă este declarată, ei i se atribuie valoarea
iniţială 0 dacă variabila e de tip numeric sau “ “ (şirul vid)
dacă e de tip şir de caractere. Variabilelor de tip Variant însă,
nu li se atribuie la declarare nici o valoare, cu alte cuvinte sunt
“vide” (a nu se confunda aceasta cu valoarea 0 sau “ “ şi nici
cu valoarea Null). Aceste variabile rămân vide până în momentul
când li se atribuie o valoare. Puteţi testa dacă o variabilă de tip
Variant a fost sau nu iniţializată cu ajutorul funcţiei IsEmpty,
care returnează valoarea True dacăn variabila este “vidă”.
Pentru a “vida” din nou o variabilă, trebuie să-i atribuiţi ca
valoare o altă variabilă de tip Variant care nu a fost încă
iniţializată:
Dim varOrice As Variant
‘ acum varOrice este vida
varOrice = 0 ‘s-a atribuit valoarea 0 variabilei
If IsEmpty(varOrice) Then …
‘ am testat daca varOrice este vida (si nu este)
Dim VarCeva As Variant
varOrice = varCeva
‘ acum varOrice este vida din nou
Notă: În Access, caracterul apostrof (‘) introduce un comentariu
într-un modul.
O altă valoare specială pe care o poate avea o variabilă de tip
Variant este Null (dacă veţi încerca să atribuiţi valoarea Null
unei variabile de orice alt tip decât Variant, veţi obţine o
eroare). Dacă folosiţi valoarea Null într-o expresie, întreaga
expresie va avea valoarea Null. De exemplu:
Dim varOrice As Variant
varOrice = Null
varOrice = varOrice + 2.5
După cea de-a treia linie de cod, varOrice va avea tot valoarea Null.
Dacă înlocuiţi această linie cu:
varOrice = varOrice & “ceva”
varOrice va avea valoarea “ceva”. Deci, operatorul & este singurul
care nu propagă valoarea Null într-o expresie.
Puteţi testa dacă o variabilă are valoarea Null cu ajutorul
funcţiei IsNull.
Variabilele de tip Variant sunt foarte utile, deoarece, pe lângă
faptul că nu trebuie să vă mai bateţi capul cu alegerea unui tip de
date, sunt singurul tip de variabile cărora li se poate atribui
valoarea Null. Astfel, dacă unei anumite variabile îi veţi atribui
valori dintr-un câmp al unei tabele care poate conţine şi valoarea
Null, acea variabilă trebuie să fie de tip Variant. Folosirea acestui
tip de variabile are însă şi dezavantaje, printre care încetinirea
execuţiei aplicaţiei şi chiar posibila apariţiei a unor erori.
7.3.2.2 Option Explicit
Să revenim acum la opţiunea Option Explicit şi să vedem ce se
poate întâmpla în cazul în care nu am stabilit această opţiune
în cadrul secţiunii (General) a unui modul. Pentru aceasta, vom
considera următoarea subrutină:
Sub AriaCercului (db1Raza As Double)
Dim db1Aria As Double
db1Aria = 3.14 * db1Raza * db1Raza
Debug.Print “Aria = ” & db1Aria
End Sub
Pentru a rula această subrutină, deschideţi fereastra Debug,
apăsând butonul Debug Window de pe bara cu instrumente (fereastra
Debug vă va permite să apelaţi procedurile direct, pentru a le putea
testa). Scrieţi în partea de jos a ferestrei Debug linia:
Call AriaCercului (5)
După aceasta, apăsaţi pe Enter şi veţi vedea rezultatul: 0
(figura 7.4). Este clar că acest rezultat este eronat. Motivul este
acela că în codul subrutinei s-a strecurat o greşeală: în loc de
db1Raza am scris, într-un loc, db1Rsza. Opţiunea Option Explicit
nefiind stabilită, şi deci nefiind necesar ca variabila să fie
declarată înainte de a fi folosită, Access a atribuit variabilei
db1Raza valoarea implicită 0, care a dus la acest rezultat eronat.
Fig. 7.4
7.3.3 Constante
Constantele sunt tot un fel de variabile, cu deosebirea că nu le
puteţi schimba valoarea. În Access există trei tipuri de constante:
• Constante simbolice, create cu ajutorul instrucţiunii Const,
• Constante intrinsece,
• Constante de sistem: True, False şi Null.
Cu ajutorul constantelor simbolice puteţi da un nume unei valori.
Astfel, codul dumneavoastră va fi mai uşor de citit şi de
întreţinut. Prin următoarea linie de cod:
Const csPi = 3.14
am definit constanta csPi, a cărei valoare este 3.14. Constantele pot
fi folosite oriunde pot fi folosite şi variabilele. Mai mult, ele pot
fi folosite la definirea unor constante:
Const csMinut=60
Const csOra=csMinut * 60
Putem atribui şi tipuri de date constantelor, astfel încât Access
să le poată recunoaşte şi să putem efectua diferite operaţii cu
ele:
Const csPi As Double = 3.14
Constantele intrinsece sunt constnte definite în Access. În tabelul
7.2 am inclus şi coloana “Constanta intrinsecă”, ce conţine
numele constantelor ale căror valori sunt returnate de funcţia
VarType. Astfel, putem scrie în codul nostru ori:
If VarType (avrOrice) = 2 Then …
Ori
If VarType (avrOrice) = vbInteger Then …
Rămâne la alegerea dumneavoastră care dintre liniile de mai sus
este mai clară. În tabelul 7.2 sunt enumerate doar câteva dintre
constantele intrinsece definite în Access.
7.3.4 Vizibilitatea şi durata de viaţă a variabilelor
Vizibilitatea unei variabile este dată de porţiunea de cod în care
ea poate fi folosită şi depinde de locul în care a fost declarată.
Vizibilitatea unei variabile create în cadrul unei proceduri se reduce
doar la acea procedură. O variabilă poate fi declarată şi în afara
oricărei proceduri, în cadrul secţiunii (General) (Declarations) a
unui modul. În acest caz, ea poate fi folosită de către toate
procedurile din modulul respectiv (şi, uneori, şi din alte module)
şi spunem că vizibilitatea sa este publică.
Durata de viaţă a unei variabile e dată de perioada în care ea va
putea conţine o valoare. Astfel, o variabilă locală a unei proceduri
“trăieşte” atâta timp cât se rulează procedura respectivă şi
este recreată la următorul apel al procedurii. Dacă doriţi ca o
variabilă locală să existe şi după terminarea procedurii,
folosiţi cuvântul cheie Static la declararea ei. Putem declara şi o
procedură ca fiind statică, astfel încât toate variabilele sale
locale să fie statice.
Variabilele publice există atâta timp cât este deschisă baza de
date.
În Access 97 puteţi stabili şi vizibilitatea procedurilor, folosind
cuvintele cheie Public şi Private. O procedură având specificatorul
Private poate fi apelată numai din interiorul modulului în care este
declarată, în timp ce o procedură cu specificatorul Public poate fi
apelată din orice alt modul.
Pentru a putea apela o procedură din fereastra Debug, aceasta trebuie
să fie publică.
În exemplele de proceduri pe care le-am prezentat până acum, toate
variabilele erau locale şi deci valorile lor se pierdeau după
terminarea rulării procedurilor în care erau declarate. În
continuare, ne vom ocupa de variabilele statice şi publice.
7.3.4.1 Variabile statice
Pentru ca o variabilă declarată într-o procedură să-şi păstreze
valoarea şi între două apeluri ale procedurii, ea trebuie să fie
declarată folosind cuvântul cheie Static, în locul lui Dim. O astfel
de variabilă va fi iniţializată o singură dată: la primul apel al
procedurii. Pentru a studia mai bine variabilele statice, să
considerăm următorul exemplu:
Sub VarStatic()
Static intVar As Integer
intVar = intVar + 1
Debug.Print intVar
End Sub
Rulaţi subrutina de mai multe ori. Rezultatele vor fi cele din figura
7.5.
Fig. 7.5
Dacă intVar nu ar fi fost declarată ca statică, subrutina ar fi
tipărit de fiecare dată aceeaşi valoare: 1. Pentru ca toate
variabilele unei proceduri să fie statice, folosiţi cuvântul cheie
Static înaintea declaraţiei procedurii:
Static Sub VarStatic()
7.3.4.2 Variabile publice
Există două tipuri de variabile publice în Access:
• Variabile publice în cadrul unui modul
• Variabile publice în cadrul aplicaţiei
Variabilele publice în cadrul unui modul se declară cu ajutorul
instrucţiunii Dim la secţiunea (General) (Declarations) a modulului
şi pot fi folosite de către toate procedurile modulului. Următorul
exemplu foloseşte astfel de variabile.
1. La secţiunea (Declarations) a unui modul declaraţi variabila
intVarModul astfel:
Dim intVarModul As Integer
2. Creaţi următoarele două subrutine:
Sub Incrementare ()
intVarModul = intVarModul + 1
End Sub
Şi
Sub Tiparire ()
Debug.Print intVarModul
End Sub
3. Apelaţi de mai multe ori ambele subrutine din fereastra Debug.
Figura 7.6 prezintă rezultatele.
Fig. 7.6
4. Creaţi o a 3-a procedură, în acelaşi modul:
Sub LocalVar()
Dim intVarModul As Integer
IntVarModul = 50
Debug.Print intVarModul
End Sub
2. Apelaţi acum subrutina LocalVar şi apoi, din nou, pe Tiparire. În
figura 7.7 puteţi vedea ce se întâmplă.
LocalVar lucrează cu variabila intVarModul declarată în interiorul
său fără a modifica sau a fi afectată de variabila publică
intVarModul, chiar dacă acestea au acelaşi nume.
Fig. 7.7
Notă: Pentru a evita confuziile este bine, totuşi, să alegeţi
pentru variabilele locale nume diferite de cele ale variabilelor
publice.
Variabilele publice în cadrul aplicaţiei pot fi accesate din toate
modulele aplicaţiei, dar pot fi declarate numai în cadrul secţiunii
(General) (Declarations) a unui modul standard. Aceste variabile se
declară înlocuind instrucţiunea Dim cu instrucţiunea Public:
Public intVarPublic As Integer
Nu puteţi declara variabile publice în cadrul procedurilor.
Notă: Folosiţi variabile publice în cadrul aplicaţiei numai dacă
este neapărat nevoie. Astfel vă puteţi feri de erorişi codul
dumneavoastră va fi mai uşor de întreţinut şi de refolosit. Dacă
veţi dori ca mai multe proceduri să folosească o anumită valoare,
daţi-o ca parametru sau ca valoare de retur.
7.4. Instrucţiuni de control
VBA vă oferă posibilitatea de a testa în cadrul procedurilor
anumite condiţii şi de a efectua operaţii diferite în funcţie de
rezultatele testelor. În continuare, vom studia instrucţiunile VBA
care vă permit luarea de decizii în urma unor astfel de teste.
7.4.1 Instrucţiunea If…Then
Veţi folosi această instrucţiune în cazul în care veţi dori să
executaţi anumite operaţii doar dacă o condiţie este adevărată.
Ea are două sintaxe. Dacă instrucţiunea este folosită pe o singură
linie de cod, sintaxa este:
If conditie Then instructiune
Altfel, dacă instrucţiunea e compusă din mai multe linii de cod:
If conditie Then
Instructiuni
End If
Cea de-a doua variantă este utilă atunci când doriţi să se
execute mai multe instrucţiuni în cazul în care condiţia este
adevărată.
Următorul exemplu ilustrează folosirea ambelor variante ale
instrucţiunii If…Then:
Sub TestIfThen (strDat As String, strCautat As String)
Dim strRezultat As String
If strDat = “” Then strRezultat = “Sirul dat este vid”
If InStr (strDat, strCautat) Then
strRezultat = strCautat
strRezultat = strRezultat & “ se afla in “ & strDat
End If
Debug.Print strRezultat
End Sub
Figura 7.8 prezintă două exemple de execuţie a subrutinei
TestIfThen.
Fig 7.8
În cadrul subrutinei TestIfThen am folosit o funcţie predefinită
în Access, InStr, care verifică dacă un şir de caractere se
regăseşte în alt şir şi returnează poziţia la care apare şirul
căutat în şirul sursă sau 0 dacă şirul căutat nu se regăseşte
în şirul sursă.
Orice expresie poate apărea în cadrul clauzei If. Dacă expresia se
evaluează la ceva diferit de 0, ea e considerată a fi adevărată,
şi falsă dacă valoarea ei este zero.
7.4.2 Instrucţiunea If…Then…Else
Pentru a specifica ce operaţii trebuie efectuate în cazul în care
condiţia e falsă, folosiţi aceasta instrucţiune. De exemplu:
If InStr (strDat, strCautat) Then
strRezultat = strCautat & “ se afla in “ & strDat
Else
strRezultat = strCautat & “ nu se afla in “ & strDat
End If
7.4.3 Instrucţiunea ElseIf
Puteţi privi această instrucţiune ca pe un mijloc de a imbrica mai
multe instrucţiuni If…Then…Else şi deci, de a verifica mai multe
condiţii. Iată un exemplu:
If strDat = “” Then
strRezultat = “Sirul dat este vid”
ElseIf InStr(strDat, strCautat) Then
strRezultat = strCautat & “ se afla in “ & strDat
Else
strRezultat = strCautat & “ nu se afla in “ & strDat
End If
Astfel, dacă prima condiţie nu e adevărată, se verifică cea de-a
doua şi, dacă nici aceasta nu e adevărată, se execută
instrucţiunea din cadrul clauzei Else. În acest mod puteţi folosi
oricâte instrucţiuni EndIf.
7.4.4 Instrucţiunea Select Case
Atunci când trebuie să testaţi mai multe condiţii şi să
efectuaţi pentru fiecare un anumit set de operaţii, folosirea
instrucţiunilor ElseIf poate să devină greoaie. Puteţi folosi, în
schimb, o instrucţiune Select Case care să facă acelaşi lucru.
Astfel, următoarele două secvenţe de cod duc la acelaşi rezultat:
If intVarsta<=18 Then
…
ElseIf intVarsta>=19 And intVarsta<=25 Then
…
ElseIf intVarsta>=26 And intVarsta<=40 Then
…
Else
…
End If
Şi
Select Case intVarsta
Case Is <=18
…
Case 19 To 25
…
Case 26 To 40
…
Case Else
…
End Select
Se poate observa că cea de-a doua variantă este mult mai uşor
lizibilă. Expresiile clauzelor Case se testează în ordinea în care
sunt date şi, în momentul în care este întâlnită o expresie
adevărată, se vor executa instrucţiunile corespunzătoare şi se va
ieşi din instrucţiunea Select Case. Astfel, dacă expresiile a două
dintre clauzele Case sunt adevărate, va fi executat numai codul
corespunzător primeia dintre ele, nemaifăcându-se apoi nici o
verificare.
Instrucţiunea Select Case de mai sus poate fi scrisă şi astfel:
Select Case intVarsta
Case Is <=18
…
Case 19, 20, 21, 22, 23, 24, 25
…
Case 26 To 40
…
Case Else
…
End Select
Existenţa clauzei Case Else în cadrul unei instrucţiuni Select Case
nu este obligatorie. Ea poate fi însă utilă în cazul în care
variabila testată poate avea şi altă valoare decât cele cuprinse
în clauzele Case.
Notă: Variabila testată poate conţine atât valori numerice, cât
şi şiruri de caractere sau date.
7.4.5 Instrucţiunea IIf (Immediate If)
Această instrucţiune este aproape echivalentă cu instrucţiunea
If…Then…Else. Spunem “aproape” pentru că există o diferenţă
în modul în care sunt executate cele două instrucţiuni. Iată mai
întâi care este sintaxa instrucţiunii IIf:
IIf (conditie, valoarea1, valoarea2)
Unde:
conditie este condiţia care trebuie să fie testată;
valoarea1 este valoarea returnată în cazul în care condiţia e
adevărată;
valoarea2 este valoarea returnată când condiţia e falsă.
Să considerăm acum următoarele două funcţii:
Function Impartire(intImpartitor As Integer, intDeimp As Integer) As_
Double
If intImpartitor = 0 Then
Impartire = 0
Else
Impartire = intDeimp /intImpartitor
End If
End Function
Şi
Function Impartire(intImpartitor As Integer,
intDeimp As Integer) As_ Double
Impartire = IIf(intImpartor = 0, 0, intDeimp /intImpartitor)
End Function
Aparent, cele două funcţii fac acelaşi lucru. Diferenţa constă
în faptul că în prima funcţie, dacă este îndeplinită condiţia
instrucţiunii IIf, se execută instrucţiunea Impartire = 0 şi se
iese din instrucţiunea If…Then…Else fără alte verificări. În
instrucţiunea IIf din cea de-a doua funcţie se evaluează însă
toate argumentele. Astfel, dacă intImpartitor = 0, la evaluarea lui
intDeimp /intImpartitor va rezulta o eroare.
Faptul că în instrucţiunea IIf se evaluează toate argumentele, nu
numai că încetineşte execuţia procedurii, dar poate duce şi la
erori.
7.5 Instrucţiuni iterative
Există situaţii, foarte des întâlnite în programare, când un
anumit bloc de instrucţiuni trebuie să fie executat de mai multe ori.
Pentru astfel de operaţii, VBA vă pune la dipoziţie instrucţiunile
For…Next şi Do…Loop, despre care vom vorbi în continuare.
7.5.1 Instrucţiunea For…Next
Această instrucţiune este utilă atunci când ştiţi precis câte
iteraţii aveţi de efectuat. Sintaxa ei este:
For contor = val_initiala To val_finala [Step pasul]
…
Next [contor]
Unde:
• contor – este variabila care se incrementează la fiecare
iteraţie
• val_initiala – valoarea iniţială a variabilei contor
• val_finala – valoarea finala a variabilei contor
• pasul – valoarea cu care se incrementează variabila contor la
fiecare iteraţie.
Valoarea implicită a pasului este 1. Pasul poate fi şi negativ, caz
în care variabila contor va descreşte la fiecare iteraţie cu
valoarea absolută a pasului.
For intCont = 1 To intTotal Step2
Debug.Print intCont
Next
În exemplul de mai sus, valoarea iniţială a contorului intCont este
1 şi la fiecare pas această valoare creşte cu două unităţi,
până când se egalează valoarea variabilei intTotal. De asemenea, la
fiecare iteraţie se va afişa valoare lui intCont.
7.5.2 Instrucţiunea Do…Loop
Pentru cazurile în care cunoaşteţi dinainte numărul de iteraţii
ce trebuie efectuate, instrucţiunea For…Next este ideală. Sunt
însă şi situaţii în care un set de instrucţiuni trebuie să se
execute până când sau atâta timp cât o anumită condiţie este
satisfăcută. În astfel de cazuri, veţi folosi instrucţiunea
Do…Loop, care are următoarele sintaxe:
Do Until conditie
bloc de instructiuni Loop
Sau:
Do
bloc de instructiuni Loop Until conditie
Sau:
Do While conditie
bloc de instructiuni
Loop
Sau:
Do
bloc de instructiuni
Loop While conditie
Primele variante ale instrucţiunii Do…Loop execută blocul de
instrucţiuni până când condiţia va deveni adevărată (adică
atâta timp cât ea este falsă). Deosebirea dintre ele este aceea că
în cea de-a doua variantă blocul de instrucţiuni se execută cel
puţin o dată. Ultimele două variante execută blocul de
instrucţiuni atâta timp cât condiţia e adevărată, cu deosebirea
că, în cazul ultimei variante, blocul de instrucţiuni se execută
cel puţin o dată.
7.5.3 Întreruperea iterării
Atât în cazul instrucţiunii For…Next, cât şi în cel al
instrucţiunii Do…Loop, ştim când anume se va opri procesul
iterativ. VBA vă dă însă şi posibilitatea de a întrerupe acest
proces la o anumită iteraţie, cu ajutorul instrucţiunii Exit. De
exemplu:
For intCont = 1 To intTotal
If intStop Then
Exit For
End If
Debug.Print intCont
Next
Dacă intStop este diferit de zero, procesul iterativ se opreşte,
indiferent de valoarea lui intCont.
În mod asemănător, pentru a părăsi o subrutină sau o funcţie,
puteţi folosi instrucţiunile Exit Sub sau Exit Function.
7.6 Matrice
O matrice poate fi privită ca o mulţime de variabile de acelaşi
tip, având aceleaşi nume şi care stochează informaţii similare.
Fiecărei variabile ce compune matricea îi corespunde un indice (un
număr de ordine). Dacă numărul de elemente ale matricei a fost
specificat la declarare, matricea se numeşte statică; altfel, ea se
numeşte dinamică.
7.6.1 Matrice statice
După ce aţi fixat un număr de elemente la declararea matricei,
acesta nu mai poate fi schimbat pe parcurs. Matricele statice se
declară astfel:
Dim nume_matrice (ip To iu) As tip_de_date
Unde:
nume_matrice – este identificatorul (numele) matricei
ip – este indicele primului element
iu – este indicele ultimului element
tip_de_date – este tipul datelor stocate în matrice.
Notă: Nu confundaţi matricele statice cu variabilele statice.
Repetăm faptul că o variabilă statică e o variabilă declarată cu
ajutorul cuvântului cheie Static şi îşi păstrează valoarea şi
după terminarea procedurii în care a fost declarată, iar o matrice
statică este o matrice al cărei număr de elemente a fost specificat
la declarare.
La rândul lor, matricele statice pot fi declarate, asemeni
variabilelor, cu ajutorul instrucţiunilor Dim, Static, Private sau
Public.
În continuare, vă prezentăm o subrutină ce ilustrează folosirea
matricelor statice:
Sub MatriceStat ()
Dim i As Integer
Dim iMatrice (1 To 5) As Integer
iMatrice (1) = InputBox (“Introduceti primul element”,
“Matrice”)
For i = 2 To 5
iMatrice (i) = InputBox (“Introduceti al “ & i & ”-lea
element”, “Matrice”)
Next i
Debug.Print “Primul element este “ & iMatrice(1)
For i = 2 To 5
Debug.Print “All “ & i & “-lea element este “ & iMatrice(i)
Next i
End Sub
Rulaţi subrutina (apelând-o de la fereastra Debug). Vor apărea
întâi cinci cutii de dialog care vă vor cere să introduceţi câte
un element, apoi elementele introduse vor fi afişate ca în figura
7.9.
Fig 7.9
Observaţi că am folosit funcţia predefinită InputBox, care
afişează o cutie de dialog ce permite utilizatorului să introducă o
valoare, pe care funcţi o returnează. Astfel, după ce fiecare
element al matricei a primit câte o valoare introdusă de utilizator,
matricea este parcursă cu ajutorul instrucţiunii iterative
For…Next, pentru a afişa valorile stocate.
Indici
Nu este obligatoriu ca indicele primului element al unei matrici să
fie 1; el poate fi orice număr întreg, de exemplu:
Dim iMatrice(5 To 14) As Integer
este declaraţia unei matrice de 10 elemente numere întregi.
Dacă nu specificaţi indicele primului element al unei matrici,
Access va considera în mod implicit că acesta e zero. Astfel,
următoarele două declaraţii sunt echivalente:
Dim iMatrice(9) As Integer
şi
Dim iMatrice(0 To 9) As Integer
Dacă veţi dori ca indicele implicit al primului element să nu fie
0, ci un altul (1, de exemplu), introduceţi la secţiunea
(Declarations) a modulului următoarea linie de cod:
Option Base 1
7.6.2 Matrice dinamice
Dacă nu cunoaşteţi de la început numărul de elemente pe care
trebuie să le aibă o matrice, puteţi să o declaraţi ca fiind
dinamică. Astfel de matrice se declară tot cu ajutorul
instrucţiunilor Dim, Static, Private sau Public, dar punând două
paranteze rotunde după numerele matricei. Apoi, cu ajutorul
instrucţiunii ReDim, puteţi fixa indicii primului şi ultimului
element al matricei.
În continuare, vom modifica exemplul anterior astfel încât
utilizatorul să poată introduce numărul de elemente ale matricei.
Sub MatriceDin()
Dim i As Integer
Dim iTot As Integer
Dim iMatrice() As Integer
ITot = InputBox(“Introduceti numarul total de elemente”)
ReDim iMatrice(1 To iTot)
iMatrice(1) = InputBox(“Introduceti primul element”, “Matrice”)
For i = 2 To iTot
iMatrice(1) = InputBox(“Introduceti al “ & i & “-lea element”,
“Matrice”)
Next i
Debug.Print “Primul element este “ & iMatrice(1)
For i = 2 To iTot
Debug.Print “Al “ & i & “-lea element este “ & iMatrice(i)
Next i
End Sub
După ce aţi specificat, cu ajutorul instrucţiunii ReDim, indecşii
primului şi ultimului element al matricei, puteţi folosi din nou
instrucţiunea ReDim pentru a modifica aceşti indecşi (şi deci,
dimensiunea totală a matricei). În mod normal, modificând aceşti
indecşi se vor pierde valorile stocate de elementele matricei. Pentru
a preveni acest lucru, folosiţi cuvântul cheie Preserve. Astfel,
dacă declarăm următoarea matrice:
Dim iMatrice () As Integer
…
ReDim iMatrice (1 To 10)
şi dorim ulterior să reducem la cinci elemente fără a pierde
valorile primelor 5, vom scrie:
ReDim Preserve iMatrice (1 To 5)
7.6.3 Detectarea matricelor
Există trei funcţii care ne ajută să aflăm dacă o variabilă
este simplă sau este o matrice: IsArray, VarType şi TypeName.
Funcţia IsArray returnează valoarea True dacă variabila care îi
este dată drept argument este o matrice şi False dacă nu.
Despre funcţia VarType am mai vorbit şi în secţiunea 7.3.2, unde
am dat şi tabelul cu valorile pe care aceasta le poate returna. Aţi
putut observa în acel tabel că unei variabile de tip matrice îi
corespunde valoarea de retur 8192 (sau constanta intrinsecă vbArray).
Astfel, dacă variabila dată ca argument funcţiei VarType este o
matrice, funcţia va avea ca valoare de retur 8192 plus valoarea
corespunzătoare tipului variabilelor ce compun matricea.
Sub TestMatrice()
Dim iNum As Integer
Dim iMatrice (1 To 10) As Integer
Debug.Print “iNum: “ & VarType(iNum)
Debug.Print “iMatrice: “ & VarType(iMatrice)
End Sub
Dacă veţi rula subrutina Test Matrice, în fereastra Debug vor
apărea valorile 2 şi 8194, ca în figura 7.10.
Fig 7.10
Observaţi că pentru variabila iMatrice, funcţia VarType a returnat
valoarea 8194, adică 8192 pentru matrice, plus 2 pentru tipul Integer
(care e tipul elementelor matricei).
Funcţia TypeName se aseamănă cu VarType, cu diferenţa că în
locul valorii corespunzătoare unui tip de date, ea returnează chiar
numele tipului respectiv. Spre exemplu, următoarea subrutină:
Sub TestMatrice1 ()
Dim iNum As Integer
Dim iMatrice (1 To 10) As Integer
Debug.Print “iNum: “ & TypeName (iNum)
Debug.Print “iMatrice: “ & TypeName (iMatrice)
End Sub
va da rezultatele din figura 7.11.
Figura 7.11
7.6.4 Matrice multidimensionale
Până acum am vorbit numai despre matrice unidimensionale, numite şi
vectori. Matricele pot avea însă şi două, trei sau mai multe
dimensiuni.
Pentru a declara o matrice multidimensională, trebuie să
specificaţi marginile inferioare şi superioare ale indicilor pentru
fiecare dimensiune, separate prin virgulă. Astfel, pentru a declara o
matrice bidimensională cu 6 elemente şi cu indicii începând de la
1, scrieţi:
Dim iMatrice(1 To 2, 1 To 3) As Integer
sau, pentru o matrice de aceeaşi dimensiune dar cu indicii începând
de la 0 (presupunând că nu s-a specificat opţiunea Option Base 1):
Dim iMatrice(1, 2 ) As Integer
Notă: Teoretic, numărul maxim de dimensiuni ale unei matrici este 60.
Practic, însă nu veţi folosi matrice cu mai mult de patru
dimensiuni, deoarece ar fi foarte greu de lucrat cu ele.
7.6.4.1 Matrice multidimensionale dinamice
Ca şi cele unidimensionale, matricele multidimensionale pot fi
declarate ca fiind dinamice, pentru ca numărul dimensiunilor şi
marginile fiecărei dimensiuni să poată fi stabilite ulterior.
Sintaxa este următoarea:
Dim iMatrice() As Integer
…
ReDim iMatrice(1 To 2, 1 To 3)
Sau, pentru ca indicii matricei să înceapă de la 0:
Dim iMatrice() As Integer
…
ReDim iMatrice(1, 2)
O astfel de matrice are 2x3 = 6 elemente. Similar, prin instrucţiunea
următoare:
ReDim iMatrice(1, 2, 3)
matricea va fi tridimensională şi va conţine2x3x4=24 de elemente.
7.6.4.2 Accesarea componentelor unei matrice multidimensionale
Pentru a accesa un element al unei matrice multidimensionale, trebuie
să specificaţi indicii corespunzători fiecărei dimensiuni a
matricei, ce caracterizează elementul respectiv. Următoarea
subrutină declară o matrice bidimensională şi o umple cu anumite
valori, pe care apoi le afişează. Fiecărui element al matricii îi
vom da ca valoare suma indicilor care îi corespund.
Sub Matrice()
Dim i As Integer
Dim j As Integer
‘ crearea matricei dinamice
Dim iMat() As Integer
‘ redimensionarea matricei
ReDim iMat(1 To 2, 1 To 3)
For i = 1 To 2
For j = 1 To 3
iMat (i, j) = i+j
Next
Next
For i = 1 To 2
For j = 1 To 3
Debug.Print i & “ + “ & j & “ = “ & iMat(i, j)
Next
Next
End Sub
Rulând subrutina de mai sus, veţi obţine rezultatele din figura
7.12.
Fig. 7.12
7.6.5 Ştergerea matricelor dinamice
O matrice ocupă în memorie 20 de octeţi, plus câte 4 octeţi
pentru fiecare dimensiune, plus numărul de octeţi necesari datelor
stocate, adică numărul de elemente ale matricei înmulţit cu
numărul de octeţi ocupaţi de tipul respectiv de date. Astfel,
matricea iMatrice (1, 2, 3) ocupă în memorie:
20 octeţi + 3x4 octeţi + (2x3x4)x2 octeţi = 80 octeţi.
Pentru a elibera memoria ocupată de o matrice dinamică, puteţi
folosi instrucţiunea Erase astfel:
Erase iMatrice
Folosită pentru matrice statice, instrucţiunea Erase le va
reiniţializa, fără să elibereze memoria ocupată de acestea.
7.6.6 Folosirea matricelor ca parametri pentru proceduri
Access vă permite să daţi şi matrice ca parametri funcţiilor şi
subrutinelor. Un paametru-matrice (sau matrice de parametri) vă dă
posibilitatea de a crea proceduri cu un număr variabil de parametri.
De exemplu, următoarea funcţie calculează media aritmetică a
numerelor ce îi sunt date ca parametri:
Function Media (ParamArray aNum() ) As Double
Dim valCrt
Dim dblSuma As Double
For Each valCrt In aNum
dblSuma = dblSuma + valCrt
Next
Media = dblSuma / (UnBound (aNum) + 1)
End Function
Dacă în fereastra Debug scrieţi:
?Media (1,2,3,4,5)
şi apăsaţi tasta Enter, veţi obţine rezultatul 3.
Iată trei lucruri esenţiale pe care trebuie să le aveţi în vedere
când lucraţi cu parametri de tip matrice:
• Pentru a declara o matrice ca parametru al unei proceduri,
precedaţi-o cu cuvântul cheie ParamArray.
• Un parametru de tip matrice poate apărea doar pe ultima poziţie
în lista de parametri ai unei proceduri.
• Matricele de parametri pot fi numai de tipul Variant.
Funcţia Media calculează întâi suma tuturor elementelor matricei de
parametri, pe care o împarte apoi la numărul total de elemente.
Notă: Indicii matricelor de parametri încep întotdeauna de la zero,
indiferent dacă în modulul ce conţine procedura aţi specificat sau
nu opţiunea Option Base 1.
Funcţia predefinită Ubound returnează valoarea celui mai mare indice
al unei matrice. Cum indicii matricei de parametri aNum încep de la 0,
numărul total de elemente este Ubound(aNum) + 1.
7.7 Lucrul cu biblioteci DLL şi cu funcţii Windows API
Vom vorbi în continuare despre una dintre cele mai importante
facilităţi oferite de VBA: posibilitatea de a apela un DLL (Dynamic
Link Library) dintr-o procedură VBA. Astfel, puteţi realiza mai mult
decât vă permit funcţiile predefinite şi instrucţiunile VBA:
puteţi controla sistemul de operare Windows.
Windows vine cu mai multe biblioteci DLL, ce conţin sute de funcţii
utile pentru programatori. Aceste funcţii formează ceea ce poartă
numele de Windows API (prescurtarea API vine de la Application
Programming Interface, adică interfaţa de programare a aplicaţiilor
Windows).
Dar ce este, de fapt, un DLL? Este un fişier sursă ce conţine un
număr mare de funcţii (o bibliotecă de funcţii). Programatorul
poate folosi o funcţie DLL într-un program de-al său fără ca acel
program să conţină o copie a funcţiei respective. Indiferent de
numărul aplicaţiilor ce apelează funcţii dintr-un DLL la un moment
dat, biblioteca DLL se încarcă în memorie o singură dată, şi
anume, prima oară când s-a apelat o funcţie din el. Apoi, după ce
aplicaţiile nu mai au nevoie de funcţiile sale, biblioteca DLL este
descărcată din memorie.
7.7.1 Declararea funcţiilor API
Înainte de a putea apela o funcţie dintr-un DLL, trebuie să-I daţi
indicaţii lui Access unde se află funcţia şi cum anume să o
apeleze. Acest lucru îl realizaţi cu ajutorul instrucţiunii Declare,
incluzând practic o declarare a funcţiei la secţiunea (General)
(Declarations) a modului în care se face apelul. Printr-o astfel de
declaraţie, VBA primeşte şase informaţii:
• Domeniul de vizibilitate al funcţiei;
• Numele pe care îl veţi folosi în codul dumneavoastră pentru a
apela funcţia;
• Numele şi calea bibliotecii DLL care o conţine;
• Numele funcţiei, aşa cum este ea definită în DLL;
• Numele şi tipul argumentelor;
• Tipul valorii returnate (dacă aceasta există).
Dacă funcţia returnează o valoare, sintaxa instrucţiunii Declare
este:
[Public | Private] Declare Function denumireaFunctiei_
Lib “numeleBibliotecii” [Alias “numeleDinDLLAlFunctiei”]_
[([argumente])] [As tip]
iar dacă funcţia nu returnează nici o valoare:
[Public | Private] Declare Sub denumireaFunctiei_
Lib “numeleBibliotecii” [Alias “numeleDinDLLAlFunctiei”]_
[([argumente])]
7.7.1.1 Domeniul de vizibilitate al funcţiei API
Ca şi în cazul unei proceduri VBA obişnuite, puteţi stabili
vizibilitatea funcţiilor declarate prin intermediul instrucţiunii
Declare. Astfel, dacă instrucţiunea Declare e precedată de cuvântul
cheie Private, funcţia API nu va fi apelată decât din modulul în
care a fost declarată. Dacă folosiţi cuvântul cheie Public (care e
şi implicit), funcţia va putea fi apelată din orice modul.
7.7.1.2 Denumirea funcţiei API
În cadrul instrucţiunii Declare trebuie să specificaţi şi
denumirea pe care o veţi folosi în codul dumneavoastră pentru a
apela funcţia API respectivă. Această denumire trebuie să respecte
regulile impuse pentru orice procedură VBA: să înceapă cu o
literă, să conţină numai caractere alfanumerice sau caracterul
underscore(_), să fie unicîn cadrul domeniului său de vizibilitate,
să conţină maximum 255 de caractere şi să nu fie un cuvânt cheie
VBA. Dacă nu folosiţi clauza Alias pentru a specifica numele din DLL
al funcţiei, denumirea trebuie să fie exact aceeaşi cu acest nume
din DLL.
7.7.1.3 Specificarea bibliotecii DLL
În cadrul clauzei Lib a instrucţiunii Declare trebuie să
specificaţi, între ghilimele, numele bibliotecii DLL şi, eventual,
locaţia sa pe disc. Dacă biblioteca DLL este una dintre principalele
biblioteci DLL din Windows, puteţi omite extensia .DLL (de exemplu,
“User32”, “GDI32” sau “Kernel32”). Dacă nu specificaţi
calea completă pentru DLL, Windows îl va căuta în ordine:
1. în directorul în care se află Access;
2. în directorul curent;
3. numai pentru Windows NT: în directorul Windows\System32;
4. în directorul Windows\System;
5. în directorul Windows;
6. în directoarele din PATH.
7.7.1.4 Clauza Alias
Clauza Alias a instrucţiunii Declare că permite să schimbaţi
numele unei funcţii API din cel specificat în DLL într-unul permis
în VBA. Astfel, dacă aţi specificat o altă denumire pentru funcţie
decât cea dată în DLL, trebuie să includeţi în instrucţiunea
Declare şi clauza Alias, care să conţină numele exact al funcţiei.
De exemplu, pentru a declara funcţia API_lwrite(), trebuie să
folosiţi un alias, deoarece în VBA numele funcţiilor nu pot începe
cu caracterul underscore(_):
Declare Function lwrite Lib “Kernel32” Alias “_lwrite” _
(ByVal hFile As Integer, ByVal lpBuffer As String, ByVal intBytes_
As Integer) As Integer
Astfel, pentru a apela în codul dumneavoastră funcţia_lwrite() din
Kernel32.DLL, veţi folosi denumirea lwrite().
7.7.1.5 Argumente
În mod implicit, Access dă unei proceduri, ca argumente, pointeri la
adresa de memorie a variabilelor şi nu valorile explicite ale
acestora. Cu toate acestea, multe funcţii API aşteaptă să
primească drept argumente valorile variabilelor şi nu pointeri la
adresele lor. În acest caz, trebuie să daţi şi dumneavoastră
acestor funcţii, ca argumente, tot valori şi acest lucru îl
realizaţi plasând cuvântul cheie ByVal în faţa numelor
argumentelor funcţiei din cadrul instrucţiunii Declare:
Declare Function GetSystemMetrics Lib “user32” (ByVal nIndex_
As Long) As Long
Şiruri de caractere ca argumente
Multe funcţii API primesc ca argumente şiruri de caractere ce se
termină cu caracterul ‘\0’ (al cărui cod ASCII este 0). VBA nu
lucrează cu astfel de şiruri de caractere. De aceea, pentru a putea
da un şir VBA ca argument unei funcţii dintr-un DLL, trebuie întâi
să-l transformaţi într-un şir de caractere ce se termină cu
‘\0’. Tot cuvântul cheie ByVal vă ajută şi de această dată.
Astfel, dacă folosiţi acest cuvânt cheie pentru un argument de tip
String, VBA îl converteşte într-un şir terminat cu ‘\0’ şi
apoi îi dă funcţiei API respective un pointer la adresa de memorie a
şirului. Deşi acest fapt vine în contradicţie cu ce am spus până
acum, el se aplică totuşi şirurilor în VBA.
Dacă o funcţie dintr-un DLL primeşte ca argument valoarea unei
variabile, ea nu va putea modifica efectiv această valoare. Dacă
însă funcţia primeşte adresa de memorie a variabilei, atunci ea îi
poate modifica valoarea. Cum aceasta se întâmplă şi în cazul
şirurilor de caractere, pot apărea probleme. Dacă funcţia din DLL
modifică valoarea şirului de caractere primit ca argument şi noua
valoare conţine mai multe caractere, funcţia nu modifică şi
dimensiunea şirului. Ea scrie noul şir la adresa respectivă,
suprascriind caracterul ‘\0’ şi ocupând în continuare locaţii
de memorie adiacente. Acest fapt poate duce la blocarea aplicaţiei şi
chiar a sistemului. Pentru a-l evita, trebuie să vă asiguraţi că
şirul pe care-l daţi funcţiei ca argument este suficient de mare
pentru a putea păstra valorile pe care aceasta i le va atribui.
Puteţi folosi în acest scop un şir de caractere de lungime fixă,
suficient de mare:
Dim strSir As String* 255
Matrice ca argumente
Puteţi da ca argumente unei funcţii API elementele unei matrici aşa
cum i-aţi da orice altă variabilă. Pentru a face acest lucru, pur
şi simplu daţi funcţiei ca argument primul element al matricei.
Funcţia va şti să regăsească şi celelalte elemente. Deoarece
elementele unei matrice se află la locaţii consecutive de memorie,
este suficient ca funcţia să ştie unde începe matricea şi
dimensiunea ei. Nu puteţi da ca argument unei funcţii dintr-un DLL.
Transformarea tipurilor de date ale argumentelor
Deoarece majoritatea bibliotecilor DLL sun scrise în C sau C++,
tipurile de date ale argumentelor funcţiilor pe care acestea le
conţin nu sunt aceleaşi cu tipurile de date VBA. De aceea, e necesar
să folosim în instrucţiunea Declare tipul de date VBA corespunzător
tipului C al argumentului funcţiei din DLL. Tabelul 7.13 arată
corespondenţele dintre tipurile date din limbajul C şi tipurile VBA.
Tip de date în C Corespondent în VBA
ATOM, BOOL, HFILE, int, UINT, WORD, WPARAM ByVal i As Integer
int FAR*, UINT FAR* i As Integer
BYTE ByVal byt As Byte
BYTE* byt As Byte
CALLBACK, DWORD, FARPROC, HACCEL, HANDLE, HBITMAP, HBRUSH, HGLOBAL,
HICON, HINSTANCE, HLOCAL, HMENU, HMETAFILE, HMODULE, HPALETTE, HPEN,
HRGN, HRSRC, HTASK, HWND, LONG, LPARAM, LRESULT ByVal adr As Long
Char*, LPSTR, LPCSTR ByVal str As String
Tabelul 7.13
Tipuri-utilizator
Multe funcţii API primesc argumente ce au ca tip de date alte tipuri
decât cele predefinite. Acestea se numesc tipuri de date definite de
utilizator sau tipuri-utilizator. Un tip-utilizator poate fi o
structură în C, adică un mod de a grupa variabile de tipuri diferite
şi care împreună definesc un nou concept. Una dintre structurile cel
mai des folosite în bibliotecile DLL este structura RECT, ce
reprezintă un dreptunghi prin distanţele laturilor sale faţă de
marginea din stânga şi, respectiv, de sus a ecranului.
Type RECT
left As Long
top As Long
right As Long
bottom As Long
End Type
este tipul VBA corespunzător structurii RECT în C.
Argumentele ce au ca tip de date un tip-utilizator sunt date prin
referinţă (adică prin intermediul unui pointer la adresa din memorie
a unei variabile de acel tip).
Pointeri nuli
Există şi cazuri când o funcţie API aşteaptă ca argument
pointerul nul, care în VBA este dat ca:
ByVal 0&
unde caracterul & arată faptul că pointerul este pe 32 de biţi
(adică Long). Observaţi faptul că pointerul nul trebuie dat ca
argument prin valoare.
De exemplu, funcţia API ClipCursor (pe care o vom folosi în Exemplul
2) are argumentul:
lpRect As Any
Dacă ea primeşte ca argument un pointer la o variabilă de tip RECT,
atunci cursorul va fi capturat în dreptunghiul definit de acea
variabilă. Dacă primeşte ca argument pointerul nul, ea eliberează
cursorul.
Tipul Any este folosit pentru a dezactiva mecanismul Access de
verificare a corespondenţei dintre tipurile argumentelor din
declaraţia unei funcţii şi tipurile argumentelor efective, astfel
încât funcţia poate primi orice tip de date pentru un argument de
tip Any.
Notă: Atunci când lucraţi cu funcţii DLL, este bine să faceţi
regulat copii ale bazei de date. Este de asemenea bine să salvaţi
orice alte informaţii din alte aplicaţii Windows deschise, deoarece
este posibil ca, din cauza unor erori generate de aceste funcţii,
sistemul să se blocheze şi să pierdeţi informaţiile nesalvate.
CAP:8. Lucrul cu obiecte
Unul dintre motivele principale ale apariţiei programării orientate
pe obiecte este nevoia de a modela cât mai bine fenomenele şi
entităţile din lumea înconjurătoare. O maşină, o casă, un
calculator – toate acestea sunt obiecte, care la rândul lor conţin
diferite părţi componente – obiecte şi ele. Caracteristica cea mai
importantă a obiectelor este aceea că ele conţin toate informaţiile
necesare pentru a funcţiona. În Access 97, un formular este un
obiect. El ştie tot ce trebuie pentru a-şi face datoria. De exemplu,
dacă apăsaţi butonul Cnacel, formularul se închide; dacă apăsaţi
butonul Minimize din bara de titlu, formularul se minimizează etc.
Astăzi întâlnim obiecte în mai toate domeniile programării:
programare obiectuală sistem, sisteme de gestiune a bazelor de date
orientate pe obiecte, programare obiectuală în proiectare, jocuri
orientate obiectual, peste tot, numai programare obiectuală. Şi toate
acestea se datorează avantajelor pe care aceasta le oferă faţă de
limbajele procedurale tradiţionale:
• Eficienţă mai mare datorată posibilităţii de a refolosi
cantităţi însemnate de cod din alte aplicaţii, de unde rezultă şi
creşterea complexităţii şi calităţii aplicaţiilor;
• Posibilitatea de a accesa date stocate pe platforme şi sisteme
diferite;
• Posibilitatea de a oferi utilizatorilor metode grafice intuitive
şi prietenoase de comunicare cu sistemul.
În continuare, vom explica termenii cheie ce apar atunci când vorbim
de obiecte.
Proprietăţi
Toate obiectele au ca proprietăţi ce le caracterizează. Aşa cum o
maşină se caracterizează prin marcă, model, culoare şi o groază
de caracteristici tehnice, în Access 97 un formular are şi el o
mulţime de proprietăţi, cum ar fi: titlul (Caption), filtrul
(Filter) etc.
Proprietăţile unui obiect pot fi modificate fie cu ajutorul paginii
de proprietăţi în modul Design View, fie prin intermediul limbajului
VBA.
Metode
Metodele reprezintă modul în care un obiect efectuează diferite
acţiuni. Aşa cum o maşină ştie ce metodă să aplice pentru a
frâna atunci când şoferul apasă pedala de frână, în Access 97
obiectul bază de date (Database) are o metodă pentru a crea un nou
set de înregistrări (OpenRecordset).
Clase
O clasă reprezintă mulţimea tuturor obiectelor care au aceleaşi
proprietăţi şi metode. Un obiect al unei clase poartă numele de
instanţă a clasei respective. O clasă poate avea mai multe subclase
(sau clase derivate) care moştenesc proprietăţile şi metodele
clasei de bază dar, pe lângă acestea, mai au şi propriile lor
proprietăţi şi metode, ce le particularizează.
8.1 Obiectele din Access 97
În Access există două seturi de obiecte: obiectele Access generale
(prezentate în tabelul 8.1) şi obiecte pentru accesarea datelor (Data
Access Objects sau, pe scurt, DAO), prezentate în tabelul 8.2.
Obiect Access Descriere
Application Obiectul Microsoft Access
Control Un control de pe un formular sau raport
DoCmd Acţiuni în VBA
Debug Fereastra Debug
Form Un formular sau subformular deschis
Module Un modul
Report Un raport sau subraport deschis
Screen Ecranul
Section O secţiune a unui formular sau raport
Pages Paginile unui control
References Referinţe la alte biblioteci de obiecte
Tabelul 8.1
Obiect DAO Descriere
Container Un obiect care conţine informaţii despre alte obiecte
Database O bază de date deschisă
DBEngine Motorul bazei de date
Document Informaţii pe care motorul bazei de date le administrează,
despre alte obiecte
Error Erori generate de accesarea datelor
Group Un cont al unui grup de utilizatori
Index Un index pe o tabelă
Parameter Un parametru al unei interogări
Property Proprietatea unui obiect
QueryDef O interogare salvată
Recordset Un set de înregistrări definit de o tabelă sau interogare
Relation O relaţie între două tabele sau interogări
TableDef O tabelă salvată
User Contul unui utilizator
Workspace O sesiune de lucru cu o bază de date
Tabelul 8.2
În continuare, vom vorbi mai pe larg despre obiectele DAO şi despre
cum se folosesc ele.
8.1.1 Colecţii
În tabelul 8.2 aţi văzut că o bază de date este un obiect care
conţine, la rândul său, alte obiecte. În mod asemănător,
formularele conţin controale, iar tabelele, câmpuri. Obiectele care
sunt conţinute într-un alt obiect sunt grupate în colecţii.
Colecţiile pot fi formate numai din obiectele aceleiaşi clase.
Astfel, dacă un obiect conţine mai multe formulare, acestea vor forma
colecţia Forms (formulare) a obiectului respectiv. O colecţie poate
fi deci considerată ca fiind un vector. Figura 8.3 prezintă obiectele
DAO sub forma unei diagrame ierarhice ce arată legăturile dintre
obiecte şi colecţiile lor.
Figura 8.3
În vârful ierarhiei se află DBEngine (motorul bazei de date). El
conţine două colecţii: Errors şi Workspaces (erori şi sesiuni de
lucru). În Workspace este ca un birou al unei clădiri, clădirea
fiind motorul DBEngine. Colecţia Errors conţine o listă cu erorile
apărute în DBEngine.
Aproape toate acţiunile dumneavoastră sunt procesate de motorul
DBEngine şi sunt efectuate asupra unui obiect DAO. De aceea, este
foarte important să înţelegeţi ce sunt obiectele pentru accesarea
datelor şi care sunt relaţiile dintre ele. Pentru aceasta, vom folosi
în continuare fereastra Debug care ne va ajuta să vedem obiectele
stocate în baza noastră de date şi cum sunt ele organizate în
ierarhia DAO.
1. Creaţi un nou modul standard în baza de date curentă (Cursuri
Optionale.mdb). Deschideţi fereastra Debug şi scrieţi în ea:
?DBEngine.Workspaces(0).Name
După ce aţi apăsat tasta Enter, veţi primi următorul rezultat:
#Default Workspace# (adică sesiunea de lucru implicită).
Prin linia de cod scrisă mai sus aţi cerut numele unei sesiuni de
lucru. Obiectul DBEngine, care se află în vârful ierarhiei DAO,
conţine două colecţii: Workspaces şi Errors. Colecţia Workspaces
este, de fapt, o matrice ale cărei elemente sunt obiecte de tip
Workspace. Astfel, DBEngine.Workspaces(0).Name înseamnă
“proprietatea Name (nume) a elementului cu indicele 0 al colecţiei
Workspaces a obiectului DBEngine”.
2. Să coborâm pe o treaptă inferioară a ierarhiei, cerând numele
bazei de date curente. Pentru aceasta, introduceţi în fereastra
Debug:
?DBEngine.Workspaces(0) . Databases(0) .Name
După ce apăsaţi tasta Enter, rezultatul va fi calea completă şi
numele fişierului în care se află baza de date curentă.
Fiecare obiect de tip Workspace conţine trei colecţii: Users
(utilizatori), Gorups (grupuri) şi Databases (baze de date) care, la
rândul lor pot fi privite ca matrice (vectori). Prin linia de cod de
mai sus aţi cerut, aşadar numele obiectului de tip Database cu
indicele 0 din cadrul colecţiei Databases a obiectului Workspaces(0)
al obiectului DBEngine.
3. Mai coborâm o treaptă a ierarhiei şi cerem numele unui obiect al
unei colecţii a obiectului, DBEngine.Workspaces(0) .Databases(0), şi
anume:
?DBEngine.Workspaces(0).Databases(0).TableDefs(0).Name
TableDefs(0) e obiectul cu indicele 0 din matricea TableDefs (tabele
salvate). După ce apăsaţi pe Enter, rezultatul va fi numele unei
tabele din baza de date curentă, şi anume, Curs. Dacă înlocuiţi
TableDefs(0) cu TableDefs(3), veţi obţine un rezultat mai
neobişnuit: MSysACEs. Aceasta deoarece tabelele sunt stocate în
ordine alfabetică în cadrul matricei TableDefs, astfel încât
tabelei sistem MSysACEs (folosită de Access) îi corespunde indicele 3
(primele trei tabele sunt, în ordine alfabetică: Curs, Curs_Prof şi
Curs_Student).
Observaţi că între obiectele de pe trepte consecutive ale ierarhiei
şi între obiecte şi proprietăţile lor se pune un punct.
Continuând ca mai sus, puteţi găsi informaţii despre toate
obiectele stocate într-o bază de date.
În continuare, ne vom ocupa în detaliu cu obiectele şi colecţiile
ierarhiei DAO.
Notă: E important să sesizaţi diferenţa dintre o colecţie şi
tipul elementelor ce o compun. Spre exemplu, Workspaces (la plural)
este numele colecţiei, iar Workspace (la singular) este tipul
elementelor pe care ea le conţine.
Obiectul DBEngine (motorul Jet Engine)
Este obiectul aflat în vârful ierarhiei DAO, este un obiect
predefinit ce nu poate fi creat. Există un singur obiect DBEngine
pentru o aplicaţie. El nu face parte din nici o colecţie şi conţine
toate celelalte obiecte. El poate fi folosit pentru a compacta sau
repara o bază de date, pentru a înregistra baze de date ODBC, pentru
a obţine versiunea motorului Jet şi pentru a stabili timpul maxim
necesar deschiderii sesiunii unui utilizator.
Colecţia Errors (Erori)
Un obiect de tip Error primeşte toate erorile apărute în urma
eşuării unei acţiuni efectuate asupra unui obiect DAO. Erorile sunt
ordonate în cadrul colecţiei în funcţie de codul lor.
Colecţia Workspaces (Sesiuni de lucru)
Un obiect de tip Workspace defineşte o sesiune de lucru pentru un
utilizator. Acest obiect conţine toate bazele de date deschise de acel
utilizator. Tranzacţiile efectuate în cadrul unei sesiuni (obiect de
tip Workspace) sunt globale tuturor bazelor de date ale sesiunii
respective. Access creează implicit obiectul Workspaces(0). Dacă nu
au fost impuse măsuri de securitate asupra bazei de date curente,
proprietăţii Name(nume) a acestui obiect i se dă valoarea #Default
Workspace#, iar proprietăţii UserName(numele utilizatorului) i se dă
valoarea Admin(administrator). Acest obiect implicit nu poate fi şters
sau închis şi este deci disponibil tot timpul.
Colecţia Databases (Baze de date)
Un obiect de tip Database reprezintă o bază de date deschisă sau
creată cu DAO. Cu ajutorul metodei CreateDatabase a unui obiect
Workspace, adăugaţi automat o bază de date la colecţia Database a
sesiunii respective. O bază de date poate fi închisă cu ajutorul
metodei Close, ceea ce o va şterge din cadrul colecţiei. Colecţia
Databases conţine toate bazele de date deschise DAO, plus baza de date
curentă, deschisă în Access (care este obiectul
DBEngine.Workspaces(0). Databases(0) sau CurrentDB).
Colecţia Users (Utilizatori)
Un obiect de tip User reprezintă contul unui utilizator. Vom reveni
cum mai multe detalii despre utilizatori, conturi şi grupuri, când
vom vorbi despre aplicaţii multiuser şi securitate.
Colecţia Groups (Grupuri)
Un obiect de tip Group (grup) reprezintă grupuri de utilizatori şi
drepturile acestora. Fiecare utilizator dintr-un grup e reprezentat
printr-un obiect de tip User din colecţia Users a grupului.
Colecţia QueryDefs (Interogări)
Fiecare interogare salvată în Access sau creată cu ajutorul metodei
CreateQueryDef este reprezentată printr-un obiect de tip QueryDef din
colecţia QueryDefs. Obiectele de tip QueryDef sunt deci instrucţiuni
SQL precompilate. Cu ajutorul unui obiect de tip QueryDef puteţi crea
seturi de înregistrări, îi puteţi regăsi instrucţiunea SQL,
puteţi afla dacă returnează sau nu înregistrări sau puteţi
executa interogarea.
Colecţia TableDefs (Tabele)
Un obiect de tip TableDef reprezintă o tabelă stocată într-o bază
de date. Tabela se poate afla în baza de date curentă sau poate fi
ataşată dintr-o bază de date externă. Cu ajutorul unui obiect de
tip TableDef puteţi afla dacă tabela e ataşată, îi puteţi afla
regulile de validare, dacă poate fi sau nu actualizată sau numărul
de înregistrări.
Colecţia Indexes (Indecşi)
Un obiect de tip index reprezintă un index al unei tabele sau al unui
set de înregistrări.
Colecţia Fields (Câmpuri)
Un obiect de tip Field reprezintă o coloană. Obiectele de tip
Relation (relaţie), Recorset, TableDef, QueryDef şi Index conţin
câte o colecţie Fields. Atributele unui câmp pot fi aflate şi
modificate prin intermediul proprietăţilor obiectului Field
corespunzător.
Colecţia Recordsets (Seturi de înregistrări)
Obiectele de tip Recordset (set de înregistrări) sunt cel mai des
folosite şi deci, poate, cele mai importante obiecte DAO. Aceste
obiecte sunt temporare (nu sunt salvate pe disc).
Colecţia Relations (Relaţii)
Fiecare relaţie dintre două sau mai multe tabele ale unei baze de
date Access e reprezentată printr-un obiect de tip Relation. Colecţia
Relations a unui obiect de tip Database conţine toate relaţiile
definite în baza de ate respectivă.
Colecţia Parameters (Parametri)
Aţi văzut că în Access puteţi crea interogări cu parametri.
Parametrii declaraţi cu ajutorul cuvântului cheie PARAMETERS în
instrucţiunea SQL a unei interogări se numesc parametri formali.
Colecţia Parameters a unui obiect de tip QueryDef e formată din toţi
parametri formali definiţi pentru interogarea respectivă. Nu puteţi
şterge sau adăuga obiecte la colecţia Parameters.
Colecţia Properties (Proprietăţi)
Un obiect de tip Property reprezintă o caracteristică a unui obiect.
Fiecare obiect DAO are o colecţie Properties. Un obiect de tip
Properties poate fi o proprietate predefinită sau una definită de
utilizator. Programatorul poate adăuga proprietăţi (cu ajutorul
metodei CreateProperty) unui anumit obiect şi este responsabil pentru
stabilirea şi modificarea valorilor acestor proprietăţi.
Proprietăţile definite de utilizator sunt singurele care pot fi
şterse din colecţia Properties a unui obiect; proprietăţile
predefinite nu pot fi şterse.
8.1.2 Containere şi documente
Un container este o colecţie de obiecte salvate în Access: baze de
date, formulare, rapoarte, module, tabele, relaţii. Termenul
“document” este o descriere generică pentru un obiect stocat
într-un container. Pentru a înţelege mai bine ce reprezintă
containerele şi documentele, gândiţi-vă la fereastra Database.
Fiecare pagină a acestei ferestre reprezintă un container, iar
fiecare obiect dintr-o pagină este un document.
Pentru a examina containerele şi documentele bazei de date “Cursuri
Optionale.mdb”, vom scrie o subrutină care le va afişa pe ecran.
Sub Containere_Documente()
Dim dbCrt As Database
Dim conCrt As Container
Dim docCrt As Document
Set dbCrt = DBEngine.Workspaces(0) .Databases (0)
For Each conCrt In DbCrt.Containers
Debug.Print “Container: “ & conCrt.Name
For Each docCrt In conCrt.Documents
Debug.Print “Document: “ & docCrt.Name
Next
Next
End Sub
Întâi am definit trei variabile: una de tip Database, care indică
baza de date curentă, una de tip container care indică fiecare
element din colecţia Containers şi una de tip Document, ce indică
fiecare document dintr-un container.
Apoi, pentru a itera printre elementele colecţiilor Containers, am
folosit instrucţiunea For Each, ce se aseamănă cu instrucţiunea
For…Next, cu deosebirea că este creată special pentru parcurgerea
colecţiilor
8.2 Lucrul cu variabile de tip obiect
Când declaraţi o variabilă obişnuită, practic îi cereţi lui
Access să aloce spaţiul necesar stocării unei informaţii pentru
care aţi specificat un tip de date (dacă nu specificaţi nici un tip
de date, Access va considera în mod implicit că tipul e variant).
Lucrurile sunt puţin diferite la declararea unei variabile de tip
obiect. În acest caz, Access creează numai un pointer la obiect. De
exemplu, nici una din declaraţiile de mai jos:
Dim db As Database
Dim form As Form
Dim ctl As Control
nu stochează informaţii şi, deocamdată, nu indică vreun obiect
existent. Pentru a le face să indice un obiect, trebuie să folosim
cuvântul cheie Set, ca mai jos:
Set dbCrt = DBEngine.Workspaces(0) .Databases(0)
Set form = dbForms!DetaliiProf
Set ctl = frm.Controls!Nume
Legătura dintre variabile şi obiectul spre care acestea indică este
distrusă (şi memoria necesară este eliberată) o dată cu expirarea
duratei de viaţă a variabilei. Dacă doriţi să faceţi
dumneavoastră, explicit, acest lucru, puteţi folosi valoarea
predefinită Nothing:
Set frm = Nothing
După cum aţi mai văzut şi în exemplele anterioare, pentru a
accesa un anumit obiect DAO trebuie să parcurgeţi ierarhia în sens
descrescător, până la acel obiect:
DBEngine.ColectieParinte.ColectieCopil (“ObiectCopil”)
Tabelul 8.5 prezintă cele patru metode prin care puteţi accesa un
element al unei colecţii.
Sintaxa Exemplu Explicaţii
colectie (“nume”) DBEngine.Workspaces(0).
Databases_ (“Cursuri Optionale”)
colectie (var) StrBazaDate = “Cursuri Optionale”
DBEngine.Workspaces(0).
Databases_
(strBazaDate) var e o variabilă de tip şir de caractere sau Variant
colectie (indice) DBEngine.Workspaces(0).
Databases(0)
indice reprezintă poziţia obiectului în cadrul colecţiei
colectie!nume
Sau
colectie![nume] DBEngine.Workspaces(0).
Databases!_
[Cursuri Optionale]
Parantezele drepte sunt necesare numai dacă numele colecţiei
conţine caractere speciale (de exemplu, spaţii)
Tabelul 8.5
Astfel, dacă vreţi să accesaţi un obiect al cărui nume îl
cunoaşteţi, puteţi folosi acest nume ca mai jos:
Debug.Print Current.TableDefs(“Profesor”).RecordCount
Aţi văzut că pentru a obţine baza de date curentă, trebuie să
scrieţi:
DBEngine.Workspaces(0) .Databases(0) Sau, pe scurt, DBEngine(0) (0)
Access vă mai pune însă la dispoziţie şi funcţia CurrentDB(),
pentru a obţine un pointer la baza de date curentă. Dacă doriţi să
accesaţi o bază de date din afara sistemului Access (prin OLE),
trebuie să folosiţi varianta DBEngine(0) (0). Altfel, dacă lucraţi
în Access, puteţi folosi ambele variante, cu observaţia că funcţia
CurrentDB() este mai rapidă. Atenţie, însă, la următorul aspect:
nu puteţi folosi un pointer la un obiect pe care l-aţi obţinut
apelând funcţia CurrentDB() într-o linie următoare de cod. Cu alte
cuvinte, următoarea procedură:
Sub Test1 ()
Dim doc As Document
Set doc = CurrentDb.Containers!Forms.Documents(0)
Debug.Print doc.Name
va eşua când va încerca să tipărească doc.Name deoarece, în acel
punct, doc este un pointer invalid. Următoarea procedură, în schimb,
va rula corect:
Sub Test2 ()
Dim doc As Database
Dim doc As Document
Set db = CurrentDb()
Set doc = db.Containers!Forms.Documents(0)
Debug.Print doc.Name
End Sub
Când folosim semnul exclamării (!) şi când punctul (.)
Atât operatorul (!), cât şi operatorul (.) sunt folosiţi pentru a
descrie relaţiile de apartenenţă dintre colecţii, obiecte şi
proprietăţi.
În general, după (!) urmează numele unui obiect creat de
dumenavoastră: un formular, un raport sau un control (deci un element
al unei colecţii). Astfel, operatorul (!) separă un obiect de
colecţia din care face parte. Operatorul (.) este folosit, în
general, pentru a separa un obiect de o colecţie, proprietate sau
metodă a sa.
8.3 Colecţii implicite
Aţi putut observa din exemplele de până acum că adesea, pentru a
obţine un pointer la un obiect, trebuie să scrieţi o linie de cod
destul de lungă. În Access însă, aproape orice tip de obiect are o
colecţie implicită, care va fi luată în considerare dacă nu
specificaţi nici o colecţie. De aceea,
DBEngine.Workspaces(0) .Databases(0) .TableDefs(0)
se mai poate scrie prescurtat ca: DBEngine(0) (0) (0)
Aceasta pentru că, după cum puteţi vedea şi în tabelul 8.6,
TableDefs e colecţia implicită a unui obiect de tip Database,
Databases e colecţia implicită a unui obiect de tip Workspace, iar
Workspaces e colecţia implicită a obiectului DBEngine.
Obiect Colecţia implicită
Container Documents
Database TableDefs
DBEngine Workspaces
Group Users
Index Fields
QueryDef Parameters
Recordset Fields
Relation Fields
TableDef Fields
User Groups
Workspace Databases
Tabelul 8.6
8.4 Lucrul cu proprietăţile obiectelor
Fiecare obiect DAO are o colecţie de proprietăţi. Unele obiecte au
şi proprietăţi care nu există până în momentul în care li se
dă o valoare. De aceea, este important să înţelegeţi diferenţele
dintre tipurile de proprietăţi ale obiectelor DAO.
8.4.1 Tipuri de proprietăţi
Există două tipuri de proprietăţi DAO: predefinite şi definite de
utilizator.
Proprietăţile predefinite ale unui obiect reprezintă
caracteristicile de bază ale acestuia. Ele există încă de la
crearea obiectului şi sunt disponibile pentru orice aplicaţie ce
foloseşte motorul Jet. De exemplu, pentru un obiect de tip Field
(câmp), proprietăţile Name(nume) şi Type(tip) sunt predefinite.
Proprietăţile definite de utilizator nu există până când nu sunt
adăugate la colecţia Properties a obiectului. De exemplu,
proprietatea Description (descriere) a unui câmp nu este predefinită
şi nu există până când nu introduceţi descrierea. Dacă
încercaţi să regăsiţi proprietatea Description a unui obiect ce
încă nu o are, veţi obţine o eroare.
8.4.2. Accesul la proprietăţi
Pentru a regăsi o proprietate predefinită a unui obiect, puteţi
folosi sintaxa:
obiect.proprietate
Pe de altă parte, nu puteţi regăsi o proprietate definită de
utilizator decât prin intermediul colecţiei Properties a obiectului:
Obiect.Properties(“proprietar”)
sau Obiect.Properties!proprietate
Această din urmă sintaxă funcţionează şi pentru proprietăţi
predefinite.
8.4.3. Stabilirea proprietăţilor
Cu ajutorul instrucţiunii With puteţi stabili mai multe
proprietăţi ale unui obiect, fără a mai fi necesar să specificaţi
obiectul pentru fiecare proprietate în parte:
Private Sub Set_Form_Prop()
With txtCtl
.Text = “Acesta este un control de tip text”
.ForeColor = RGB(0, 255, 0) ‘verde
.BackColor = 0
End With
End Sub
8.5. Crearea şi manipularea obiectelor cu DAO
În exemplele de până acum, nu am făcut altceva decât să folosim
DAO pentru a accesa obiecte existente şi proprietăţile acestora. O
mare parte a facilităţilor oferite de DAO constă însă în
posibilitatea de a crea şi de a modifica obiecte.
8.5.1. Crearea obiectelor
Pentru a crea un obiect nou, procedaţi astfel:
1. Folosiţi una dintre metodele Create…(CreateTable, CreateIndex
etc.) pentru a crea obiectul dorit (tabelă, index etc.).
2. Stabiliţi proprietăţile obiectului creat. Unele proprietăţi
(cum ar fi numele) sunt esenţiale şi trebuie specificate la crearea
obiectului. Altele pot fi stabilite şi ulterior.
3. Adăugaţi obiectul la colecţia corespunzătoare, pentru ca ele să
facă parte din baza de date.
Dacă obiectul nou creat conţine alte obiecte (aşa cum o tabelă
conţine câmpuri), trebuie să creaţi întâi obiectul principal şi
pe urmă cele subordonate, pe care le adăugaţi la colecţiile
corespunzătoare ale obiectului principal. Apoi, îl adăgaţi şi pe
acesta la colecţia sa.
Tabelul 8.7 prezintă în detaliu metodele Create…cu argumentele
acestora şi cu descrierile de rigoare.
Obiect Metoda Argumente Tip de date Descriere
Tabela CreateTableDef Name String Numele tabelei
Attributes Integer Stabilire valori pentru tabele ataşate, sistem
sau ascunse
Source String Informaţii despre tipul tabelei de bază a unei
tabele ataşate
Connect String Calea şi numele fişierului unei tabele ataşate
Câmp CreateField Name String Numele câmpului
Type Integer Tipul de date
Size Integer Dimensiunea (pentru câmpuri de tip text)
Index CreateIndex Name String Numele indexului
Interogare CreateQueryDef Name String Numele interogării
SQL String Şir de caractere ce conţine instrucţiunea SQL pe care
se bazează interogarea
Relaţie CreateRelation Name String Numele relaţiei
Table String Numele tabelei primare
ForeignTable String Numele tabelei ce conţine cheia străină
Attributes Integer Atributele relaţiei: tipul relaţiei,
integritatea referenţială, actualizări şi ştergeri în cascadă
Workspace Create Workspace Name String Numele sesiunii de lucru
User String Numele utilizatorului
Password String Parola pentru sesiune
Bază de date CreateDatabase DatabaseName String Numele fişierului ce
conţine baza de date
Locale String Expresie ce specifică limba pentru noua bază de date
(pentru sortări şi comparaţii între variabile de tip text)
Options Integer O constantă sau o combinaţie de constante ce arată
dacă baza de date este criptată sau versiunea motorului Jet
Grup CreateGroup Name String Numele grupului de utilizatori
PID String Identificatorul grupului
Utilizator CreateUser Name String Numele utilizatorului
PID String Identificatorul utilizatorului
Tabelul 8.7
În continuare, vom ilustra crearea unor astfel de obiecte complexe.
8.5.1.1. Crearea unei tabele
Funcţia următoare creează tabela Profesor1 şi îi adaugă doar
două coloane: IdProf şi Nume.
Function CreeazaTabProf ()
Dim db As Database
Dim tdProf As TableDef
Dim fd1 As Field
Dim fd2 As Field
Set db = CurrentDb ()
‘Crearea tabelei si a coloanelor
Set tdProf = db.CreateTableDef ()
tdProf.Name = “Profesor1”
Set fd1 = tdProf.CreateField (“IdProf”, dbLong)
Set fd2 = tdProf.CreateField (“Nume”, dbText, 60)
‘Adaugarea la colectii
With tdProf.Fields
.Append fd1
.Append fd2
End With
With db.TableDefs
.Append tdProf
‘Actualizarea colectiei TableDefs
.Refresh
End With
End Function
Este să folosiţi metoda Refresh (actualizare) pentru a vă asigura
că noile obiecte au fost adăugate (acest lucru e recomandat mai ales
în cazul unei aplicaţii multiuser).
Notă: Această funcţie nu tratează nici o eroare şi, de aceea, va
eşua dacă o veţi rula de două ori consecutiv. Pentru a o putea rula
cu succes a doua oară, ştergeţi întâi tabela creată.
8.5.1.2 Crearea unui index
Iată care sunt paşii pe care trebuie să-i urmaţi pentru a crea un
index folosind DAO:
1. Folosiţi metoda CreateIndex a unui obiect de tip TableDef pentru a
crea indexul şi stabiliţi-i proprietatea Name (nume).
2. Atribuiţi valorile dorite proprietăţilor noului index (cele mai
importante proprietăţi sunt Name, Primary, Unique şi Required).
După ce aţi adăugat indexul la colecţia sa, nu-i veţi mai putea
modifica proprietăţile. Pentru aceasta, va trebui să ştergeţi
obiectul şi să creaţi unul nou, cu proprietăţile dorite.
3. Folosiţi metoda CreateField a indexului pentru a crea câte un
obiect de tip Field pentru fiecare câmp ce face parte din index.
Adăugaţi-le apoi la colecţia Fields a indexului.
4. Folosiţi metoda Append a obiectului de tip TableDef pentru a
adăuga indexul la colecţia Indexes.
Funcţia CreareCheiePrimara() pe care o dăm mai jos ca exemplu,
creează o cheie primară pentru o tabelă. Ea primeşte ca argumente
numele tabelei, numele indexului şi coloanele ce vor compune cheia
primară. Argumentul varColoane fiind de tip Variant, poate conţine
fie o matrice, dacă vor fi mai multe coloane în componenţa cheii
primare, fie un singur nume. Pentru a testa dacă nu există deja o
cheie primară pentru tabela respectivă, funcţia CreareCheiePrimara()
apelează funcţia ExistaCP(), care returnează numele indexului
corespunzător cheii primare, dacă acesta există, sau valoarea Null,
dacă nu există. De asemenea, pentru a adăuga un obiect de tip Field
la colecţia Fields a unui index, funcţia CreareCheiePrimara()
apelează funcţia AdaugareCamp(), ce returnează valoarea True în caz
de reuşită şi False în caz de eşec. Pentru a testa funcţia
CreareCheiePrimara() am creat şi subrutina TestCP, ce listează pentru
tabela Curs_Prof cheia primară formată din coloanele IdCurs şi
IdProf.
Function CreareCheiePrimara(strTabela As String, strCP As
String,_ varColoane As Variant) As Boolean
Dim db As Database
Dim td As TableDef
Dim idxs As Indexes
Dim idx As Index
Dim fd As Field
Dim varCP As Variant
Dim varIdx As Variant
On Error GoTo CreareCheiePrimara_Err
Set db = CurrentDb()
Set td = db.TableDefs(strTabela)
Set idxs = td.Indexes
‘daca exista o cheie primara, o stergem
varCP = ExistaCP(td)
If Not IsNull (varCP) Then
Idxs.Delete varCP
End If
‘cream noul index
Set idx = td.CreateIndex (strCP)
‘facem ca indexul sa fie cheie primara. Astfel, stabilim automat
proprietatile:
‘IgnoreNulls = False; Required = True; Unique = True; idx.Primary =
True
‘cream campurile si le adaugam la colectia Fields
‘daca avem mai multe coloane:
If IsArray (varColoane) Then
For Each varIdx In varColoane
Call AdaugareCamp (idx, varIdx)
Next varIdx
Else
‘daca avem o singura coloana:
Call AdaugareCamp (idx, varColoane)
End If
‘adaugam indexul la colectia Indexes
idexs.Append idx
CreareCheiePrimara = True
CreareCheiePrimara_Exit:
Exit Function
CreareCheiePrimara_Err:
MsgBox “Crearea indexului a esuat”
CreareCheiePrimara = False
Resume CreareCheiePrimara_Exit
End Function
Private Function ExistaCP(td As TableDef) As Variant
Dim idx As Index
For Each idx In td.Indexes
If idx.Primary Then
ExistaCP = idx.Name
Exit Function
End If
Next idx
ExistaCP = Null
End Function
Private Function AdaugareCamp (idx As Index, varIdx As Variant)_
As Boolean
Dim fd As Field
On Error GoTo AdaugareCamp_Err
If Len(varIdx & “ “) > 0 Then
Set fd = idx.CreateField(varIdx)
Idx.Fields.Append fd
End If
AdaugareCamp = True
AdaugareCamp_Exit:
Exit Function
AdaugareCamp_Err:
AdaugareCamp = False
Resume AdaugareCamp_Exit
End Function
Sub TestCP()
Debug.Print CreareCheiePrimara(“Curs_Prof”, “PrimaryKey”,_
Array(“IdCurs”, “IdProf”))
End Sub
8.5.1.3 Crearea unei relaţii
Pentru a crea o relaţie folosind DAO, trebuie să efectuaţi
următorii paşi:
1. Verificaţi dacă tabela primară (tabela din partea 1 a relaţiei)
are definită o cheie primară.
2. Folosiţi metoda CreateRelation a obiectului bază de date pentru a
crea relaţia. Proprietăţile relaţiei le puteţi stabili fie la
crearea ei, fie ulterior, una câte una (Table, ForeignTable şi
Attributes sunt printre cele mai importante).
3. Creaţi câte un obiect de tip Field (câmp) pentru fiecare coloană
din cheia primară a tabelei primare. Pentru fiecare dintre acestea,
stabiliţi proprietatea ForeignName, ce reprezintă numele coloanei
corespunzătoare din tabela din partea (many) a relaţiei. Adăugaţia
apoi obiectele de tip Field la colecţia Fields a relaţiei.
4. Folosiţi metoda Append a obiectului de bază de date pentru a
adăuga relaţia la colecţia Relations.
Funcţia CreareRel, prezentă mai jos, creează o asociere left outer
join între tabelele Profesor şi Titlu şi permite actualizările în
cascadă. Dacă relaţia există deja, funcţia CreareRel o şterge şi
o creează din nou.
Function CreareRel() As Boolean
Dim db As Database
Dim rel As Relation
Dim fd As Field
On Error GoTo CreareRel_Err
Set db = CurrentDb()
‘cream obiectul relatie
Set rel = db.CreateRelation()
‘stabilim proprietatile relatiei
With rel
.Name = “RelProfTitlu”
.Table = “Titlu”
.ForeignTable = “Profesor”
‘left outer join, modificari in cascada
.Attributes = dbRelationLeft Or dbRelationDeleteCascade
End With
‘cream campurile
Set fd = rel.CreateField(“IdTitlu”)
fd.ForeignName = “IdTitlu”
rel.Fields.Append fd
‘adaugam relatia la colectia Relations
CreareRel = True
CreareRel_Exit:
Exit Function
CreareRel_Err:
Select Case Err.Number
Case 3012 ‘daca relatia exista deja
Db.Relations.Delete rel.Name
Resume
Case Else
MsgBox “Relatia nu a putut fi creata”
CreareRel = False
Resume CreareRel_Exit
End Select
End Function
8.5.1.4. Crearea proprietăţilor-utilizator
DAO vă dă posibilitatea să creaţi noi proprietăţi pentru un
obiect, pe care să le adăugaţi apoi la colecţia Properties a
obiectului respectiv. Paşii pe care trebuie să-i urmaţi sunt cei de
mai jos:
1. Folosiţi metoda CreateProperty a obiectului respectiv pentru a crea
proprietatea.
2. Definiţi caracteristicile proprietăţii.
3. Adăugaţi proprietatea la colecţia Properties a obiectului.
Subrutina de mai jos creează o nouă proprietate pentru o tabelă:
UltimaModificare. Ea păstrează data ultimei modificări a tabelei.
Sub UltimaModif(strTab As String)
Dim db As Database
Dim tb As TableDef
Dim prUltMod As Property
Set db = CurrentDb()
Set tb = db.TableDefs(strTab)
‘cream noua proprietate
Set prUltMod = td.CreateProperty(“UltimaModificare”, dbDate, Now)
‘adaugam UltimaModificare la colectia Properties
‘ignoram posibilele erori
On error Resume Next
td.Properties.Append prUltMod
‘afisam valoarea proprietatii
Debug.Print td.Properties(“UltimaModificare”).Value
End Sub
Deoarece metoda Append dă o eroare dacă proprietatea există deja,
pentru a scăpa de probleme am dezactivat detectarea erorilor.
8.5.2. Modificarea obiectelor
Puteţi modifica un obiect existent fără a-l deschide în modul
Design View, ci numai folosind proprietăţile şi metodele furnizate
de DAO. Trebuie totuşi să ţineţi cont de anumite restricţii atunci
când stabiliţi proprietăţile unui obiect DAO. Unele proprietăţi
pot fi stabilite numai la crearea obiectului şi nu mai pot fi
modificate după ce acesta a fost adăugat la colecţia
corespunzătoare (proprietatea Attributes a unui obiect de tip TableDef
e un exemplu în acest sens). Pentru a modifica o astfel de
proprietate, trebuie să creaţi un nou obiect, să copiaţi în el
toată informaţia conţinută în cel vechi, să stabiliţi
proprietatea respectivă, să adăugaţi noul obiect la colecţia sa
şi apoi să ştergeţi vechiul obiect. De asemenea, trebuie să
ţineţi cont de faptul că unele proprietăţi ale unui obiect DAO nu
există decât din momentul în care li s-a dat o valoare, astfel
încât încercarea de a regăsi o astfel de proprietate s-ar putea
solda cu o eroare.
8.6. Obiecte definite de utilizator
În Access 97 puteţi crea propriile dumneavoastră obiecte, cu
proprietăţile şi metodele lor, în cadrul modulelor pentru clase. Pe
parcursul acestui subcapitol, ne-am propus să creăm un obiect care
să poată fi accesat prin VBA şi care să ofere diferite informaţii
despre sistem.
8.6.1. Proprietăţile şi metodele obiectului
Primul lucru pe care trebuie să-l facem atunci când creăm un obiect
este să stabilim care sunt informaţiile pe care acesta le va oferi.
Cu alte cuvinte, trebuie să determinăm caracteristicile şi
comportamentul lui. Tabelul 8.8 conţine proprietăţile obiectului
Calculator, pe care îl vom crea.
Proprietate Descriere
Calculator.Nume Şir de caractere ce conţine numele calculatorului
Calculator.PornireWindows Proprietate de tip Date/Time, ce arată când
a fost pornit ultima oară sistemul de operare Windows
Calculator.DirAccess Şir de caractere ce conţine directorul în care
se află msaccess.exe
Tabelul 8.8
În plus faţă de aceste proprietăţi, obiectul Calculator trebuie
să-i ofere utilizatorului posibilitatea de a efectua diferite
acţiuni, cum ar fi, de exemplu, ştergerea unui director gol sau
redarea unui fişier de sunet wave. Pentru aceasta, vom implementa
metodele
Calculator.StergeDir şi Calculator.RedareWave
Ceea ce vom face pe parcursul acestui capitol este să definim o
clasă (clasa Calculator), cu ajutorul unui modul pentru clase (class
module). Apoi, prin VBA, vom putea crea şi folosi obiecte ale acestei
clase.
Deschideţi fereastra Database şi alegeţi comanda Class Module din
meniul Insert pentru a crea un nou modul pentru clase. Salvaţi acest
modul cu numele Calculator (numele clasei pe care dorim să o
implementăm). Observaţi că modulele pentru clase sunt foarte
asemănătoare cu modulele standard. Una dintre diferenţe este aceea
că ele pot conţine două proceduri speciale, Class_Initialize() şi
Class_Terminate(). Procedura Class_Initialize() se apelează automat la
crearea instanţelor unui obiect al clasei definite în modulul
respectiv. De aceea, în cadrul acestei proceduri se efectuează, de
obicei, iniţializări ale proprietăţilor obiectului. Procedura
Class_Terminate() este apelată ori de câte ori este distrusă o
instanţă a unui obiect bazat pe modulul respectiv.
Declaraţi întâi la secţiunea (General)(Declarations) a modulului o
variabilă globală în cadrul modulului Calculator:
Private strDirAccess As String
Creaţi subrutina Calss_Initialize(), selectând din caseta combinată
Object (aflată în partea din stânga-sus a ferestrei modulului)
secţiunea Class, iar din caseta combinată Procedure (din partea
dreapta-sus a ferestrei modulului), evenimentul Initialize
(iniţializare). În cadrul acestei subrutine vom iniţializa variabila
globală declarată anterior. Ea va păstra directorul (cu calea
completă) în care este instalată aplicaţia Access (în care se
află fişierul Msaccess.exe). Pentru a obţine o informaţie, vom
apela funcţia VBA SysCmd. Scrieţi deci, în cadrul subrutinei
Class_Initialize(), următoarea linie de cod:
StrDirAccess = SysCmd(acSysCmdAccessDir)
Funcţia SysCmd() poate fi folosită pentru a efectua diferite
acţiuni în Access. Dacă îi dăm ca parametru constanta intrinsecă
acSysCmdAccessDir, ea va returna un şir de caractere ce reprezintă
directorul în care se află Msaccess.exe. Faptul că am obţinut
această informaţie nu este suficient. Mai trebuie să ne asigurăm
că ea poate fi accesată prin intermediul proprietăţii
Calculator.DirAccess. Procedura Property Get creează o proprietate şi
stabileşte modul în care sunt regăsite valorile acestei
proprietăţi. Ea are următoarea sintaxă:
[Public | Private] [Static] Property Get NumeProprietate_
[(ListaArgumente)] As TipDate
unde:
Public – indică faptul că procedura Property Get poate fi apelată
de orice altă procedură din orice alt modul;
Private – indică faptul că procedura Property Get poate fi apelată
numai de către procedurile din modulul în care a fost declarată;
Static – indică faptul că valorile variabilelor locale ale
procedurii se păstrează între apeluri;
NumeProprietate – numele proprietăţii ale cărei valori le
regăseşte procedura;
ListaArgumente – lista argumentelor procedurii;
TipDate – tipul de date al proprietăţii.
Procedura Property Get ce regăseşte valoarea proprietăţii
DirAccess este:
Public Property Get DirAccess() As String
DirAccess = strDirAccess
End Property
Proprietatea Calculator.dirAccess este read-only, adică valoarea ei
nu poate fi modificată. Totuşi, majoritatea proprietăţilor unui
obiect (formular, raport, control etc.) îşi pot schimba valoarea. O
astfel de proprietate este şi Calculator.Nume. pentru a regăsi şi
modifica valoarea acestei proprietăţi, vom folosi două funcţii API,
GetComputerName şi, respectiv, SetComputerName, ale căror
declaraţii:
Private Declare Function GetComputerName Lib “kernel132” Alias_
“GetComputerNameA” (ByVal lpBuffer As String, nsize As Long) As
Long
Private Declare Function SetComputerName Lib “kernel132” Alias_
“SetComputerNameA” (ByVal lpComputerName As String) As Long
trebuie să le includeţi la secţiunea (General)(Declarations) a
modulului.
Funcţia SetComputerName primeşte ca argument un şir de caractere ce
reprezintă noul nume pe care doriţi să i-l daţi calculatorului
dumneavoastră. Modificarea nu devine efectivă însă decât după ce
aţi închis şi pornit din nou calculatorul. Astfel, dacă apelaţi
funcţia SetComputerName cu argumentul “NumeNou” şi apoi apelaţi
funcţia GetComputerName fără a fi iniţializat între timp
calculatorul, aceasta din urmă va returna vechiul nume al
calculatorului şi nu şirul de caractere “NumeNou”, cum ar fi de
aşteptat. De aceea, ne propunem ca proprietatea Calculator.Nume să
păstreze ultimul nume pe care l-am dat calculatorului în cadrul unei
instanţe a obiectului Calculator şi nu rezultatul returnat de
funcţia GetComputerName.
Deoarece proprietatea Nume poate fi modificată, în plus faţă de o
procedură Property Get, trebuie să scriem şi o procedură Property
Let pentru aceasta proprietate, care să ne ajute să-i modificăm
valoarea prin intermediul unei simple atribuiri, sintaxa instrucţiunii
Property Let este următoarea:
[Public | Private] [Static] Property Let NumeProprietate_
(ListaArgumente)
unde cuvintele cheie Public, Private, Static şi NumeProprietate au
aceleaşi semnificaţii ca şi pentru instrucţiunea Property Get, iar
ListaArgumente reprezintă argumentele procedurii. Numele şi tipul
fiecărui argument (cu execepţia ultimului) trebuie să corespundă
exact numelui şi tipului argumentelor procedurii Property Get a
aceleiaşi proprietăţi. Ultimul argument reprezintă noua valoare ce
va fi atribuită proprietăţii şi deci trebuie să aibă acelaşi tip
de date ca şi cel returnat de procedura Property Get. Iată care sunt
cele două proceduri pentru regăsirea şi modificarea valorilor
proprietăţii Calculator.Nume:
Public Property Get Nume () As String
Nume = strNume
End Property
Public Property Let Nume (strNumeNou As String)
Call SetComputerName (strNumeNou)
strNume = strNumeNou
Variabila strNume este globală în cadrul modulului şi trebuie deci
să fie declarată la secţiunea (General)(Declarations) a acestuia:
Private strNume As String * 255
Ea trebuie să fie iniţializată în cadrul funcţiei
Class_Initialize():
Call GetComputerName(strNume, 255)
Până acum am vorbit numai despre proprietăţile obiectului
Calculator. Metodele unui obiect sunt mult mai simplu de implementat:
ele sunt subrutine sau funcţii publice obişnuite. Iată care sunt
cele două metode ale obiectului Calculator:
Public Function StergeDir(strDir As String)
StergeDir = RemoveDirectory(strDir)
End Function
Public Sub PlayWave(strWave As String)
Call PlaySound(strWave, 0, 0)
End Sub
Pentru a putea apela funcţiile API RemoveDirectory şi PlaySound,
trebuie să includeţi la secţiunea (General)(Declarations) a
modulului declaraţiile lor:
Private Declare Function RemoveDirectory Lib “kernel132” Alias_
“RemoveDirectoryA” (ByVal lpPathName As String) As Long
Private Declare Function PlaySound Lib “winmm.dll” Alias_
“PlaySoundA” (ByVal lpszName As String, ByVal hModule As Long,
ByVal_ dwFlags As Long) As Long
8.6.2 Crearea instanţelor obiectului
Primul lucru pe care trebuie să-l subliniem este acela că există o
diferenţă între crearea unei variabile de tip obiect şi crearea
unui obiect. Prin următoarea lini de cod:
Dim comp As New Calculator
nu se creează o nouă instanţă a obiectului Calculator, ci doar se
alocă resursele necesare creării unui nou obiect de acest tip.
Obiectul în sine nu este creat până când una dintre proprietăţile
sau metodele sale nu este folosită sau apelată. Cu alte cuvinte,
dacă după declaraţia de mai sus am dori să afişăm proprietatea
DirAccess şi am scrie:
MsgBox comp.DirAccess
această instrucţiune este cea care declanşează crearea obiectului,
apelarea procedurilor:
Class_Initialize şi Prop Get DirAccess
Instrucţiunea folosită pentru alocarea resurselor poate fi
înlocuită cu:
Set comp = New Calculator
În acest caz, instrucţiunea Dim alocă spaţiul necesar creării
obiectului, iar instrucţiunea Set determină crearea obiectului şi
apelarea procedurii Class_Initialize.
Observaţi utilizarea cuvântului cheie New în ambele variante
folosite pentru crearea instanţelor. Acesta trebuie folosit pentru
orice obiect.
Pentru a testa funcţionalitatea unui obiect de tip Calculator, creţi
un nou modul standard în care scrieţi următoarea subrutină:
Sub testCalculator()
Dim comp As New Calculator
MsgBox comp.DirAccess
MsgBox comp.Nume
Comp.Nume = “CalculatorulMeu”
End Sub
8.6.3. Durata de viaţă a obiectelor
În situaţia în care avem mai multe variabile care fac referire la
acelaşi obiect, acesta nu poate fi distrus şi deci, resursele ocupate
de el nu pot fi eliberate decât după ce au fost distruse toate
variabilele ce fac referire la el. Acest lucru se întâmplă ori când
o variabilă îşi încheie durata de viaţă (scopul), ori când ea
primeşte valoarea Nothing:
Set comp = Nothing
8.7 Lucrul cu obiecte de tip Recordset
Adevărata putere a unei baze de date constă în modul în care putem
să regăsim informaţia, să manipulăm înregistrările şi seturile
de înregistrări. Ce este un set de înregsitrări? Atunci când
deschideţi o tabelă în modul Datasheet View, vedeţi un set de
înregistrări. De aceea, dacă vă decideţi să programaţi în VBA,
veţi lucra foarte mult cu obiecte de tip Recordset. Iată un prim
exemplu de subrutină ce foloseşte un astfel de obiect pentru a găsi
numărul de înregistrări dintr-o tabelă a bazei de date Cursuri
Opţionale.mdb:
Public Function NrInregistr(strTabela As string)
Dim db As Database
Dim rst As Recorset
Dim iNrInregistrari
Set db = CurrentDb()
Set rst = db.OpenRecordset(strTabela)
iNrInregistrari = rst.RecordCount
Debug.Print “Tabela “ & strTabela & “ contine “ &
iNrInregistrari &“ inregistrări”
rst.close
End Function
Deschideţi fereastra Debug şi scrieţi:
?NrInregistr(“Student”)
după care apăsaţi pe Enter. Figura 8.9 prezintă rezultatul
obţinut.
Figura 8.9
Atâta timp cât un set de înregistrări este deschis (între apelul
metodei OpenRecordset şi al metodei Close), puteţi face orice doriţi
cu înregistrările sale: le puteţi edita, şterge sau puteţi chiar
adăuga înregistrări noi. Este important să închideţi un set de
înregistrări (apelând metoda Close) pentru a elibera resursele pe
care Access i le-a alocat.
8.7.1. Tipuri de seturi de înregistrări
În VBA există nu mai puţin de cinci feluri de obiecte de tip
Recordset:
• Obiecte Recordset de tip tabelă;
• Obiecte Recordset de tip dynaset;
• Obiecte Recordset de tip snapshot;
• Obiecte Recordset de tip forward-only;
• Obiecte Recordset de tip dinamic.
În funcţie de următorii factori, decideţi pe care dintre aceste
tipuri îl veţi folosi la un moment dat:
• Dacă doriţi să şi actualizaţi înregistrările, nu numai să
le vedeţi;
• Dacă tabelele se află într-o bază de date Access sau de alt
tip;
• Câte înregsitrări conţine setul de înregistrări.
În cadrul acestui capitol ne vom ocupa numai de primele trei tipuri de
seturi de înregistrare.
După cum aţi observat şi din exemplul anterior, pentru a crea un set
de înregistrări, folosiţi expresia:
Set rst = db.OpenRecordset (Sursa[, tip[, optiuni[, blocaje]]])
Sau
Set rst = obiect.OpenRecordset ([tip[, optiuni[, blocaje]]])
Unde:
• db – este un obiect de tip Database;
• sursa – este o tabelă, o interogare sau o instrucţiune SQL ce
returnează înregistrări;
• obiect – un obiect al unei baze de date deschis anterior:
tabelă, interogare sau un alt set de înregistrări;
• tip – specifică tipul setului de înregistrări şi poate fi una
dintre următoarele constante predefinite:
• dbOpenTable – set de înregistrări de tip tabelă
• dbOpenDynaset – dynaset
• dbOpenSnapshot – snapshot
• dbOpenForwarsOnly – set de înregistrări de tip forward-only
• dbOpenDynamic – set de înregistrări de tip dinamic;
• opţiuni – combinaţie de constante ce definesc caracteristicile
noului set de înregistrări;
• blocaje – constantă ce specifică tipul de blocaj aplicat
setului de înregistrări (pentru aplicaţii multiuser).
Notă: Access97 vă permite să creaţi un obiect de tip recordset
printr-o singură linie de cod, de exemplu: Set rst
= CurrentDb.OpenRecordset(“Profesor”, dbOpenTable)
ceea ce în Access 95 nu era posibil. Metoda compusă din doi paşi
este totuşi preferabilă, dacă veţi folosi obiectul de tip Database
în cadrul procedurii şi pentru alte acţiuni.
8.7.1.1. Seturi de înregistrări de tip tabelă
Acesta este tipul implicit de set de înregistrări pe care Access îl
creează dacă nu specificaţi alt tip ca argument al metodei
OpenRecordset şi dacă sursa de înregistrări este o tabelă din baza
de date curentă. Unul dintre avantajele unui astfel de set de
înregistrări este acela că puteţi folosi indecşi pentru a accelera
căutările.
8.7.1.2. Seturi de înregistrări de tip dynaset
Un astfel de set de înregistrări poate conţine date din mai multe
tabele locale sau ataşate. Puteţi edita datele dintr-un dynaset şi
modificările vor fi efectuate şi în tabelele de bază. În cazul
unei aplicaţii multiuser, Access va actualiza datele dintr-un dynaset
deschis pentru a reflecta modificările efectuate de alţi utilizatori
asupra tabelelor de bază. Iată câteva situaţii în care ar trebui
să optaţi pentru crearea unui dynaset:
• când doriţi să puteţi modifica înregistrările;
• când obiectul de tip Recordset are dimensiuni foarte mari;
• când obiectul de tip Recordset conţine obiecte OLE.
Acesta este tipul implicit de set de înregistrări pe care Access îl
creează dacă sursa de înregistrări este o interogare, o
instrucţiune SQL SELECT sau o tabelă care nu se află într-o bază
de date Access. Iată câteva exemple de creare a unui dynaset:
Set db = CurrentDb()
Set rst = db.OpenRcordset(“IntProfCurs”, dbOpenDynaset)
unde IntProfCurs este o interogare;
Set db = CurrentDb()
Set rst = db.OpenRecordset(“SELECT * FROM Student”, dbOpenDynaset)
unde sursa de înregistrări este o instrucţiune SELECT.
8.7.1.3. Seturi de înregistrări de tip snapshot
Seturile de înregistrări de tip snashot nu permit modificarea
datelor şi nici nu reflectă modificările efectuate de alţi
utilizatori asupra tabelelor de bază. Ele reprezintă instantanee ale
datelor la un moment dat. Avantajul lor este acela că sunt mai rapide
decât cele dynaset, dar numai atunci când numărul de înregistrări
nu este mai mare de 500.
8.7.2. Actualizarea datelor unui set de înregistrări
Pentru a vă asigura că datele unui set de înregistrări sunt
actualizate, puteţi executa din nou interogarea care stă la baza
setului, apelând metoda Requery (reinterogare) a obiectului. Nu orice
obiect de tip Recordset suportă însă reinterogarea. De aceea, pentru
a afla acest lucru, trebuie ca înainte de a apela metoda Requery să
verificaţi dacă proprietatea Restartable a obiectului are valoarea
True (altfel, reinterogarea va genera o eroare):
If rst.Restartable = True Then rst.Requery
8.7.3. Parcurgerea seturilor de înregistrări
După ce aţi creat un obiect de tip Recorset, înregistrarea curentă
va fi prima înregistrare a setului. Dacă nu aţi specificat nici o
regulă de sortare a înregistrărilor, acestea se pot afla în orice
ordine.
Access vă pune la dispoziţie cinci metode pentru a parcurge
înregistrările unui set de înregistrări:
Metoda Descriere
MoveNext Înregistrarea următoare devine cea curentă
MovePrevious Înregistrarea precedentă devine cea curentă
MoveFirst Prima înregistrare devine cea curentă
MoveLast Ultima înregistrare devine cea curentă
Move n[, start] Înregistrarea curentă devine cea care se află la n
înregistrări distanţă (înainte sau înapoi) de cea curentă sau de
o anumită poziţie (start).
Parametrul n al metodei Move indică numărul de înregistrări care
trebuie să fie parcurse pentru a ajunge la cea dorită. Dacă n>0,
parcurgerea se face înainte, dacă n<0, înapoi. Parametrul opţional
start reprezintă un semn de carte, adică o anumită poziţie de la
care începe deplasarea cu n înregistrări. Dacă acest parametru nu
este specificat, se porneşte de la înregistrarea curentă. (Despre
semne de carte vom vorbi mai târziu, în cadrul acestui subcapitol.)
8.7.4. Regăsirea numărului de înregistrări ale unui set de
înregistrări
În exemplul pe care l-am dat la începutul acestui subcapitol, am
folosit proprietatea RecordCount a unui obiect de tip Recordset pentru
a-i afla numărul de înregistrări. După cum v-aţi putut da seama
ulterior, setul respectiv era de tip tabelă. Pentru acest tip, Access
cunoaşte numărul de înregistrări şi dă proprietăţii RecordCount
valoarea corespunzătoare. Lucrurile nu sunt însă la fel de simple
şi în cazul altor tipuri de seturi de înregistrări.
Pentru a mări performanţele aplicaţiei dumneavoastră, atunci când
creează un obiect Recordset de tip dynaset sau snapshot, Access trece
la executarea liniei de cod următoare celei ce apelează metoda
OpenRecordset imediat după ce a fost regăsită prima înregistrare.
De aceea, Access nu cunoaşte imediat numărul de înregistrări al
unui astfel de set. Pentru ca acest număr să fie calculat corect,
trebuie să apelaţi metoda MoveLast, pentru a vă asigura că au fost
regăsite toate înregsitrările şi apoi să folosiţi proprietatea
RecordCount:
Set rst = db.OpenRecordset(“IntProfCurs”, dbOpenDynaset)
Rst.MoveLast
Debug.Print rst.RecordCount
Notă: În cazul în care vreţi să aflaţi numai dacă setul de
înregistrări conţine măcar o înregistrare, nu trebuie să mai
apelaţi metoda MoveLast, pentru că Access nu trece la următoarea
linie până când nu a fost returnată prima înregistrare a setului.
De aceea, dacă proprietatea RecordCount are valoarea zero, e clar că
setul nu conţine înregistrări.
Dacă adăugaţi sau ştergeţi înregistrări dintr-un dynaset,
proprietatea RecordCount a obiectului respectiv se modifică în
consecinţă. În cazul unei aplicaţii multiuser, dacă aţi
utilizatori adaugă sau şterg înregistrări din tabela din care îşi
iau setul datele, aceste modificări nu sunt reflectate imediat, astfel
încât va trebui să-l reinterogaţi şi să apelaţi MoveLast
înainte de a folosi proprietatea RecordCount.
8.7.5. Poziţia absolută şi poziţia procentuală
Pentru a parcurge un set de înregistrări sau pentru a afla poziţia
înregistrării curente, puteţi folosi proprietăţile
AbsolutePosition (poziţia absolută) şi PercentPosition (poziţia
procentuală) a obiectului de tip Recordset.
Proprietatea AbsolutePosition reprezintă poziţia înregistrării
curente în cadrul setului (faţă de zero), iar dacă nu există o
înregistrare curentă, valoarea ei este –1. Ea este disponibilă
numai pentru seturi de tip dynaset sau snapshot. Spre exemplu, pentru
ca înregistrarea curentă să devină cea de-a 4-a înregistrare din
set, scrieţi:
rst.AbsolutePosition = 3
Proprietatea PercentPosition indică poziţia înregistrării curente
ca procentaj din numărul total de înregistrări ale setului şi poate
avea valori între 0.0 şi 100.00. Astfel, pentru a vă deplasa până
la jumătatea setului, puteţi scrie:
rst.PercentPosition = 50
Pentru a vă asigura că proprietatea PercentPosition returnează o
valoare corectă, trebuie să reinterogaţi setul şi apoi să apelaţi
metoda MoveLast, din aceleaşi motive prezentate anterior pentru
proprietatea RecordCount.
8.7.6. Poziţiile de început şi de sfârşit ale setului de
înregistrări (BOF şi EOF)
Orice set de înregistrări are două proprietăţi (BOF şi EOF) care
arată dacă înregistrarea curentă se află la începutul setului
(BOF) sau la sfârşitul lui (EOF).
Dacă prima înegistrare este cea curentă şi apelaţi metoda
MovePrevious, proprietatea BOF ia valoarea True şi înregistrarea
curentă nu mai există. Dacă mai apelaţi încă o dată metoda
MovePrevious, valoarea lui BOF rămâne True, dar va fi generată o
eroare.
Dacă ultima înregistrare este cea curentă şi apelaţi metoda
MoveNext, proprietatea EOF ia valoarea True şi nu mai există o
înregistrare curentă. Dacă apelaţi din nou metoda MoveNext,
valoarea lui EOF rămâne True, dar va fi generată o eroare.
8.7.7. Regăsirea valorilor câmpurilor unui set de înregistrări
Pentru a afla valorile diferitelor câmpuri ale unui set de
înregistrări, corespunzătoare înregistrării curente, puteţi
folosi una dintre următoarele trei variante de sintaxă:
Sintaxa Exemplu
rst!camp rst!Nume
rst(“camp”) rst(“Nume”)
rst(indice) rst(1)
Reţineţi faptul că, într-un set de înregistrări, primul câmp
are întotdeauna indicele 0, indiferent de opţiunea Option Base pe
care aţi specificat-o. Astfel, rst(1) se referă la cea de-a doua
coloană a setului rst.
Să presupunem că dorim să afişăm numele şi catedra tuturor
profesorilor din tabela Profesor. Pentru aceasta, putem scrie
următoarea procedură:
Public Sub Nume_Student()
Dim db As Database
Dim rst As Recordset
Set db = CurrentDb()
Set rst = db.OpenRecordset(“Profesor”)
With rst
‘verificam daca rst contine inregistrari
If .RecordCount Then
.MoveLast
‘parcurgem setul de la ultima catre prima inregistrare
Do Until .BOF
Debug.Print ![Nume], ![Catedra]
.MovePrevious
Loop
End If
.Close
End With
End Sub
Dacă veţi rula această subrutină, rezultatele din fereastra Debug
vor fi asemănătoare cu cele din figura 8.10:
Fig 8.10
De multe ori, veţi dori să aveţi un acces mai rapid la un set de
date pe care nu doriţi să le modificaţi, ci numai să le
vizualizaţi. Pentru aceasta, puteţi crea un set de tip snapshot cu
opţiunea dbForwardOnly, care este foarte rapid, dar nu permite decât
parcurgerea înainte a setului. O modalitate de a vă bucura de
rapiditatea unui astfel de set de înregistrări şi de a putea, în
acelaşi timp, să accesaţi în orice ordine datele pe care acesta le
conţine, este să copiaţi datele într-o matrice. Dumneavoastră nu
trebuie decât să declaraţi o variabilă de tip Variant şi să
apelaţi metoda GetRows() a setului. Access va crea o matrice
bidimensională, pe care o va dimensiona corespunzător. Putem deci
rescrie procedura Nume_Student astfel încât să folosim un snapshot
şi o matrice:
Public Sub Nume_Student_1()
Dim db As Database
Dim rst As Recordset
Dim varDate As Variant
Dim iNrInreg As Integer
Dim i As Integer
Set db = CurrentDb()
Set rst = db.OpenRecordset(“Student”, dbOpenSnashot, dbForwardOnly)
‘alegem un numar suficient de mare de inregistrari
varDate = rst.GetRows(1000)
‘aflam indicele ultimei linii a matricei
iNrInreg = Ubound(varDate, 2)
‘tiparim datela coloanei 1-a (Nr_matr) si a 2-a (Nume)
For i = iNrInreg To 0 Step –1
Debug.Print varDate(1, i), varDate(2, i)
Next i
rst.Close
End Sub
Rezultatele vor fi tot cele din figura 8.10, dar, pentru un set cu
multe înregistrări, procedura se va executa mult mai repede.
8.7.8. Căutarea înregistrărilor
Atunci când doriţi să regăsiţi numai o anumită înregistrare
(sau un set de înregistrări ce satisfac un anumit criteriu), veţi
folosi una dintre metodele Seek sau Find ale setului respectiv. Despre
acestea vom vorbi în cadrul secţiunilor următoare.
8.7.8.1. Căutări în seturi de înregistrări de tip tabelă
După ce aţi creat un obiect Recordset de tip tabelă, cea mai
rapidă modalitate de a regăsi anumite înregistrări este apelarea
metodei Seek. (Apelarea acestei metode pentru un set de înregistrări
care nu este de tip tabelă va genera o eroare). Pentru aceasta,
trebuie să efectuaţi doi paşi:
1. Stabiliţi valoarea proprietăţii Index a setului, deoarece
căutările cu metoda Seek se fac numai pe indecşi.
2. Apelaţi metoda Seek dându-i ca argumente un operator de
comparaţie (<,<=,>= sau >) şi una sau mai multe valori care să
reprezinte criteriile de căutare (în funcţie de numărul coloanelor
ce intră în componenţa idexului). Valorile trebuie să corespundă
tipurilor de date ale coloanelor indexului.
După ce aţi folosit metoda Seek pentru a căuta o înregistrare,
trebuie să verificaţi dacă aţi găsit ceva. Pentru aceasta, veţi
verifica valoarea proprietăţii NoMatch a setului de instrucţiuni.
Mai reţineţi faptul că metoda Seek returnează numai prima
înregistrare care satisface criteriul specificat, chiar dacă aceasta
nu e singura.
Să presupunem că dorim să aflăm nota obţinută de un student la o
anumită materie. Pentru aceasta, vom crea un set de înregistrări
bazat pe tabela Curs_Student şi vom apela metoda Seek pentru el. În
acest scop, vom folosi drept index cheia primară a tabelei, care e
formată din coloanele NrMatricol şi IdCurs.
Public Sub SeekStud_Curs(iNrMat As Integer, iIdCurs As Integer)
Dim db As Database
Dim rst As Recordset
Set db = CurrentDb()
Set rst = db.OpenRecordset(“Curs_Student”)
‘stabilim proprietatea Index a setului
rst.Index = “PrimaryKey”
‘cautam inregistrarea pentru. care IdCurs=iIdCurs si
NrMatricol=iNrMat
Rst.Seek “=”, iIdCurs, iNrMat
If rst.NoMatch = True Then
‘nu a fost gasita o astfel de inregistrare
Debug.Print “Studentul cu nr. matricol “ & iNrMat & vbCrLf &
_
“nu s-a inscris la cursul “ & iIdCurs
Else
Debug.Print “Nota “ & rst!Nota
End If
rst.Close
End Sub
8.7.8.2. Căutări în seturi de înregistrări de tip dynaset şi
snapshot
Spre deosebire de seturile de tip tabelă, cele dynaset şi snapshot
nu pot folosi metoda Seek pentru căutări. Atât pentru acestea din
urmă, cât şi pentru căutări după coloane neindexate, Access vă
pune la dispoziţie patru metode de căutare a datelor:
Metoda Descriere
FindFirst Începând cu prima înregistrare a setului de
înregistrări, caută o înregistrare ce verifică un criteriu dat.
Dacă există, înregistrarea găsită devine cea curentă.
FindLast Începând cu ultima înregistrare a setului de
înregistrări, caută o înregistrare ce verifică un criteriu dat.
Dacă există, înregistrarea găsită devine cea curentă.
FindNext Începând cu înregistrarea curentă, caută următoarea
înregistrare ce verifică un criteriu dat. Dacă există,
înregistrarea găsită devine cea curentă.
FindPrevious Începând cu înregistrarea curentă, caută precedenta
înregistrare ce verifică un criteriu dat. Dacă există,
înregistrarea găsită devine cea curentă.
Dacă oricare dintre aceste metode nu reuşeşte să găsească o
înregistrare care să verifice criteriul respectiv, setul de
înregistrări nu va mai avea o înregistrare curentă şi orice
operaţie ulterioară asupra înregistrării curente va genera o
eroare.
Sintaxa acestor metode va fi următoarea:
rst. {FindFirst|FindPrevious|FindNext|FindLast} criteriu
unde rst este un obiect de tip dynaset sau snapshot, iar criteriu este
un şir de caractere ce conţine o expresie de genul celor din clauza
WHERE a unei instrucţiuni SQL:
rst..FindFirst “NrMatricol = “ & nMatr & “ AND Nota >=5”
Subrutina FindCursuriPromovate() caută toate cursurile la care un
student a obţinut o notă mai mare sau egală cu 5. Dacă nu există
nici o înregistrare care să întrunească acest crietriu, vom afişa
un mesaj. Cu ajutorul variabilei nRez ţinem minte dacă au fost
găsite 0, una sau mai multe înregistrări, pentru a afişa un mesaj
potrivit pentru fiecare situaţie.
Public Sub FindCursuriPromovate(nMatr As Integer)
Dim db As Database
Dim rst As Recordset
Dim nPromovate As Integer
Dim strRez As String
Set db = CurrentDb()
Set rst = db.OpenRecordset(“Curs_Student”, dbOpenSnapshot)
rst.FindFirst “NrMatricol = “ & nMatr & “AND Nota >=5”
Do While rst.NoMatch = False
nPromovate = nPromovate + 1
strRez = strRez & vbCrLf & rst!IdCurs
rst.FindNext “NrMatricol = ” & nMatr & “AND Nota >=5”
Loop
Select Case nPromovate
Case 0
Debug.Print “Studentul cu nr. matricol “ & nMatr & vbCrLf & _
“nu a promovat nici un curs“
Case 1
Debug.Print “Studentul cu nr. matricol “ & nMatr & vbCrLf & _
“a promovat cursul: “ & rst!IdCurs
Case Else
Debug.Print “Studentul cu nr. matricol “ & nMatr & vbCrLf &
_
“a promovat cursurile “ & strRez
End Select
rst.Close
End Sub
8.7.8.3. Criterii ce conţin şiruri de caractere şi date
Atunci când doriţi să creaţi criterii pentru una dintre metodele
Find sau atunci când creaţi în VBA şiruri de caractere ce conţin
instrucţiuni SQL, va trebui de multe ori să introduceţi într-un
asemenea şir valoarea unei variabile. Access cere ca această
variabilă să fie inclusă în şir între separatori ((“) pentru
şiruri de caractere şi (#) pentru date).
De exemplu, să presupunem că avem o variabilă, strNume, de tip
String, care conţine un nume pe care să-l căutăm într-un set de
înregistrări cu ajutorul metodei FindFirst şi, la un moment dat,
valoare ei este “Popescu”. Şirul de caractere care constituie
crietriul de căutare este:
[Nume] = “Popescu”
Pentru a introduce caracterul (“) într-un şir de caractere,
trebuie să îl dublăm. Ţinând cont de aceasta, şirul de caractere
care ne dă crietriul de mai sus este:
“[Nume] = ““Popescu”””
Separând şirul “Popescu”, care este aici doar un caz particular,
vom scrie:
“[Nume] = “”“ & “Popescu” & “”””
Înlocuind acum valoarea “Popescu” cu variabila strNume, obţinem
şirul de caractere care ne dă criteriul dorit:
“[Nume] = “”“ & strNume & “”””
Acelaşi lucru este valabil şi pentru date. Astfel, pentru a
specifica următorul criteriu:
[Data Angajarii] = varData
unde varData este o variabilă de tip Date, vom construi următorul
şir de caractere:
“[Data Angajarii = #” & varData & “#”
Data pe care o conţine variabila varData trebuie să fie în formatul
mm/dd/yy, altfel, nu veţi obţine rezultatul dori. Vă reamintim că
pentru a converti o dată la formatul mm/dd/yy, puteţi folosi funcţia
Format:
Format (varData, “mm/dd/yy”)
Pentru criterii ce conţin valori numerice, totul este mult mai
simplu, astfel că pentru a avea următorul criteriu:
[IdCurs] = nCurs
vom scrie şirul de caractere:
“[IdCurs] = “ & nCurs
8.7.9 Semne de carte
În plus faţă de metodele pentru parcurgerea unui set de
înregistrări, Access vă mai pune la dispoziţie şi proprietatea
Bookmark (semn de carte) a unui astfel de obiect. După cum aţi
văzut, fiecare set are o singură înregistrare curentă. Un Bookmark
este o proprietate a cărei valoare identifică unic înregistrarea
curentă a setului la un moment dat. Puteţi atribui această valoare
unei variabile de tip String sau Variant pentru a o folosi ulterior la
regăsirea înregistrării respective. Mai exact:
1. Regăsiţi valoarea proprietăţii Bookmark a înregistrării
curente şi o stocaţi într-o variabilă de tip String sau Variant.
2. Pentru a vă întoarce ulterior la acea înregistrare, daţi
proprietăţii Bookmark valoarea stocată anterior.
Astfel, puteţi păstra oricâte semne de carte doriţi pentru un
anumit set de înregistrări. Lucrul cu semne de carte este metoda cea
mai simplă de deplasare între înregistrările unui set.
În mare, iată cum veţi folosi în codul dumneavoastră proprietatea
Bookmark a unui set de înregistrări:
Dim strBM As String
strBM = rst.Bookmark
‘ne deplasam la ultima inregistrare
rst.MoveLast
‘…efectuam diferite operatii si apoi revenim de unde am plecat
rst.Bookmark = strBM
De multe ori veţi dori, poate, să comparaţi două semne de carte
pentru a vedea dacă înregistrarea curentă este aceeaşi cu cea
pentru care aţi salvat un semn de carte. Pentru aceasta, trebuie să
ştiţi că, deşi puteţi stoca un semn de carte într-o variantă de
tip String sau Variant, ea este reprezentată intern ca o matrice de
biţi. De aceea, atunci când comparăm două semne de carte,
comparaţia trebuie să fie făcută pe biţi. Pentru aceasta, puteţi
folosi funcţia predefinită StrComp, care returnează valoarea 0 dacă
cele două variabile comparate sunt egale şi care primeşte un al
treilea argument (primele două sunt variabile de comparat), ce
specifică modul în care se va face comparaţia: 0 pentru compraţie
pe biţi, 1 pentru comparaţia obişnuită (care nu e case-senzitivă,
adică nu ţine cont de majuscule/minuscule), 2 pentru a folosi tipul
de comparaţie specificat de opţiunea Option Compare de la secţiunea
(General)(Declarations) a modulului. De exemplu, dacă strBM1 şi
strBM2 sunt două semne stocate anterior,
NRez = StrComp(strBM1, strBM2, 0)
NRez va avea valoarea 0 dacă cele două semne de carte coincidşi o
valoare diferite de zero, altfel.
Seturile de înregistrări bazate pe tabele native Access acceptă
proprietatea Bookmark, spre deosebire de cele bazate pe tabele din alte
baze de date (Paradox, de exemplu). De aceea, înainte de a folosi
semne de carte pentru un obiect de tip Recordset, este bine să
testaţi dacă el acceptă această proprietate. În acest scop,
verificaţi dacă proprietatea Bookmarkable a setului are valoarea
True.
8.7.10 Metoda Clone (clonare)
Orice set de înregistrări are o singură înregistrare curentă.
Dacă doriţi să lucraţi cu două înregistrări curente pe acelaşi
set de date, puteţi folosi metoda clone pentru a crea o clonă a
setului. Astfel, vom avea două obiecte de tip Recordset indicând spre
acelaşi set de înregistrări. Această metodă este mult mai rapidă
decât dacă am crea un al doilea set bazat pe aceleaşi date. Atunci
când lucraţi cu clone, ţineţi cont de următoarele două probleme:
1. Un set de înregistrări creat cu metoda Clone nu are de la început
o înregistrare curentă. Pentru că o înregistrare a sa să devină
curentă, apelaţi una dintre metodele Find sau Move sau daţi
proprietăţii Bookmark o valoare regăsită din setul original.
2. Folosirea ulterioară a metodei Clonei pentru setul original sau
pentru cel clonat nu îl afectează pe cel clonat sau, respectiv, pe
cel original.
8.7.11 Proprietatea RecordsetClone
Dacă metoda Clone este folosită mai ales pentru a lucra cu două
înregistrări curente ale aceluiaşi set de date, vom folosi
proprietatea RecordsetClone pentru a avea acces la setul de
înregistrări al unui formular. Acest lucru este util atunci când
dorim să manipulăm setul de date pe care se bazează un formular,
fără ca acţiunile noastre să fie vizibile pe formular.
Pentru a ilustra cum se lucrează cu metoda Clone şi cu proprietatea
RecordsetClone, vom scrie funcţia ComparaInreg() ce verifică dacă
două înregistrări succesive ale unui set de înregistrări au
aceeaşi valoare pentru un anumit câmp. Funcţia primeşte ca
argumente variabila frm de tip Form (ce va identifica formularul) şi
variabila strCamp de tip String (ce conţine numele câmpului
respectiv) şi returnează valoarea True dacă înregistrarea curentă
şi cea anterioară conţin aceeaşi valoare a câmpului identificat de
argumentul strColoana şi False, altfel.
Function ComparaInreg(frm As Form, strCamp as string) As Boolean
Dim rst As Recordset
Dim rstClona As Recordset
‘obtinem un pointer la setul de inregistrari al formularului
Set rst = frm.RecordsetClone
‘sincronizam setul astfel obtinut cu originalul
rst.Bookmark = frm.Bookmark
‘pentru a putea lucra cu doua inregistrari curente,
‘clonam setul obtinut anterior si le sincronizam
Set rstClona = rst.Clone
rstClona.Bookmark = rst.Bookmark
‘daca inregistrarea curenta este prima, returnam valoarea False
rstClona.MovePrevious
If rstClona.BOF Then
ComparaInreg = False
Else
‘daca inregistrarea curenta nu este prima,
‘efectuam comparatia cu cea precedenta ei
‘si returnam rezultatul
ComparaInreg = (rst(strCamp) = rstClona(strCamp))
End If
rstClona.Close
End Function
Înregistrarea curentă a setului de înregistrări clonat (rstClona)
va fi întotdeauna cea precedentă înregistrării curente a setului
rst. Iată deci, cum putem lucra cu două înregistrări curente pentru
a compara valorile câmpurilor unui set, fără a avea nevoie de
variabile în care să păstrăm valorile regăsite. Această funcţie
poate fi, de exemplu, apelată din cadrul procedurii de tratare a
evenimentului Current a unui formular, pentru a afişa un anumit mesaj
sau pentru a efectua diferite alte acţiuni în funcţie de valoarea
returnată.
8.7.12 Sortarea şi filtrarea unui set de înregistrări
Pentru a sorta un set de înregistrări de tip tabelă, nu trebuie
decât să-i stabiliţi proprietatea Index. Vă reamintim că atunci
când creaţi un index pe o tabelă, puteţi specifica ordinea de
sortare crescătoare sau descrescătoare pentru indexul respectiv.
Setul va fi sortat exact după ordinea specificată de index.
Pentru a crea un set de înregistrări sortat de tip dynaset sau
snapshot, puteţi proceda în două moduri:
1. Să creaţi setul pe baza unei instrucţiuni SQL ce conţine clauza
ORDER BY:
Set rst = db.OpenRecordset(“SELECT * FROM Profesor
ORDER BY Nume;”)
2. Să stabiliţi proprietatea Sort pentru dynaset sau snapshot şi
apoi să creaţi un nou set pe baza celui sortat.
Valoarea proprietăţii Sort este un şir de caractere conţinând
coloana după care se va face sortarea şi, opţional, ordinea de
sortare (ordinea ascendentă este implicită):
rst.Sort = “[Nume]”
rst.Sort = “[Nume] Asc” ‘ascendent
rst.Sort = “[Nume] Desc” ‘descendent
Iată un exemplu în care creăm un set de înregistrări (rst), îl
sortăm şi apoi creăm unul nou (rstSortat) pe baza lui:
Dim db As Database
Dim rst As Recordset
Dim rstSortat As Recordset
Set db = CurrentDb()
Set rst = db.OpenRecordset(“Profesor”, dbOpenDynaset)
rst.Sort = “[Nume]”
Set rstSortat = rst.OpenRecordset()
‘…efectuam diferite operatii cu rstSortat
rst.Close
rstSortat.Close
Pentru a filtra un set de înregistrări,aveţi de asemenea la
dispoziţie două posibilităţi:
• Să creaţi setul pe baza unei instrucţiuni SQL ce conţine clauza
WHERE. Această metodă poate fi folosită numai pentru a crea seturi
pe baza unui obiect din baza de date.
• Să stabiliţi proprietatea Filter a unui dynaset sau snapshot
pentru a-i restrânge numărul de înregistrări şi apoi să creaţi
un nou set pe baza acestuia.
Valoarea proprietăţii Filter trebuie să fie un şir de caractere
asemănător unei expresii din clauza WHERE a unei instrucţiuni
SELECT.
Iată un exemplu ce creează câte un set de înregistrări folosind
cele două metode mai sus amintite:
Dim db As Database
Dim rst As Recordset
Dim rstSQL As Recordset
Dim rstFiltrat As Recordset
Set db = CurrentDb()
‘folosim prima metoda
Set rstSQL = db.OpenRecordset(“SELECT FROM Profesor WHERE
[Catedra]_ = “”Matematici””;”)
‘folosim a doua metoda
Set rst = db.OpenRecordset(“Profesor”, dbOpenDynaset)
rst.Filter = “[Catedra] = “”Matematici”””
Set rstFiltrat = rst.OpenRecordset()
…
Atunci când folosiţi proprietatea Sort sau Filter a unui set de
înregistrări, ţineţi cont de următoarele:
• Ele nu se aplică seturilor de tip tabelă;
• Sortarea sau filtrarea sunt vizibile numai pentru setul creat pe
baza celui sortat sau filtrat;
• Crearea seturilor pe baza instrucţiunilor SQL poate fi mai rapidă
decât folosirea proprietăţilor Sort şi Filter.
8.7.13 Editarea înregistrărilor unui set de înregistrări
Pentru a putea modifica datele unui set de înregistrări trebuie, mai
întâi, să aveţi dreptul să faceţi asta. Seturile de tip tabelă
sau dynaset pot fi modificate numai dacă altcineva nu a blocat tabela
respectivă (în cazul aplicaţiilor multiuser). Seturile snapshot şi
seturile bazate pe interogări de tip Crosstab sau Union nu permit
modificarea datelor. Pentru a vă asigua că puteţi modifica datele
unui set de înregistrări, verificaţi dacă proprietatea sa Updatable
are valoarea True.
Access vă pune la dispoziţie cinci metode pentru editarea datelor
dintr-un set de înregistrări:
Metoda Descriere
Edit Copiază înregistrarea curentă dintr-un buffer pentru a permite
editarea.
AddNew Creează o nouă înregistrare dintr-un buffer.
Update Salvează modificările din buffer.
CancelUpdate Goleşte bufferul fără a salva modificările.
Delete Şterge înregistrarea curentă.
Pentru a vedea dacă în buffer există vreo înregistrare care nu a
fost salvată, puteţi verifica valoarea proprietăţii EditMode, care
poate fi:
Valoarea Constanta intrinsecă Descriere
0 dbEditNone Bufferul e gol
1 dbEditInProgress Bufferul conţine înregistrarea curentă (s-a
apelat metoda Edit)
2 dbEditAdd Bufferul conţine o înregistrare nouă (s-a apelat metoda
AddNew)
8.7.13.1. Modificarea înregistrării curente
Pentru a edita înregistrarea curentă a unui set de înregistrări
(presupunând că puteţi face acest lucru), trebuie să efectuaţi
următoarele operaţii:
1. Apelaţi metoda Edit pentru a copia înregistrarea curentă în
buffer.
2. Efectuaţi modificările dorite.
3. Apelaţi metoda Update pentru a salva modificările.
Să presupunem că în tabela Profesor s-a introdus greşit numele unui
profesor: în loc de “Popescu Marian” s-a introdus “Popescu
Marin”. Pentru a rectifica din program această eroare, creaţi setul
rst bazat pe tabela Profesor şi scrieţi:
With rst
‘cautam inregistrarea pe care dorim s-o editam
.FindFirst “[Nume] = “”Popescu Marin”””
‘daca nu o gasim, afisam un mesaj
If .NoMatch Then
MsgBox “Popescu Marin nu se afla in tabela Profesor”
‘altfel, o editam
Else.Edit
![Nume] = “Popescu Marian”
.Update
End If
End With
8.7.13.2 Adăugarea unei noi înregistrări la un set de înregistrări
Pentru a adăuga o nouă înregistrare la un set (presupunând că
puteţi face acest lucru), procedaţi astfel:
1. Apelaţi metoda AddNew pentru a adăuga o nouă înregistrare
(valorile câmpurilor vor fi cele implicite, dacă există valori
implicite).
2. Introduceţi valorile câmpurilor.
3. Apelaţi metoda Update pentru a salva înregistrarea.
Înregistrarea curentă, după ce aţi adăugat o nouă înregistrare,
va fi tot cea dinainte acestei operaţii. De aceea, pentru ca
înregistrarea să fie curentă să fie cea nouă, apelaţi metoda Move
cu valoarea proprietăţii LastModified a setului ca argument.
Următorul exemplu adaugă o nouă înregistrare la un set bazat pe
tabela Profesor şi face ca înregistrarea curentă să fie cea nouă.
With .rst
.AddNew
![Nume] = “Toma Dorel”
![Catedra] = “Fizica”
![IdTitlu] = 2
.Update
.Move 0, .LastModified
End With
8.7.13.3 Ştergerea unei înregistrări a unui set de înregistrări
Pentru a şterge înregistrarea curentă a unui set nu trebuie decât
să apelaţi metoda Delete. După ce aţi şters o înregistrare, ea
continuă să fie cea curentă. MovePrevious pentru ca înregistrarea
precedentă să fie cea curentă.
Pentru a şterge înregistrarea corespunzătoare profesorului cu
numele “Popescu Marin” dintr-un set bazat pe tabela Profesor,
scrieţi:
With .rst
.FindFirst “[Nume] = “”Popescu Marin”””
If .NoMatch Then
MsgBox “Popescu Marin nu se afla in tabela Profesor”
Else
.Delete
.MovePrevious
End If
End With
8.8. Obiecte speciale
Există anumite proprietăţi ale unor obiecte care reprezintă, la
rândul lor, alte obiecte. Aţi făcut deja cunoştinţă cu
proprietăţile Me şi RecordsetClone. Tabelul 8.16 vă prezintă alte
proprietăţi ce reprezintă obiecte.
Proprietatea A cui este Ce reprezintă
ActiveControl Ecran (Screen) Controlul care are focusul.
ActiveForm Ecran (Screen) Formularul care are focusul sau care conţine
controlul cu focus.
ActiveReport Ecran (Screen) Raportul care are focusul sau care conţine
controlul cu focus.
Form Subformular, formular sau control Pentru un control de tip
Subform, reprezintă subformularul găzduit. Pentru un formular,
reprezintă formularul însuşi.
Me Formular sau raport Însuşi formularul sau raportul respectiv.
Module Formular sau raport Modulul asociat formularului sau raportului
respectiv.
Parent Control Formularul sau raportul ce conţine controlul respectiv.
PreviousControl Formular Controlul care a avut anterior focusul.
RecordsetClone Subraport, raport sau control Setul de înregistrări pe
care se bazează formularul.
Report Pentru un control de tip Subreport, reprezintă subraportul
găzduit. Pentru un raport, reprezintă raportul însuşi.
Section Control Secţiunea formularului sau raportului în care se
află controlul.
Tabelul 8.16
CAP:9. Crearea şi lucrul cu rapoartele
Rapoartele reprezintă o metodă prin care datele pot fi prezentate
într-un mod intuitiv şi plăcut. Ele pot fi tipărite, vizualizate
sau exportate într-un alt format. Deşi între formulare şi rapoarte
există multe asemănări, una dintre deosebiri este aceea că
rapoartele nu pot fi folosite pentru introducerea datelor. Raportele
pot să conţină aproape toate elementele unui formular, cu excepţia
controalelor care presupun acţiuni ale utilizatorului, cum ar fi cele
de tip Comba box. Puteţi să convertiţi formularele în rapoarte şi
vice-versa făcând clic dreapta pe numele formularului sau al
raportului în fereastra Database şi alegând opţiunea Save As Report
(sau Save As Form) din meniul derulant.
Datele unui raport pot proveni dintr-o tabelă, o interogare sau o
instrucţiune SQL.
9.1 Crearea unui raport
Pentru a crea un nou raport, Access vă pune la dispoziţie două
programe wizard, Auto Report şi Report Wizard. Acestea sunt utile mai
ales atunci când sursa de date a raportului este simplă sau pentru a
crea un raport de pornire pe care să îl perfecţionaţi ulterior,
manual.
9.1.1. Crearea rapoartelor cu ajutorul programelor Wizard
Pentru a crea un formular în mai puţin de un minut, nu trebuie
decât să apăsaţi butonul New din pagina Reports a ferestrei
Database şi să alegeţi din cutia de dialog New Report una dintre
opţiunile AutoReport (Columnar, pentru ca datele să fie prezentate pe
o singură coloană sau Tabular, pentru prezentarea datelor sub formă
de tabel). În plus, mai trebuie să selectaţi numele unei tabele sau
interogări din caseta combinată a acestei cutii de dialog. După ce
aţi apăsat butonul OK, raportul creat va fi afişat pe ecran în
modul Print Preview.
Pentru a crea însă un raport mai elaborat, vom folosi Report Wizard.
Să presupunem că dorim să creăm un raport care să prezinte, pentru
fiecare student, cursurile opţionale la care s-a înscris. Vom crea
raportul pe baza interogării Student_Cursuri, din figura 9.1:
Fig. 9.1
De data aceasta, alegeţi din cutia de dialog New Report opţiunea
Report Wizard. În prima cutie de dialog, alegeţi din caseta
combinată Tables/Queries interogarea Student_Cursuri şi apăsaţi
butonul (>>) pentru a selecta toate câmpurile acestei interogări,
prezentate în lista Available Fields.
Fig. 9.2
Cea de-a doua cutie de dialog din wizard vă întreabă în funcţie de
care date să se facă gruparea: de cele din tabela Curs, de cele din
tabela Curs_Student sau de cele din tabela Student. Deoarece dorim să
vedem cursurile la care s-a înscris fiecare student şi nu studenţii
care s-au înscris la fiecare curs, vom alege ca gruparea să se facă
în funcţie de tabele Student.
Fig. 9.3
Următoarea cutie de dialog vă permite să stabiliţi şi alte
niveluri de grupare a datelor. După cum puteţi vedea, deja există
două niveluri: primul conţine informaţii despre un student:
NrMatricol, NumeSt, PrenumeSt, Grupa, iar al doilea, despre cursurile
la care acesta s-a înscris: Denumire şi Nota. Să zicem că am dori
ca, la rândul lor studenţii să fie grupaţi în funcţie de grupa
în care se află. Pentru aceasta, selectaţi coloana Grupa din lista
din stânga cutiei de dialog şi apăsaţi butonul (>).
Fig. 9.4
Nu este prea târziu încă să vă răzgândiţi asupra ordinii în
care vor fi grupate datele. Pentru aceasta puteţi folosi butoanele
Priority (↑ şi ↓). Pentru acest exemplu păstraţi totuşi ordinea
din figura 9.5 şi apăsaţi butonul Next.
Fig. 9.5
Dacă la pasul anterior am stabilit după care coloane se va face
gruparea datelor, în această cutie de dialog putem stabili ordinea
în care vor fi afişate datele de pe ultimul nivel: Denumire şi Nota.
Să zicem că preferăm să afişăm cursurile în ordinea alfabetică
a denumirii lor. Pentru aceasta, va trebuie să alegeţi în prima
casetă combinată coloana Denumire. Dacă doriţi să schimbaţi
ordinea de sortare, apăsaţi pe butonul din dreapta casetei combinate.
Tot în această cutie de dialog există şi butonul Summary Options,
care deschide o altă cutie de dialog. Aici puteţi alege ca pentru o
coloană de pe ultimul nivel să se afişeze şi suma, media, minimul
sau maximul.
Fig. 9.6
Următoarele două cutii de dialog vă prezintă câteva variante de
aliniere a datelor şi, respectiv, câteva stiluri de fonturi folosite
pentru afişarea lor (pentru acest exemplu vom alege alinierea în
trepte (Stepped) şi stilul Compact). În ultima cutie de dialog din
wizard introduceţi numele raportului (Student_Cursuri) şi apăsaţi
butonul Finish. Raportul se va deschide în modul Print Preview şi va
arăta în genul celui din figura 9.7.
Fig. 9.7
9.1.2. Crearea manuală a rapoartelor
Dacă vă decideţi să creaţi manual un raport, pornind de la zero,
alegeţi în cutia de dialog New Report opţiunea Design View. Se va
deschide în modul Design View un raport fără nici un control pe el.
Dacă aţi învăţat cum să proiectaţi un formular, crearea manuală
a unui raport o să vi se pară foarte uşoară. Vom avea de-a face cu
aceleaşi categorii de secţiuni, aceleaşi tipuri de controale şi
aceleaşi ferestre suport: ToolBox (cutia cu instrumente), Field List
(lista câmpurilor) şi Properties (pagina de proprietăţi). Singurul
element nou îl constituie fereastra Sorting and Grouping (sortare şi
grupare) care vă va ajuta să stabiliţi nivelurile de grupare şi
ordinea în care vor fi afişate datele. Figura 9.8 prezintă
formularul Student_Cursuri în modul Design View.
Fig. 9.8
9.2. Sursa de date a raportului
Atunci când creaţi un nou raport în Access, aveţi posibilitatea de
a alege sursa de date a acestuia din caseta combinată a cutiei de
dialog New Report. Această sursă de date poate fi tabelă sau
interogare salvată. Pentru raportul pe care l-am creat anaterior,
sursa de date este interogarea Student_Cursuri. Ca şi în cazul
formularelor, sursa de date este specificată de proprietatea Record
Source, după cum puteţi vedea şi din pagina de proprietăţi a
raportului Student_Cursuri (figura 9.9).
Fig. 9.9
Puteţi schimba ulterior sursa de date a unui raport, modificând
valoarea acestei proprietăţi.
Pentru ca informaţiile stocate într-un câmp al sursei de date să
poată fi afişate în raport, trebuie ca grila în QBE proprietatea
Show a câmpului respectiv şă fie activată. Dacă interogarea pe
care se bazează raportul are parametri, pentru a putea vizualiza sau
tipări raportul, utilizatorul trebuie să furnizeze valorile
parametrilor respectivi.
9.3. Secţiunile unui raport
În figura 9.10 puteţi vedea secţiunile raportului Student_Curs şi,
după cum
v-aţi dat seama, ele nu sunt cu mult diferite de secţiunile unui
formular.
Fig. 9.10
• Report Header – Apare numai pe prima pagină, ca un titlu pentru
întregul raport. Dacă doriţi să creaţi o pagina separată numai
pentru titlul raportului, alegeţi ca valoare a proprietăţii
ForceNewPage a acestei secţiuni opţiunea After Section (după
secţiune).
• Page Header – Apare în partea de sus a fiecărei pagini, cu
excepţia primeia, unde apare după antetul raportului. Cel mai adesea,
conţine titlurile câmpurilor afişate.
• Detail – Se repetă pantru fiecare înregistrare la vizualizarea
sau la tipărirea raportului. S-ar putea ca la proiectarea raportului
să nu ştiţi exact cât de înaltă trebuie să fie secţiunea
Detail. De exemplu, este foarte posibil ca o înregistrare să nu aibă
nimic într-un câmp de tip memo, în timp ce altă înregistrare să
ocupe o jumătate de pagină sau chiar mai mult. Proprietăţile Can
Grow (poate creşte) şi Can Shrink (se poate micşora) ale secţiunii
Detail determină pentru aceasta o înălţime variabilă, în funcţie
de fiecare înregistrare în parte.
• Page Footer – Apare în partea de jos a fiecărei pagini a
raportului. Cel mai adesea conţine data şi ora şi, eventual,
numărul paginii. Observaţi, din figura 9.10, că secţiunea Page
Footer a raportului Student_Cursuri conţine două casete de text, ce
au ca surse de date expresiile: Now () şi
=”Page “ & [Page] & “ of “ & [Pages]
Prima afişează data curentă, iar cea de-a doua, pagina curentă din
numărul total de pagini ale raportului. Variabila [Page] are ca
valoare numărul paginii curente, iar variabila [Pages], numărul total
de pagini. Pentru a tipări aceste informaţii în subsolul de pagină
al unui raport, alegeţi opţiunile Page Numbers şi, respectiv, Date
and Time din meniul Insert.
Report Footer – Apare numai pe ultima şi poate conţine totaluri ale
datelor diverselor secţiuni ale raportului. Pentru a afişa totalul
unui control numeric, adăugaţi la această secţiune o casetă text,
a cărei proprietate Control Source să aibă valoarea:=Sum
([Nume_Control]). Dacă doriţi ca totalurile să fie afişate pe o
pagină separată la sfârşitul raportului, daţi proprietăţii
ForceNewPage a acestei secţiuni valoarea Before Section (înaintea
secţiunii).
În plus, faţă de aceste secţiuni pe care le-am întâlnit şi la
crearea formularelor, un raport poate avea un număr de antete şi
subsoluri de grup, care să afişeze titlurile câmpurilor ce definesc
grupul respectiv şi totaluri în cadrul grupului.
9.4. Proprietăţile unui raport
Pentru a deschide pagina de proprietăţi a unui raport, procedaţi
exact ca în cazul formularelor: faceţi clic pe careul negru din
colţul din stânga-sus al raportului în modul Design View şi
alegeţi comanda Properties din meniul View. În continuare, vă
prezentăm câteva dintre proprietăţile cu care veţi lucra cel mai
des pentru a determina comportamentul raportului.
• Record Source – Sursa de date a raportului poate fi o tabelă, o
interogare sau o instrucţiune SQL.
• Filter: - Numele unei interogări (sau al unei instrucţiuni SQL)
care limitează numărul de înregistrări din tabela de bază ce vor
fi afişate în raport.
• Filter On: - Dacă are valoarea Yes, filtrul definit de
proprietatea Filter se va aplica.
• Order By: - Un câmp sau o listă de câmpuri separate prin
virgule, din sursa de date a raportului în funcţie de care va fi
stabilită ordinea în care vor fi afişate datele.
• Order By On: - Dacă are valoarea Yes, se va face sortarea
stabilită de proprietatea Order By.
• Caption: - Numele care apare în bara de titlu a formularului în
modul Print Preview.
• Record Locks: - Dacă are valoarea All Records (toate
înregistrările), alţi utilizatori nu vor putea modifica datele din
tabelele de bază ale raportului atâta timp cât acesta nu este
vizualizat sau tipărit (pentru aplicaţi multiuser).
• Page Header şi Page Footer: - Stabileşte dacă antetul şi/sau
subsolul de pagină va fi tipărit şi pe paginile în care apare
antetul şi/sau subsolul raportului.
• Picture: - Dacă doriţi ca pe fundalul raportului să apară o
imagine, aici puteţi introduce numele şi calea unui fişier cu
extensia .bmp, .dib, .wmf sau .emf.
• Picture Type: - Determină dacă imaginea specificată de
proprietatea Picture va fi salvată în baza de date sau va fi
păstrată într-un fişier separat.
• Picture Size Mode: - Determină în ce mod imaginea specificată de
proprietatea Picture va fi micşorată în cazul în care nu încape
în pagină.
• Picture Alignment: - Arată dacă imaginea specificată de
proprietatea picture va fi centrată sau aliniată la stânga sau
dreapta paginii.
• Picture Tiling: - Dacă imaginea specificată de proprietatea
Picture este mai mică decât pagina, ea se va repeta pe toată pagina.
• Picture Pages: - Determină dacă imaginea specificată de
proprietatea Picture va fi tipărită pe toate paginile, numai pe
prima, sau pe nici una.
• Layout for Print: - Dacă are valoarea Yes, la proiectarea
raportului nu veţi putea folosi decât fonturile native ale
imprimantei şi pe cele True Type.
Cea mai bună cale de a descoperi cum lucrează proprietăţile unui
raport este totuşi să le testaţi cu diferite valori pe care le pot
lua.
9.5. Sortarea şi gruparea datelor
Dacă veţi alege comanda Sorting and Grouping din meniul View, în
timp ce raportul Student_Cursuri este deschis în modul Design View, se
va deschide cutia de dialog prezentată în figura 9.11.
Fig. 9.11
Posibilitatea de grupa şi de a sorta înregistrările este ceea ce
deosebeşte rapoartele de formulare. Cutia de dialog din figura 9.11.
vă permite să stabiliţi ordinea de sortare a înregistrărilor.
Cheia de sortare cea mai semnificativă se află pe prima poziţie din
lista Field/Expression (Grupa, în acest exemplu). Urmează apoi
coloanele NrMatricol şi, respectiv, Denumire. Cu alte cuvinte, pentru
fiecare grupă, se vor afişa toţi studenţii, în ordinea
crescătoare a numerelor lor matricole şi, pentru fiecare student, se
vor afişa cursurile la care acesta s-a înscris, în ordinea
alfabetică a denumirilor lor. Dacă veţi dori să inversaţi ordinea
de sortare pentru un anumit câmp din această listă, alegeţi în
câmpul corespunzător din coloana Sort Order cealaltă opţiune
(Descending (descendentă) dacă iniţial ordinea era Ascending
(ascendentă) şi invers). Pentru fiecare câmp din listă puteţi
stabili cinci proprietăţi:
• Group Header: Dacă are valoarea Yes, Access va crea pentru acest
câmp o secţiune antet, în care puteţi include ce controale doriţi.
De exemplu, pentru coloana Grupa, acest antet conţine o casetă de
text care are ca sursă de date chiar această coloană.
• Group Footer: Dacă are valoarea Yes, Access va crea pentru acest
câmp o secţiune subsol, unde aţi putea include controale care să
afişeze diferite totaluri pentru grupul respectiv. Deocamdată, nici
unul dintre grupurile definite nu are subsol, dar în cadrul acestui
capitol, vom adăuga unul.
• Group On: Dacă valoarea sa este Each Value, Access va considera ca
făcând parte din acelaşi grup doar înregistrările pentru care
valorile câmpului respectiv sunt egale. Cu alte cuvinte, pentru
fiecare valoare a câmpului, Access va crea un grup separat care,
eventual, va avea un antet şi/sau un subsol. Dacă valoarea sa este
Interval (pentru câmpuri numerice), grupurile se vor extinde la toate
înregistrările pentru care valoarea câmpului respectiv se află
într-un interval specificat. Pentru câmpuri de tip text, avem
opţiunea Prefix Characters care va considera ca făcând parte din
acelaşi grup toate înregistrările pentru care valoarea câmpului
respectiv începe cu aceleaşi n caractere, unde n este valoarea
proprietăţii Group Interval. De asemenea, pentru coloane de tip
sate/time, această proprietate mai poate avea valorile “Year”,
“Quarter”, “Month” etc., înregistrările putând fi astfel
grupate pe ani, trimestre, luni etc.
• Group Interval: Dacă valoarea proprietăţii Group On este alta
decât “Each Value”, proprietatea Group Interval defineşte
intervalul în care se poate afla valoarea câmpului respectiv pentru a
face parte dintr-un grup.
• Keep Together: Dacă are valoarea No, Access va trece la o pagină
nouă numai atunci când pagina curentă este plină. Dacă are
valoarea Whole Group (întregul grup), Access va face tot posibilul ca
antetul, subsolul şi secţiunea Detail a grupului să se afle pe
aceeaşi pagină. Dacă ele nu încap în pagina curentă, se va trece
la o pagină nouă. Dacă are valoarea With First Detail (numai primul
detaliu), Access va trece la o pagină nouă dacă antetul şi cel
puţin prima înregistrare de la secţiunea Detail a grupului nu încap
pe pagina curentă.
9.6. Folosirea funcţiilor agregat în cadrul rapoartelor
Raportul Student_Cursuri ar furniza mai multă informaţie dacă ar
afişa, pentru fiecare student, media cursurilor opţionale la care s-a
înscris. Am mai spus că cel mai bun loc pentru a afişa totaluri este
subsolul unei secţiuni sau al unui grup. Pentru exemplul nostru, media
ar trebuie să fie afişată în subsolul grupului determinat de
coloana NrMatricol dar, după cum puteţi vedea şi în figura 9.10,
acest grup nu are subsol. Pentru a adăuga un subsol pentru grupul
NrMatricol, deschideţi fereastra Sorting and Grouping şi daţi
proprietăţii Group Footer a acestui grup valoarea Yes. Access va crea
subsolul NrMatricol Footer şi îl va plasa între secţiunea Detail
şi secţiunea Page Footer. Acum nu mai trebuie decât să plasaţi în
acest subsol o casetă de text şi să daţi proprietăţii
RecordSource ca valore expresia:
=Avg ([Nota])
Eventual, daţi proprietăţii Caption a etichetei asociate valoarea
“Media:” iar proprietăţii Name a casetei, valoarea txtMedia. Acum
formularul deschis în modul Design View va arăta ca în figura 9.12:
Fig. 9.12
Cel mai important lucru, atunci când folosim funcţii agregat în
rapoarte, este acela că Access restrânge numărul de înregistrări
pentru care se face agregarea numai la grupul curent. Astfel, dacă
includeţi o funcţie agregat în cadrul antetului sau subsolului unui
grup, vor fi luate în considerare numai înregistrările care fac
parte din acel grup. Dacă o includeţi la secţiunea Page Header sau
Page Footer, funcţia va lua în considerare numai înregistrările din
pagina respectivă, iar dacă o includeţi la secţiunea Report Header
sau Report Footer, funcţia va calcula totalul pentru toate
înregistrările raportului. Astfel, puteţi crea atâtea sub-totaluri
câte grupuri are raportul.
Alte funcţii agregat pe care le veţi folosi frecvent sunt:
Sum([câmp_numeric]) (pentru calcularea sumelor),
Count([câmp_numeric]) (pentru a număra înregistrările),
Min([câmp_numeric]) (pentru a afla minimul) şi Max([câmp_numeric])
(pentru a afla maximul). Puteţi, de asemenea, să creaţi expresii în
care să folosiţi funcţii agregat şi să le afişaţi drept
totaluri:
=Sum([Nota]) / Count([Denumire])
9.7. Editarea rapoartelor
Am creat mai devreme raportul Student_Cursuri folosind Report Wizard
şi, apoi, i-am adăugat o casetă de text a cărei sursă de date este
o funcţie agregat. Deşi raportul ne oferă multe informaţii utile,
aspectul său ar mai putea fi îmbunătăţit: titlurile coloanelor ar
putea fi schimbate (Access a folosit numele câmpurilor, care nu sunt
întotdeauna intuitive şi prezentabile); formatul în care sunt
afişate mediile ar trebui modificat astfel încât să aibă numai
două zecimale; am putea evidenţia anumite texte şi, eventual, am
putea introduce numere de ordine.
Bineînţeles că toate aceste modificări nu vor putea fi făcute
decât în modul Design View. Pentru a schimba titlurile coloanelor,
selectaţi etichetele corespunzătoare de la secţiunea Page Header
şi, în pagina lor de proprietăţi, modificaţi proprietatea Caption:
în loc de “NumeSt” şi “PrenumeSt”, introduceţi, de exemplu,
doar “Nume” şi “Prenume”, iar în loc de “Denumire”,
introduceţi “Cursuri”. Chiar şi titlul raportului ar putea fi
îmbunătăţit, din “Student_Cursuri” în “Studenti si
Cursuri”. Probleme de aspect ar mai putea ridica şi alinierea
textului în controale. Dacă proprietatea “Text Align” (alinierea
textului) a unei etichete are valoarea “General”, textul va fi
aliniat la stânga controlului, iar dacă aceeaşi proprietate a unei
casete de text are această valoare, textele vor fi aliniate la stânga
iar valorile numerice sau de tip date/time vor fi aliniate la dreapta.
Pentru a schimba aceste valori, alegeţi explicit una dintre celelalte
valori ale proprietăţii Text Align: “Left” (la stânga),
“Center” (centrat) şi “Right” (la dreapta).
Pentru ca mediile să fie afişate cu exact două zecimale, selectaţi
cutia de text txtMedia adăugată la secţiunea anterioară şi daţi
proprietăţii Format valoarea “Fixed” iar proprietăţii Decimal
Places, valoarea 2. De asemenea, media fiind o informaţie importantă,
ar fi bine să o evidenţiem într-un fel. Pentru aceasta, daţi
proprietăţii Font Weight a casetei de text valoarea “Bold” şi,
astfel, mediile vor fi scrise îngroşat.
Un alt element des întâlnit în rapoarte îl reprezintă numerele de
ordine. Să presupunem că în dreptul fiecărui student dorim să
apară al câtelea este în cadrul raportului. Pentru aceasta,
adăugaţi la secţiunea “NrMatricol Header” o nouă casetă de
text (ştergeţi eticheta asociată, deoarece nu ne trebuie), a cărei
proprietate Control Source să fie =1. Pentru ca numărul de ordine să
fie incrementat cu unu la fiecare student, daţi proprietăţii Running
Sum a acestei casete de text valoarea “Over All”. Dacă am fi dorit
ca numerotarea să reînceapă pentru fiecare grupă, valoarea
proprietăţii Running Sum ar fi trebuit să fie “Over Group”.
Dacă observaţi că pentru anumite valori ale înregistrărilor
textul care trebuie să apară într-un control nu se vede în
întregime deoarece controlul nu este suficient de mare, daţi
proprietăţii Can Grow a controlului respectiv valoarea Yes. Astfel,
controlul va fi redimensionat automat, ca să poată afişa textul în
întregime. Acesta poate fi şi cazul casetei de text care afişează
denumirile cursurilor.
CAP:10. FOLOSIREA DATELOR EXTERNE
Rolul principal al unei baze de date este stocarea informaţiilor.
Până acum, aţi învăţat cum sunt stocate datele în Access şi cum
să le manipulaţi după ce acestea se găsesc în baze de date. Mai
trebuie să aflaţi cum puteţi transfera date în şi din Access şi
cum să folosiţi date din alte baze de date.
În acest capitol, se va prezenta:
• Să importaţi date în Access
• Să exportaţi date din Access
• Să expediaţi date prin poşta electronică
• Să folosiţi date din baze de date externe
10.1 Copierea în sau din alte aplicaţii
Desigur, există mii de aplicaţii care stochează informaţii şi ar
fi util să puteţi schimba date cu acestea. Deoarece fiecare
aplicaţie stochează datele într-un format propriu, pentru a face
schimb de date ar trebui să cunoaşteţi formatul respectiv. Din
fericire, nu trebui să cunoaşteţi detalii despre toate aplicaţiile,
ci doar despre cele mai importante. Dacă vreţi să schimbaţi date cu
un program care nu apare în listă, puteţi alege un format standard,
care să poată fi citit atât de programul respectiv, cât şi de
aplicaţia dumneavoastră.
Access poate schimba date cu patru tipuri de aplicaţii:
• Fişiere de tip text
• Mesaje poştale
• Baze de date
• Foi de calcul tabelar
De obicei, veţi lucra cu baze de date sau foi de calcul mai vechi,
ori cu sisteme private moştenite, pe care doriţi să le înlocuiţi
cu Access. În oricare dintre cazuri, vă veţi da seama că
facilităţile de import şi export sunt extrem de simple şi
flexibile.
10.1.1 Baze de date
Bazele de date diferă de la sisteme desktop mici, din care face parte
Access, la baze de date stocate pe servere de dimensiuni medii şi
până la baze de date stocate pe calculatoare mainframe de dimensiuni
foarte mari. În Access, pentru transferul datelor între baze de date
se foloseşte metoda TranferDatabase a obiectului DoCmd.
Parantezele pătrate indică un argument opţional. Să analizăm în
detaliu argumentele acestei metode:
Argument Descriere
TransferType Acţiunea pe care doriţi să o executaţi, care poate fi
una dintre următoarele:
acImport pentru a importa date
acExport pentru a exporta date
acLink pentru a lega date
Dacă lăsaţi acest argument necompletat, se foloseşte valoarea
implicită acImport.
DatabaseType Tipul bazei de date în care sau din care doriţi să
efectuaţi transferul. Poate fi una din următoarele:
Microsoft Access FoxPro 3.0
Paradox 3.x FoxPro DBC
Paradox 4.x dBase III
Paradox 5.x dBase IV
FoxPro 2.0 dBase 5.0
FoxPro 2.5 Jet 2.x
FoxPro 2.6 ODBC
DatabaseName Numele complet al bazei de date respective, inclusiv
calea.
ObjectType Tipul de obiect implicat în operaţie, care poate fi unul
din următoarele:
acTable
acQuery
acForm
acReport
acMacro
acModule
Dacă argumentul nu este completat, se foloseşte valoarea implicită
acTable.
Source Numele obiectului din care provin datele.
Destination Numele obiectului în care sunt transferate datele.
StructureOnly Trebuie să fie True dacă obiectul este un tabel şi se
transferă doar structura. Dacă este False, vor fi copiate şi datele.
Valoarea implicită este False.
SaveLoginID Se foloseşte numai pentru surse de date ODBC. Dacă este
True, numele de conectare (login) şi parola vor fi memorate pentru
conexiunile următoare. Dacă este False, va trebui să parcurgeţi
procesul de conectare de fiecare dată când accesaţi sursa de date.
Valoarea implicită este False.
Exerciţiu:- Comanda TransferDatabase
La fel ca majoritatea magazinelor, Whisky Shop trebui să tipărească
o broşură de prezentare a ofertei, iar editurile cer ca lista de
băuturi să fie transmisă în format de bază de date. În
continuare, vom crea această bază de date.
1. Închideţi orice bază de date pe care aţi deschis-o anterior şi
alegeţi New Database… (o nouă bază de date) din meniul File.
2. În pagina etichetei General, selectaţi opţiunea Blank Database
(Bază de date goală) şi executaţi clic pe OK. Denumiţi noua bază
de date Brochure (Broşură) şi salvaţi-o în directorul BegVBA (sau
în directorul care conţine bazele de date de exemplificare).
3. Acum închideţi această bază de date şi deschideţi fişierul
Student.mdb. Deoarece în viitor vom executa operaţiunea de export la
intervale regulate, vom crea acum un formular şi îl vom configura ca
pe o componentă permanentă.
4. Deschideţi formularul Outside World, frmOutsideWorld, în modul de
afişare Form. Veţi vedea că există deja un grup de opţiuni, fiind
creată prima intrare.
5. Trebuie să activăm butonul Export astfel încât, dacă se
execută clic asupra lui atunci când opţiunea de deasupra este
selectată, lista de băuturi să fie exportată automat în baza de
date Brochure.mdb. Pentru aceasta, adăugăm comanda TransferDatabase
în procedura de tratare a evenimentului clic. Treceţi în modul de
afişare Design şi alegeţi evenimentul On Click din foaia de
proprietăţi. Adăugaţi comanda TransferDatabase în forma
următoare:
Am folosit o instrucţiune Select Case care ne permite să adăugăm
ulterior în formular şi alte butoane de opţiune.
6. Închideţi fereastra modulului şi treceţi în modul de afişare
Form. Selectaţi opţiunea Export to Brochure Database şi executaţi
clic pe butonul Export din formular. Această acţiune va lansa în
execuţie noua procedură, determinând exportul listei de băuturi din
tabelul Curs în noua bază de date, într-un tabel numit Lista
Cursuri. Dacă efectuăm exportul într-o bază de date existentă, iar
tabelul este deja inclus, acesta va fi înlocuit.
7. Închideţi fişierul Student.mdb, salvând modificările efectuate
în formular, şi deschideţi Brochure.mdb, care conţine acum noul
tabel. Deschideţi tabelul pentru a vedea datele.
8. Tabelul poate fi vizualizat şi editat, iar dumneavoastră aveţi
posibilitatea să modificaţi câmpul CursID.
9. Treceţi formularul în modul de afişare Design şi executaţi clic
pe butonul Export. Înainte de a deschide fişierul Brochure.mdb,
anticipaţi ceea ce veţi vedea pe ecran.
Deşi comanda TransferDatabase este foarte flexibilă, nu veţi lucra
prea mult cu ea. De obicei, este folosită pentru a converti baze de
date din sisteme mai vechi în Access 97 sau pentru a face copii de
siguranţă, complete sau parţiale, ale unei baze de date. De exemplu,
puteţi folosi această comandă pentru a implementa o procedură
automată de salvare de siguranţă (backup). În acest scop, creaţi
un tabel care să cuprindă elementele care trebuie salvate şi
momentul declaşării acestei operaţii, astfel încât aplicaţia să
poată verifica periodic acest tabel şi să execute o comandă
TransferDatabase pentru obiectele şi în momentele specificate.
10.1.2 Foi de calcul tabelar
Transferul datelor în foi de calcul este una dintre cele mai
apreciate facilităţi de transfer. Access 97 este ideal pentru
interogarea datelor şi realizarea de rapoarte, însă atunci când
doriţi să analizaţi date numerice, cel mai bine este să folosiţi o
foaie de calcul tabelar. Puteţi analiza numere şi în Access, însă
nu are nici un rost, din moment ce există instrumentul numit Microsoft
Excel, care este foarte puternic, iar transferul datelor se realizează
foarte uşor. Pentru a transfera date în sau dintr-o foaie de calcul
tabelar, folosiţi metoda TransferSpreadsheet a obiectului DoCmd:
Argumentele sunt similare cu cele ale comenzii TransferDatabase, pe
care am analizat-o în secţiunea precedentă.
Argument Descriere
TransferType Acţiunea pe care doriţi să o executaţi, care poate fi
una dintre următoarele:
acImport pentru a importa date
acExport pentru a exporta date
acLink pentru a lega date
Dacă lăsaţi acest argument necompletat, se foloseşte valoarea
implicită acImport.
SpreadsheetType Un număr reprezentând tipul de foaie de calcul în
sau din care efectuaţi transferul. Constantele pe care le puteţi
folosi sunt următoarele:
acSpreadsheetTypeExcel13
acSpreadsheetTypeExcel14
acSpreadsheetTypeExcel15
acSpreadsheetTypeExcel17
acSpreadsheetTypeExcel97
acSpreadsheetTypeExcelLotusWK1
acSpreadsheetTypeExcelLotusWK3
acSpreadsheetTypeExcelLotusWK4
acSpreadsheetTypeExcelLotusWJ2 (doar versiunea japoneză)
TableName Numele tabelului sau interogării implicate în transfer.
FileName Numele fişierului care conţine foaia de calcul, inclusiv
calea.
HasFieldName Dacă doriţi să folosiţi primul rând al tabelului
sursă sau al foii de calcul pentru numele câmpurilor din tabelul sau
foaia de calcul destinaţie, argumentul trebuie să aibă valoarea
True; dacă doriţi să trataţi primul rând ca pe nişte date
obişnuite, valoarea trebuie să fie False. În mod implicit, se
foloseşte valoarea False.
Range Se aplică numai la operaţiile de import. Trebuie să conţină
domeniul de celule sau numele domeniului care va fi importat. Dacă
este lăsat necompletat, va fi importată întreaga foaie de calcul.
Importul datelor din foile de calcul se realizează la fel de simplu.
Mulţi utilizatori încearcă să evite bazele de date, având impresia
că sunt prea complexe. Totuşi, la un moment dat, datele devin prea
complicate pentru a fi stocate într-o foaie de calcul tabelar şi va
trebui să le importaţi într-o bază de date, împărţindu-le în
tabele. În acest caz, folosiţi metoda TransferSpreadsheet aproape în
acelaşi format ca mai sus.
În capitolele următoare, veţi întâlni şi alte exemple de transfer
al datelor în Excel.
10.1.3 Fişiere de text
Există două modalităţi de a importa şi exporta date de tip text.
Prima foloseşte fişiere de text cu caractere delimitatoare, în care
un anumit caracter determină unde se termină un câmp şi începe
altul. A doua metodă foloseşte fişiere de text cu lăţime fixă,
care necesită ca toate câmpurile şi înregistrările să aibă
poziţii prestabilite în cadrul fişierului - fiecare înregistrare
(şi câmp pe care îl conţine) are acelaşi număr de caractere ca
toate celelalte înregistrări.
Ambele tehnici de lucru folosesc metoda TransferText a obiectului
DoCmd:
Argumentele sunt similare cu cele ale metodelor prezentate anterior:
Argument Descriere
TransferType Acţiunea pe care doriţi să o executaţi, care poate fi
una dintre următoarele:
acExportDelim
acExportFixed
acExportHTML
acExportMerge
acImportDelim
acImportFixed
acImportHTML
acLinkDelim
acLinkFixed
acLinkHTML
Dacă lăsaţi acest argument necompletat, se foloseşte valoarea
implicită acImportDelim.
SpecificationName Numele specificaţiei de import/export. Este
obligatorie pentru fişierele cu lăţime fixă, dar nu şi pentru
fişierele cu caractere delimitatoare. (Deoarece când lucraţi cu
fişiere de text rebuie să furnizaţi multe valori de configurare,
acestea sunt stocate de obicei pe disc ca o specificaţie, iar numele
acestui grup de informaţii este folosit apoi ca argument pentru metoda
TransferText. Altfel, va trebui să transmiteţi de fiecare dată
valori pentru o mulţime de argumente. Vom mai vorbi despre
specificaţii în cele ce urmează).
TableName Numele tabelului pe care doriţi să îl importaţi,
exportaţi sau legaţi, ori numele interogării ale cărei rezultate
doriţi să le exportaţi.
FileName Numele fişierului de text, inclusiv calea.
HasFieldName Este True dacă primul rând al fişierului de text
conţine numele de câmpuri şi False în caz contrar. Dacă argumentul
este lăsat necompletat, se foloseşte valoarea implicită False.
HTMLTableName Numele tabelului (sau listei) din documentul HTML pe
care doriţi să le importaţi sau să îl exportaţi. Această
opţiune este ignorată, mai puţin în cazul în care aţi specificat
un transfer HTML (acExportHTML sau acImportHTML). Dacă lăsaţi
argumentul necompletat, este folosit primul tabel (sau prima listă).
Vom detalia acest argument în secţiunea despre Internet.
10.1.4 Fişiere de text cu caractere delimitatoare
Fişierele de text cu caractere delimitatoare folosesc un caracter
special pentru a separa câmpurile înregistrărilor. În majoritatea
cazurilor, acest caracter este o virgulă, deci fişierul de text va
conţine linii de cod de genul:
camp 1, camp 2, camp 3, camp 4
Încercaţi singur - Comanda TransferText
Magazinul Whisky Shop a fost inclus recent în ancheta unei reviste
care încearcă să determine tendinţele în cumpărarea de whisky.
Ziariştii s-au arătat interesaţi mai ales de tipurile de whisky
vândute şi de perioada calendaristică. Pentru a-i ajuta, le
transmitem o listă în format text cu caractere delimitatoare.
Adăugaţi un nou buton de opţiune în formularul Outside World.
Acesta va avea valoarea 3. Etichetaţi acest buton ca în figura
alăturată:
Adăugaţi următoarea secevnţă de cod la instrucţiunea Select Case
din procedura care tratează acţionarea butonului Export.
1. Treceţi formularul în modul de afişare Form, selectaţi al
treilea buton de opţiune şi executaţi clic pe Export. Deschideţi
în programul Notepad fişierul C:\BegVBA\Survey.txt. Ar trebui să
arate ca în figura alăturată.
Observaţi că specificaţia implicită cuprinde o virgulă ca
separator de câmpuri şi ghilimele pentru text. Acest tip de fişier
este numit Comma Separated Value (sau CSV) (adică fişier cu valori
separate prin virgule) şi reprezintă cea mai sigură formă de
transfer, fiind folosit şi recunoscut pe scară largă. Utilizarea
ghilimelelor în jurul textului este importantă, pentru că astfel, o
virgulă dintr-un şir de text nu mai poate fi confundată cu un
separator de câmpuri. Oricum, trebuie să fiţi foarte atent la
ghilimelele care apar în cadrul textului. De exemplu, apostroful este
un caracter valabil într-un şir, iar dacă un câmp conţine un
apostrof, nu doriţi ca acesta să marcheze sfârşitul câmpului. Este
bine să verificaţi conţinutul datelor înainte să aplicaţi
această metodă, pentru că utilizarea necorespunzătoare a virgulelor
şi ghilimelelor poate avea rezulate imprevizibile.
10.1.5 Fişiere de text cu lăţime fixă
Cealaltă metodă pentru transferul datelor prin fişiere de text
evită orice posibilă confuzie creată de ghilimele, separatoare de
câmpuri şi nume de câmpuri. Este necesară utilizarea unei
specificaţii care să detalieze numele de câmpuri, locul unde începe
fiecare câmp şi dimensiunea acestora. Cea mai simplă metodă de a
crea specificaţii este oferită de aplicaţia Wizard Text Export.
10.2 Compunerea mesajelor poştale
Ţinând cont de cantităţile mari de informaţii care sunt
înregistrate în bazele de date, este foarte important să puteţi
compune (combina) datele în cadrul unor documente obţinute în
editoare de text. De exemplu, această tehnică ar permite expedierea
unor mesaje poştale către toţi clienţii magazinului Whisky Shop,
pentru a-i anunţa despre oferte speciale sau promoţinale, dar şi
despre operaţii curente şi facturi.
Încercaţi singur - Crearea unui fişier de compunere a mesajelor
poştale
Puteţi folosi facilităţile de export din Access 97 pentru a crea un
fişier de compunere a mesajelor poştale în programul Microsoft Word.
Adăugaţi în formularul Outside World un alt buton de opţiune, de
data aceasta cu valoarea 4, şi etichetaţi-l ca în figura
alăturată:
1. Completaţi instrucţiunea Select Case cu următoarea secvenţă de
cod:
2. Acum treceţi formularul în modul de afişare Form, selectaţi
opţiunea de compunere a mesajelor poştale (Mail Merge) şi executaţi
clic pe butonul Export. Va fi creat un fişier Microsoft Word cu numele
Customers.doc, care poate fi folosit ca sursă de date pentru
compunerea mesajelor poştale.
Săgeţile care apar în figura anterioară indică faptul că într-un
fişier Word de compunere a mesajelor poştale sunt folosite caractere
Tab pentru a separa câmpurile înregistrărilor. Şirurile de text
sunt încadrate de ghilimele.
În capitolele următoare, veţi întâlni şi alte exemple referitoare
la transferul datelor din Access în Word.
10.3 Exportul altor obiecte
Până acum, aţi aflat cum să exportaţi date din tabele sau
rezultate în urma unor interogări, însă vor apărea şi situaţii
în care va trebui să exportaţi date din alte obiecte Access. În
aceste cazuri, puteţi folosi metoda OutputTo a obiectului DoCmd:
Argumentele sunt prezentate în tabelul următor:
Argument Descriere
ObjectType Obiectul pe care doriţi să îl exportaţi. Poate fi:
acOutputForm
acOutputModule
acOutputQuery
acOutputReport
acOutputTable
ObjectName Numele obiectului Access.
OutputFormat Formatul în care va fi exportat obiectul. Trebuie să fie
una dintre următoarele constante:
acFormatActiveXServer pentru Microsoft Active Server Pages.
acFormatHTML pentru un document HTML.
acFormatIIS pentru Microsoft Internet Information Server.
acFormatRTF Rich Text Format.
acFormatTXT pentru format text Notepad.
acFormatXLS pentru format Microsoft Excel.
OutputFile Numele fişierului (inclusiv calea) în care trebuie
transferat obiectul.
AutoStart Folosiţi valoarea True pentru a porni automat aplicaţia
asociată cu tipul de format extern şi False în celelalte cazuri.
Dacă argumentul nu este indicat, se foloseşte valoarea implicită
False.
TemplateFile Numele şablonului pentru fişiere HTML, HTX sau ASP. Vom
discuta despre acestea în Capitolul 17, Internet.
Încercaţi singur - Comanda OutputTo
1. Din pagina etichetei Report, deschideţi raportul rptWhiskyTotal.
Observaţi că acest raport conţine şi text formatat. Vom transfera
raportul într-un fişier de tip RTF (Rich Text Format).
2. Deschideţi formualrul Outside World şi adăugaţi al cincilea
buton de opţiune. Acesta va avea valoarea 5:
3. Adăugaţi codul următor la instrucţiunea Select Case:
4. După ce deschideţi formularul frmOutsideWorld, alegeţi această
opţiune şi executaţi clic pe butonul Export; programul World este
lansat automat şi afişează acest document.
Notă: Observaţi că numele de fişier conţine sufixul RTF, astfel ca
Windows 95 sau Windows NT să poată identifica tipul de fişier. RTF
provine de la Rich Text Format (text cu format îmbunătăţit), care
permite includerea formatului în documentul de text şi este
standardul Microsoft pentru formatarea documentelor. Utilizarea acestui
standard asigură lansarea în execuţie a programului Word. În mod
similar, dacă folosiţi constanta acFormatXLS, ar trebui să
adăugaţi extensia XLS la sfârşitul numelui de fişier. Chiar dacă
Access 97 cunoaşte tipul de fişier pe care îl creaţi, nu adaugă
sufixul în locul dumneavoastră.
Fiind vorba de un fişier RTF, s-au păstrat toate elementele de
formatare. Totuşi, observaţi că linia de deasupra totalului pe
regiune nu a fost transferată. Ţineţi cont de acest comportament
dacă folosiţi în rapoarte elemente grafice, pentru că acestea nu
sunt salvate într-un fişier RTF. Este o opţiune utilă atunci când
doriţi să distribuiţi rapoarte simple, fără să le tipăriţi la
imprimantă.
10. 4 Poşta electronică
O altă modalitate de distribuire a datelor este prin poşta
electronică. Marele avantaj al utilizării sistemului de poştă
electronică (e-mail) este uşurinţa cu care puteţi transmite date,
nu numai în reţele locale, ci în întreaga lume. Răspândirea
reţelelor globale (MicrosoftNetwork, CompuServe, America On Line,
Internet etc.) a redus timpul necesar utilizatorilor pentru a obţine
informaţiile de care au nevoie - nu mai sunteţi nevoiţi să
tipăriţi un raport la imprimantă, să faceţi cinci copii xerox pe
care să le expediaţi la filialele companiei. Acum, alegeţi numele
destinatarilor din agenda electronică şi transmiteţi raportul
respectiv într-un minut.
Puteţi transmiteţi mesaje de poştă electronică printr-o
diversitate de programe client, cum ar fi Microsoft Exchange şi
Outlook, Eudora, Pegasus etc. în exemplele din carte am folosit
Microsoft Outlook, însă şi alte programe client lucrează la fel de
bine.
Marele avantaj al programului Microsoft Outlook este faptul că poate
fi utilizat ca un client unic de poştă electronică pentru diferite
tipuri de reţele şi, din moment ce Outlook se ocupă de toate
problememle de adresare, nu trebuie să ştiţi ce tip de reţea
folosiţi. Dumneavostră nu faceţi decât să specificaţi adresele,
iar Outlook se ocupă de distribuirea mesajelor. Pentru a transfera
date prin poşta electronică, se foloseşte metoda SendObject a
obiectului DoCmd:
Deşi există mai multe argumente decât în exemplele anterioare,
acestea sunt toate foarte simple:
Argument Descriere
ObjectType Obiectul pe care doriţi să îl transferaţi. Poate fi:
acSendForm
acSendModule
acSendNoObject (doar pentru expedierea unui mesaj poştal)
acSendQuery
acSendReport
acSendTable
Dacă lăsaţi acest argument necompletat, se foloseşte în mod
implicit acSendNoObject.
ObjectName Numele obiectului Access.
OutputFormat Formatul în care se transferă obiectul. Poate fi:
acFormatXLS pentru format Microsoft Excel
acFormatRTF pentru format RTF Microsoft Word
acFormatTXT pentru format de text Notepad
acFormatHTML pentru format HTML
Dacă lăsaţi acest argument necompletat, Access vă cere să alegeţi
un format.
To O listă de destinatari pentru poşta electronică. Dacă sunt mai
mulţi, trebuie să folosiţi ca separator caracterul punct şi
virgulă (;) (sau caracterul List Separator prezentat în eticheta
Number a foii de proprietăţi Regional Settings din panoul de control
Windows). Dacă lăsaţi acest argument necompletat, Access vă cere
să introduceţi recipientele.
CC O listă de destinatari pentru linia cc.
BCC O listă de destinatari pentru linia bcc.
Subject Un şir care conţine linia de subiect a mesajului.
MessageText Un şir care conţine textul mesajului. Este plasat după
obiectul ataşat.
EditMessage Pentru a deschide aplicaţia de poştă electronică
imediat (şi a permite editarea), trebuie să folosiţi valoarea True.
Pentru a transmite direct un mesaj, trebuie să folosiţi valoarea
False. Dacă lăsaţi argumentul necompletat, se foloseşte valoarea
implicită False.
TemplateFile Numele unui fişier (inclusiv calea) care va fi folosit
ca şablon pentru documentele HTML.
În exemplul următor, un raport este transmis mai multor persoane,
una dintre ele foloseşte CompuServe, alta InternetMail, iar a treia
Microsoft Exchange. În Access, trebuie doar să specificaţi numele.
Nu este necesar să ştiţi ce sistem de poştă electronică
foloseşte destinatarul.
Încercaţi singur - Poşta electronică
Este evident că pentru acest exemplu, aveţi nevoie de o conexiune la
un sistem de poştă electronică. Însă, chiar în lipsa acesteia,
puteţi să parcurgeţi procedura fără a o implementa efectiv, pentru
a vedea cât de uşor poate fi adăugată această facilitate în
aplicaţiile Access.
Adăugaţi în grupul de opţiuni un alt buton - de data aceasta, va
avea valoarea 6.
Deoarece acest formular este destinat exportului de date, nu trebuie
să îl aglomeraţi cu detalii referitoare la poşta electronică, aşa
încât este bine să lăsaţi toate adresele necompletate. Adăugaţi
următoarea secvenţă de cod la instrucţiunea Select Case:
Prin această instrucţiune, transmitem interogarea referitoare la
vânzările lunare în format Microsoft Excel.
Rulaţi acest fragment de cod selectând al şaselea buton de opţiune
în modul de afişare Form şi executând clic pe butonul Export.
Câmpurile To, cc şi bcc sunt necompletate, aşa încât sistemul de
poştă electronică se va deschide normal şi vă va permite să
selectaţi destinatarul (sau destinatarii) din lista de adrese.
Observaţi că linia Subject a fost completată cu textul din
instrucţiune, iar textul suplimentar a fost adăugat după obiect.
În cazul în care completaţi linia To în cadrul codului şi apoi
configuraţi argumentul EditMessage la valoarea False, poşta
electronică este distribuită direct, fără vreo intervenţie din
partea dumneavoastră. Mai simplu de atât nu se poate. Prin urmare,
dacă cineva vă spune că este dificil să comunicaţi prin poşta
electronică din Access, puneţi-l la punct fără nici o jenă.
10.5 Date externe
În secţiunile anterioare ale acestui capitol, am arătat cum pot fi
transferate date în şi din Access, însă există situaţii când
trebuie să folosim date externe fără să le importăm. Access poate
accesa (nu este un joc de cuvinte!) date din alte surse şi acestea
apar în aplicaţiile dumneavoastră ca şi cum ar fi tabele Access,
permiţându-vă astfel să stocaţi datele într-o varietate de
formate, dar să le folosiţi numai din Access. În astfel de
situaţii, puteţi lega datele în baza dumneavoastră de date.
Această tehnică funcţionează în mod similar cu comenzile rapide
(shortcuts) din Windows 95 - datele rămân acolo unde sunt, însă
dumneavoastră aveţi o legătură rapidă la ele. Dacă datele se
modifică, puteţi vizualiza modificările apărute. Dacă
dumneavoastră modificaţi datele din cadrul legăturii, şi datele
originale se modifică.
Deci, care este utlitatea legării dateor externe în Access?
Ei bine, pentru început, trebuie spus că Access vă oferă
posibilitatea dezvoltării unor sisteme noi de baze de date, însă de
multe ori, aveţi deja cantităţi mari de date. Legarea permite
accesul la informaţiile din bazele de date şi foile de calcul mai
vechi, în timp ce un sistem nou trebuie dezvoltat de la zero. Există
şi varianta folosirii facilităţilor de interogare şi de crearea a
rapoartelor din Access, păstrând însă aplicaţia existentă.
De asemenea, puteţi să separaţi componentele back-end şi front-end
ale aplicaţiei. Componenta back-end cuprinde datele propriu-zise, în
timp ce componenta front-end este interfaţa cu utilizatorul. Aceasta
din urmă include formularele, rapoartele, interogările,
macroconstrucţiile şi modulele. Astfel, aplicaţia dumneavoastră va
fi divizată în două baze de date Access:
Este o tehnică uzuală, care vă permite să actualizaţi componenta
front-end fără să afecteze componenta back-end. Vă amintiţi ce
dificil este să distribuiţi aplicaţiile la utilizator. Recent
le-aţi dat o copie cu ultima versiune a bazei de date, iar acum doresc
să operaţi modificări - însă au început deja să introducă date.
Prin urmare, trebuie să efectuaţi modificările, dar şi să opriţi
toţi utilizatorii să folosească vechea bază de date şi să
copiaţi datele în una nouă. Însă dacă separaţi componentele
front-end şi back-end, partea care conţine datele nu va trebui
modificată niciodată - puteţi să înlocuiţi componenta front-end
şi apoi să refaceţi legătura cu tabelele.
Dacă decideţi să aplicaţi această metodă după ce aţi creat o
aplicaţie, alegeţi subcomanda Database Splitter din comanda Add-ins a
meniului Tools. Programul wizard ataşat acestei comenzi vă va ghida
prin etapele procesului de separare a tabelelor de restul obiectelor
din baza de date.
Şi tehnica de legare este foarte utilă, dată fiind popularitatea
sistemelor client-server. În acest caz, componenta back-end a bazei de
date este, de obicei, un server puternic de baze de date, cum ar fi
Microsoft SQL Server, care vă pune la dispoziţie facilităţile unei
baze de date relaţionale mari. Puteţi să aveţi toate datele pe
server, pentru a-l folosi la capacitate maximă, dar în acelaşi timp
să continuaţi utilizarea facilităţilor sistemului Access, cum sunt
formularele, interogările şi rapoartele.
În majoritatea cazurilor, puteţi chiar să mutaţi interogările pe
server şi să le executaţi acolo, nu pe propriul calculator. Această
tehnică poate îmbunătăţi viteza de lucru şi, în plus, are
avantajul de a minimiza traficul de reţea. Singurele informaţii care
trec prin reţea sunt instrucţiunile dumneavoastră pentru lansarea
interogărilor şi tabelul cu rezultate returnate de server. Este o
abordare care face parte din modelul client-server şi garantează că
atât clientul, cât şi serverul (de exemplu, SQL Server) lucrează la
parametrii optimi - lăsând serverul să ruleze interogările lungi
şi folosind tabelele Access pentru a accesa rapid informaţii care nu
se modifică frecvent. Este un domeniu prea vast pentru a fi prezentat
aici în detaliu, dar există numeroase cărţi dedicate acestui
subiect.
În Access 2.0 şi în versiunile anterioare, tabelele legate erau
numite tabele ataşate.
10.6 Tabele legate
În mod sigur aţi folosit şi până acum tabele legate. Acestea sunt
marcate în foaia Tables a ferestrei bazei de date cu o săgeată:
Figura alăturată prezintă un tabel din baza de date model Northwind
(distribuită împreună cu programul Access), care a fost legat la
aplicaţia Whisky. Puteţi şterge oricând o legătură, fără să
afectaţi în vreun fel tabelul cu date.
Încercaţi singur - Legarea unui obiect
În acest exemplu, vom folosi argumentul acLink al metodei Transfer
Spreadsheet a obiectului DoCmd. Puteţi folosi acest argument şi cu
metodele TransferDatabase şi TransferText. Vom lega o foaie de calcul
în aplicaţia noastră, însă, nedorind să o definim ca o
componentă permanentă a aplicaţiei, vom lucra în fereastra de
depanare.
1. Deschideţi un modul nou şi introduceţi în fereastra Debug
următoarea secvenţă de cod:
2. Această instrucţiune va face legătura cu foaia de calcul creată
într-un exemplu anterior. Al doilea argument indică faptul că
realizăm o legătură cu un fişier Excel versinea 5.0 sau 7.0.
3. Acum examinaţi pagina Tables a ferestrei bazei de date. Ar trebui
să vedeţi un obiect nou, legat, care este o foaie de calcul (pentru
a-l vizualiza, trebui să comutaţi în altă pagină şi apoi să
reveniţi).
Rezultă că această pagină poate conţine nu numai tabele, ci şi
alte surse de date. Din moment ce sursele de date pot fi legate la
Access, le puteţi edita ca şi când ar fi tabele Access.
Acum puteţi deschide foaia de calcul WhiskySales ca şi când ar fi un
tabel normal. Orice modificări pe care le operaţi aici se vor
reflecta în foaia de calcul, însă fiţi foarte atent la coloanele
care conţin date incomplete sau confuze.
Access a detectat că în a treia coloană apar numere, dar primul
rând conţine titlurile coloanelor, care sunt format text. Dacă
intenţionaţi să legaţi foile de calcul în acest fel, ar trebui să
eliminaţi titlurile de coloane sau să folosiţi în legătură
argumentul Range (Domeniu), pentru a include doar datele corecte.
Încercaţi singur - Reîmprospătarea legăturilor
Dacă intenţionaţi să separaţi o bază de date în componentele
back-end şi front-end, este evident că aveţi nevoie de o modalitate
de reîmprospătare a legăturii dintre tabele. Această operaţie este
utilă nu numai pentru a distribui o nouă copie a bazei de date
front-end, ci şi dacă aplicaţia back-end este instalată în altă
parte decât se aşteaptă Access să o găsească.
1. Creaţi o nouă bază de date (denumiţi-o BackEnd) şi executaţi
clic pe Create. Pentru a importa tabelele din baza de date model,
selectaţi din meniu File/Get External Data şi executaţi clic pe
opţiunea Import. În continuare, selectaţi fişierul Whisky8.mdb în
caseta de dialog Import, executaţi clic pe butonul Select All şi apoi
pe butonul OK în caseta de dialog Import Objects.
2. Închideţi această bază de date, apoi creaţi o altă bază de
date (FrontEnd) şi legaţi tabelele din baza de date BackEnd,
selectând opţiunea Link Tables din meniul File/Get External Data.
Repetaţi procesul de mai sus.
3. Schimbaţi numele bazei de date BackEnd cu NewBackEnd şi
încercaţi să deschideţi unul dintre tabelele legate:
Tabelele de aici sunt doar legate. Ele nu există, de fapt, în baza de
date FrontEnd. De aceea, dacă încercaţi să deschideţi unul dintre
tabele după mutarea bazei de date back-end, veţi obţine un mesaj de
eroare.
Acum vom reface legătura cu tabelele.
4. Creaţi un modul nou şi adăugaţi o funcţie numită
RefreshTableLinks. Introduceţi următoarea secvenţă de cod:
5. Acum deschideţi fereastra de depanare şi apelaţi funcţia în
felul următor:
6. Închideţi fereastra modulului şi încercaţi din nou să
deschideţi un tabel. De data aceasta, nu ar trebui să mai apară un
mesaj de eroare - aţi refăcut legăturile cu tabelele, aşa că
Access poate găsi uşor sursele de date.
Cum funcţionează?
Funcţia parcurge ciclic tabelele şi le modifică proprietatea
Connect. Această proprietate defineşte şirul de conectare pentru un
tabel legat. Apoi, folosim metoda RefreshLink pentru a ne asigura că
legătura este împrospătată. Haideţi să analizăm codul în
detaliu:
Set dbCurrent = CurrentDb()
For Each tblLinked In dbCurrent.TableDefs
Începem prin deschiderea bazei de date curente şi parcurgerea
ciclică a colecţiei TableDefs.
If tblLinked.Connect <> " " Then
tblLinked.Connect = ";DATABASE=" & strDB
Apoi, căutăm un şir nevid în proprietatea Connect. În cazul
tabelelor locale, nu va exista nici o valoare - nu dorim să facem
actualizarea pentru aceste tabele. Dacă există, totuşi, o valoare,
aceasta trebuie să fie actualizată cu numele noii baze de date
(transmis funcţiei prin argumentul strDB). Proprietatea Connect
conţine calea şi numele bazei de date din care sunt legate tabelele.
Ea are următoarea formă:
Ca argument object, folosim tabelul pe care l-am găsit în structura
ciclică, tblLinked. Argumentul databasetype este un şir care
identifică tipul de fişier - pentru Access, acest argument este
lăsat necompletat, însă trebuie să introducem un caracter punct şi
virgulă ca marcaj de rezervare. Dacă doriţi să realizaţi
conectarea la un tabel Paradox, argumentul trebuie să fie "Paradox
5.x" sau unul similar. În fişierul de asistenţă (Help) din Access,
găsiţi o listă completă a identificatorilor - căutaţi subiectul
Connect Property.
În fine, parameters reprezintă calea completă şi numle de fişier
la bazei de date, precedat de expresia DATABASE=, în cazul nostru
"DATABASE=" & strDB.
tblLinked.RefreshLink
End If
Next
Terminăm structura ciclică cu o instrucţiune de împrospătare a
legăturii. Acest lucru este necesar pentru că simpla configurare a
proprietăţii Connect nu determină restabilirea automată a
legăturii. Trebuie să folosim metoda Refresh.
Desigur, puteţi să extindeţi procedura şi să solicitaţi noul
nume al bazei de date (în loc să-l acceptaţi ca parametru). În
acest fel, veţi spori flexibilitatea funcţiei.
Diferenţe între tabelele legate şi cele locale
Tabelele legate au o serie de avantaje faţă de cele locale însă,
ca în orice domeniu, există şi dezavantaje. Iată care sunt acestea:
Deoarece tabelele legate nu fac parte din baza dumneavoastră de
date, iar înregistrările trebuie să fie extrase din alt fişier de
fiecare dată când încercaţi să le accesaţi, apar probleme de
viteză - în special dacă tabelul legat se găseşte pe un alt
calculator din reţea
Tabelele legate trebuie să fie deschise ca seturi de
înregistrări de tip dynaset sau instantaneu (snapshot) şi, din acest
motiv, ele nu acceptă metoda Seek, care poate fi aplicată doar
seturilor de înregistrări de tip tabel.
Trebuie să fiţi atent la asocierea unor tabele stocate în locuri
diferite (de exemplu, unul pe calculatorul local şi unul pe
calculatorul situat la distanţă), pentru că s-ar putea ca tipurile
de câmpuri să nu fie complet compatibile. De exemplu, pot apărea
probleme dacă asociaţi două câmpuri de date, dintre care unul are
formatul US, iar celălalt formatul British.
Trebuie să fiţi atent atunci când asociaţi tabele legate de
mari dimensiuni cu tabele locale mici. Dacă ambele tabele sunt locale,
Access poate optimiza asocierea, însă dacă este legat un tabel mare
de pe un calculator situat la distanţă, toate datele trebuie să fie
trasferate înainte de asocierea efectivă. Şi, desigur, va trebui să
luaţi în calcul supraîncărcarea cauzată de transferul datelor la
executarea interogării.
Cu toate aceste neajunsuri, nu ar trebui să renunţaţi. Soluţia
back-end/front-end este extrem de utilă în activitatea firmelor, în
condiţiile în care o aplicaţie de baze de date este modificată
constant sau este distribuită în etape.
10.7 ODBC
ODBC este abrevierea expresiei Open DataBase Connectivity
(Conectivita-tea bazelor de date deschise), care reprezintă o altă
modalitate de acces la date externe. Bazele de date stochează
informaţiile în diferite formate şi folosesc metode diferite de
acces. Aşa cum aţi văzut deja, puteţi lega la o bază de date
Access tabele din alte tipuri de baze de date. Tendinţa este însă de
a include doar sistemele desktop, cum ar fi dBase şi Paradox.
Pentru a permite tuturor sistemelor de baze de date să schimbe date
în mod liber, trebuie să existe o metodă comună de acces -
utilizarea unor drivere software adecvate, care se interpun între
mecanismul bazei de date şi datele celuilalt sistem. ODBC este o
metodă standard de implementare a acestui tip de conectivitate - un
singur sistem cu o interfaţă larg răspândită, pentru care alţi
creatori de sisteme de baze de date produc propriile lor programe
driver. Microsoft a început procesul de standardizare acum câţiva
ani, însă acesta este controlat în prezent de grupurile
internaţionale de standardizare, astfel că aproape toate tipurile de
baze de date suportă acum ODBC, inclusiv Oracle, IBM DB/2, Ingres şi
Informix. Marele avantaj este că programele pot fi scrise folosind
interfaţa standard ODBC şi vor funcţiona cu orice bază de date
pentru care există drivere disponibile.
Puteţi observa că mecanismul Jet acceptă câteva formate comune de
baze de date desktop direct prin programe driver incluse în Access şi
că ODBC este o entitate separată la "nivel" de driver. În
continuare, gestionarul ODBC poate suporta oricâte baze de date,
fiecare prin propriul său sistem de driver. Majoritatea bazelor de
date importante, cum sunt Oracle, DB2 şi alte sisteme pentru
minicalculatoare şi calculatoare mainframe, suportă ODBC, asigurând
un grad înalt de flexibilitate. Dacă nevoile dumneavoastră se
schimbă, se pot schimba şi bazele de date.
CAP: 11.TRATAREA ERORILOR, DEPANAREA ŞI TESTAREA
Aţi învăţat multe lucruri despre programarea în Access 97,
inclusiv cum puteţi crea aplicaţii sofisticate. Ceea ce nu aţi
învăţat până acum este cum să evitaţi apariţia problemelor şi
cum să le detectaţi atunci când (şi nu dacă) acestea totuşi apar.
Termenul depanare (debug) are sensul de "eliminare a erorilor din".
Nimeni nu poate scrie de la început programe fără erori;
întotdeauna mai există ceva la care nu v-aţi gândit. De aceea, este
bine să ştiţi cum să preveniţi apariţia erorilor şi ce trebuie
să faceţi atunci când acestea apar totuşi în program.
În acest capitol veţi învăţa:
Cum să preveniţi apariţia erorilor
Diferite tipuri de erori
Metode de tratare a erorilor
Cum să folosiţi evenimentele de eroare
11.1 Anticiparea erorilor
Una dintre legile lui Murphy spune: "Dacă întrezăriţi şase
posibilităţi ca un lucru să meargă prost şi le preîntâmpinaţi,
atunci va apărea în mod sigur o a şaptea, la care nu v-ţi gândit".
Alta: "Este imposibil de construit ceva care să reziste la orice
intervenţie neavizată, pentru că prostia are resurse nebănuite".
În ciuda adevărului amar al acestor observaţii, există
posibilitatea planificării (anticipării) erorilor.
Utilizatorilor nu le pasă de dimensiunea codului. Nu îi interesează
nici dacă aţi creat cel mai bun şi mai rapid algoritm de calcul al
constantei Pi (π). Tot ce îşi doresc este ca aplicaţia să arate
bine şi să funcţioneze corect. Detectarea şi eliminarea unei erori
este întotdeauna un proces care consumă mult timp şi, ca urmare,
mult mai scump decât anticiparea erorilor.
11.2 Proiectul
Dacă tocmai aţi întrebat "Ce proiect?", înseamnă că trebuie să
mergeţi direct la închisoare, fără să treceţi prin start şi
fără să încasaţi suma de 200$ (vă amintiţi de Monopoly?).
proiectul este partea cea mai importantă a aplicaţiei - fundaţia pe
baza căreia sunt construite toate celelalte obiecte. Etapa de
proiectare este cea în care stabiliţi exact ce trebuie să facă
aplicaţia . una dintre cele mai frecvente cauze de apariţie a
erorilor o reprezintă modificările. De multe ori, aplicaţiile nu
răspund cerinţelor utilizatorului şi trebuie modificate. Ca urmare,
începeţi să adăugaţi un fragment de cod aici, altul dincolo, iar
erorile îşi fac apariţia. Rezervaţi-vă timpul necesar pentru a
discuta cu utilizatorii şi a afla tot ce doresc aceştia de la
aplicaţie. Şi nu vă miraţi dacă, după mai multe săptămâni de
analiză exhaustivă a cerinţelor, dumneavoastră furnizaţi
aplicaţia "la cheie", iar utilizatorul vă spune: "Este foarte bine,
dar nu mai puteţi adăuga ceva aici…?" Este inevitabil să se
întâmple aşa, pentru că utilizatorii nu sunt foarte siguri de ceea
ce vor până când nu văd ceva concret. Nu vă repeziţi să
rezolvaţi pe loc noile solicitări. În primul rând, analizaţi
problema şi toate implicaţiile pe care le presupune rezolvarea
acesteia. Veţi economisii astfel o mulţime de timp şi efort.
Dacă ţineţi cont de la început de aceste principii, există toate
şansele să realizaţi o aplicaţie care să poată fi modificată
uşor. Această abordare determină şi reducerea numărului de erori.
În continuare, sunt prezentate câteva aspecte generale la care
trebuie să vă gândiţi înainte de a începe programarea
propriu-zisă.
Tabele
Probabil că aţi început să vă plictisiţi de atâtea sfaturi,
însă este bine să planificaţi tabelele. Încercaţi să anticipaţi
câmpurile care ar putea fi necesare, dar la care utilizatorul nu s-a
gândit. De exemplu, s-ar putea ca utilizatorii să solicite doar o
adresă pentru tabelul firmelor, însă cum procedaţi dacă trebuie
să sortaţi firmele după zonă sau după regiunea de vânzare? Aveţi
nevoie de mai multe câmpuri - Oraş, Stat (Judeţ) etc. ne-am
confruntat cu această problemă chiar la începutul cărţii şi am
văzut cum putem împărţi un nume în elementele sale componente.
Interogări
Pentru fiecare tabel, ar trebui să creaţi o interogare care să
afişeze toate câmpurile, în felul următor:
Este de preferat să folosiţi modul de afişare cu asterisc decât
să specificaţi explicit fiecare câmp, pentru că astfel, puteţi să
adăugaţi câmpuri în tabel fără să modificaţi interogarea. Ar
trebui să realizaţi toate formularele şi rapoartele pe baza acestor
interogări, şi nu direct din tabele. Avantajul acestei metode este
că permite modificarea detaliilor din tabele fără a afecta
formularul sau raportul, exceptând, desigur, faptul că noile câmpuri
nu sunt afişate automat în formular sau raport. De exemplu, să
creaţi un pseudonim (alias) pentru această interogare. Nici un
formular bazat pe interogarea respectivă nu va trebui modificat.
Formulare şi rapoarte
Aici, principiul de bază este simplitatea. S-ar putea să vă placă
la nebunie să creaţi formulare sofisticate, însă chiar sunt
necesare? Aplicaţia devine mai performantă? Ajută ele utilizatorii
să folosească aplicaţia? Aceasta ar trebui să vină în sprijinul
utilizatorului şi să îi uşureze munca. Dacă elementul pe care îl
adăugaţi la interfaţă nu are acest rol, mai bine renunţaţi la el.
Se spune că 80% dintre utilizatori folosesc doar 20% din
funcţionalitatea unei aplicaţii. Reţineţi acest aspect şi nu
încărcaţi formularele cu prea multe informaţii. Dacă doriţi un
singur formular, dar aveţi multe date care trebuie afişate,
încercaţi să folosiţi Tab Control, care permite împărţirea
câmpurilor în pagini logice.
Gruparea funcţiilor
Gruparea funcţiilor înseamnă păstrarea împreună a elementelor
similare. Dacă scrieţi mai multe rutine de lucru cu şiruri,
plasaţi-le pe toate într-un singur modul. Astfel, veţi fi sigur că
nu dublaţi nici o procedură, din moment ce toate rutinele de acelaşi
tip sunt grupate. În plus, după ce toate procedurile dintr-un modul
au fost depanate, puteţi importa modulul în alte baze de date în
care aveţi nevoie de rutinele respective, fără să vă mai preocupe
depanarea acestora.
11.3 Tehnici orientate pe obiect pentru prevenirea apariţiei erorilor
Pentru a elimina erorile dintr-o aplicaţie, puteţi folosi o serie de
tehnici orientate pe obiect.
Încapsularea
Încapsularea este numită şi "mascarea datelor", deoarece acest
este, de fapt, rolul său. Ideea este că în loc de variabile publice,
care pot fi accesate din orice funcţia, folosiţi variabile private
şi creaţi proceduri publice pentru a le putea accesa. Această
tehnică vă asigură un control mai mare asupra datelor şi vă
permite să modificaţi implementarea codului şi variabilelor, fără
a afecta alte rutine. Fiecare obiect ar trebui să ştie totul despre
el însuşi şi să nu se piardă în momentul când treceţi într-un
alt mediu de lucru.
Aşa cum s-a arătat şi în capitolul precedent, noile caracteristici
ale modulelor de clasă din Access 97, precum şi procedurile Property
Get şi Let care au fost introduse încă din Access95, asigură un alt
nivel de încapsulare în Access. Acestea permit mascarea datelor
dintr-un formular sau modul (prin declararea lor de tip privat), însă
şi accesul public prin anumite rutine selectate. Astfel, puteţi opera
modificări în codul de bază, în timp ce interfaţa rămâne
neschimbată. De asemenea, aveţi posibilitatea de a adăuga elemente
le interfaţă prin folosirea argumentelor Opţional - avantajul este
că orice nou apel le poate folosi şi, pentru că sunt opţionale,
vechile apeluri vor funcţiona în continuare corect.
Refolosirea
Tehnica de refolosire a modulelor de cod se potriveşte foarte bine cu
încapsularea şi poate fi rezumată prin dictonul: "Nu are rost să
reinventaţi roata". Dacă aveţi un fragment de cod care rezolvă o
anumită problemă, refolosiţi-l. în afară de faptul că
economisiţi un timp preţios, în cazul în care codul respectiv nu
conţine erori, nu mai trebuie să îl depanaţi. Nu ezitaţi să
folosiţi un cod creat de altcineva, dacă ştiţi că funcţionează
corect şi nu încălcaţi legile referitoare la drepturile de autor.
Refolosirea nu este acelaşi lucru cu furtul.
Când creaţi funcţii noi, trebuie să vă gândiţi dacă este cazul
să le implementaţi ca funcţii generice. De exemplu, dacă aveţi o
secvenţă de cod folosită în fiecare formular, puteţi transmite
obiectul formular în procedură cu ajutorul obiectului Me. Astfel,
orice modificare ulterioară a acestei rutine poate fi efectuată
într-un singur loc, şi nu în toate formularele. Desigur, metoda are
dezavantajul că o eroare apărută în procedură va afecta mai multe
zone ale aplicaţiei. Însă în cazul în acre efectuaţi o testare
eficientă şi secţiunile de cod sunt independente, le puteţi
transfera fără teamă în diferite proiecte.
Există mari companii care plătesc programatorilor un bonus la
fiecare refolosire a codului lor. Este o politică bună, care
încurajează eforturile de planificare şi de identificare a altor
domenii în care poate fi folosit programul respectiv.
Comanda Option Explicit
Este o comandă extrem de utilă, care ar trebui să fie implicită
pentru toate modulele dumneavoastră de cod. Puteţi configura această
opţiune în cadrul panoului Module al casetei de dialog Options…,
care poate fi deschisă din meniul Tools:
Această opţiune iniţializează comanda Option Explicit pentru toate
procedurile.
Când această opţiune este validată, în toate modulele noi de cod
va apărea instrucţiunea Option Explicit, motiv pentru care toate
variabilele pe care le folosiţi trebuie să fie declarate explicit.
Aceasta înseamnă că puteţi evita erorile cauzate de tastarea
incorectă, care sunt greu de sesizat. De exemplu, citiţi secvenţa
următoare de cod:
Aţi sesizat greşeala? Numele funcţiei a fost scris greşit în
instrucţiunea de calcul a valorii de răspuns, motiv pentru care
răspunsul corect nu va fi returnat niciodată. Cu toate că această
procedură conţine o singură linie, s-ar putea să treacă mult timp
până la detectarea erorii (până când această funcţie este
apelată în program). Utilizarea instrucţiunii Option Explicit
garantează că acest tip de eroare nu va apărea în aplicaţie. Dacă
instrucţiunea Option Explicit este inclusă în modul, cuvântul
"Circumference" va fi marcat ca o variabilă nedeclarată în momentul
compilării determinându-vă să corectaţi eroarea de tastare.
Verificarea sintaxei
Pagina Module a casetei de dialog Options include şi opţiunea Auto
Syntax Check (Verificare automată a sintaxei). În cazul validării
acestei opţiuni, Access verifică sintaxa codului în timp ce scrieţi
instrucţiunile, dar şi la compilarea codului, şi afişează un mesaj
de eroare în cazul în care găseşte o linie incorectă. Dacă
opţiunea nu este validată, linia incorectă va fi afişată cu altă
culoare (stabilită prin meniul Tools, Options), iar codul va fi
verificat doar la compilare. Opţiunea Auto Syntax Check este
importantă în special dacă nu compilaţi codul înainte a furniza
aplicaţia utilizatorilor, deoarece erorile de sintaxă pot fi generate
la rularea programului.
S-ar putea ca, uneori, această opţiune să vă deranjeze, dar este
preferabil să o selectaţi. Avantajele atârnă mult mai greu în
balanţă decât eventualele dezavantaje. Dacă totuşi nu puteţi să
lucraţi cu această opţiune validată (activată), nu uitaţi ca
după ce terminaţi o sesiune de editare să selectaţi opţiunea
Compile All Modules din meniul Debug (când aveţi deschisă fereastra
unui modul).
Comentarii
Există controverse cu privire la acest subiect. Unii programatori nu
inserează nici un fel de comentarii în cod ("Dacă a fost greu de
scris, ar trebui să fie şi greu de citi"); alţi programatori
comentează fiecare linie în parte. Ambele metode sunt greşite.
Trebuie să găsiţi o cale de mijloc. Iată câteva sugestii utile în
acest sens:
La începutul fiecărei proceduri, introduceţi un comentariu în
care descrieţi rolul acesteia, ce argumente primeşte şi ce fel de
valori returnează. De exemplu:
Comentaţi folosirea variabilelor.
Plasaţi comentariile pe linii separate, cu excepţia situaţiilor
în care descrieţi o variabilă, când comentariul ar trebui să fie
pe aceeaşi linie cu declaraţia.
Comentaţi secţiuni de cod (funcţionalităţi), şi nu linii
individuale.
Nu comentaţi ceea ce este evident. Dacă atribuiţi o valoare unei
variabile, nu este cazul să inseraţi un comentariu de genul:
"Stabileşte valoarea la…". În astfel de situaţii, introduceţi
comentarii doar dacă există un motiv pentru a descrie de ce
efectuaţi operaţia respectivă, cum ar fi atribuirea unei valori
Empty sau Null pe care o veţi folosi ulterior în cod.
Depanaţi codul, nu comentariile. Nu vă bazaţi pe comentarii,
pentru că, de multe ori, acestea nu sunt actualizat o dată cu codul.
Ar trebui să vă asiguraţi că orice modificare pe care o efectuaţi
se reflectă şi în comentariile din cod.
Cel mai important lucru pe care trebuie să îl aveţi în vedere
este consecvenţa. Ca şi în restul aplicaţiei, alegeţi stilul care
vă place şi folosiţi-l doar pe acesta.
11.4 Testarea
Multe companii mari au echipe speciale pentru testarea aplicaţiilor.
Altele preferă să lase utilizatorii să efectueze testarea (pentru
aceasta se lansează de fapt versiunile beta!). oricum, indiferent de
experienţa pe care o aveţi în programare, nu este indicat să
săriţi peste etapa de testare a codului. Fiecare programator trebuie
să îşi asume responsabilitatea pentru codul pe care l-a creat. La
urma urmei, tot dumneavoastră va trebui să eliminaţi erorile
descoperite în aplicaţie.
Testarea poate avea mai multe forme şi este bine să vă rezervaţi
timp pentru fiecare dintre ele. Consideraţi această etapă din
procesul de realizare a aplicaţiei la fel de importantă ca şi
scrierea codului. În continuare, vom analiza diferite faze de testare.
Testarea funcţională
Testarea funcţională constă în a verifica dacă întreaga
aplicaţie, sau o parte a acesteia îndeplineşte funcţia pentru care
a fost scrisă. Există trei căi de a obţine un răspuns şi acestea
ar trebui să fie folosite în ordinea corectă:
Testaţi aplicaţia personal, deoarece sunteţi cel care înţelege
cel mai bine cum ar trebui să funcţioneze.
Transmiteţi aplicaţia la utilizatori. În fond, ei sunt cei care
au stabilit cerinţele.
Transmiteţi aplicaţia (pentru testare), împreună cu
specificaţiile de utilizare, unor persoane neimplicate în proiect.
Nedispunând de alte informaţii în afară de conţinutul
documentaţiei, aceste persoane nu vor avea idei preconcepute. În
plus, nici nu vă vor deranja în cazul în care aplicaţia nu li se
pare completă.
Testarea modului de utilizare
Aceasta este etapa următoare, la care treceţi după ce vă veţi
convinge că aplicaţia răspunde cerinţelor utilizatorilor. Testarea
modului de utilizare se aplică în special porţiunilor vizibile ale
aplicaţiei. Trebuie să apreciaţi dacă interfaţa este uşor de
folosit sau este confuză pentru utilizatori? Respectă convenţiile
uzuale? De fapt, dacă utilizatorilor nu le place cum se prezintă
aplicaţia, nu mai contează cât de bine răspunde aceasta cerinţelor
iniţiale. Deşi dumneavoastră aveţi propriile criterii de apreciere,
al sfârşitul zilei trebuie să realizaţi ceva care să mulţumească
beneficiarul. Veţi lua în calcul şi timpul necesar pentru realizarea
unei anumite operaţii. Dacă o funcţie este executată într-un timp
care depăşeşte limita, va trebui să rescrieţi codul respectiv.
Testarea distructivă
Aceasta este etapa cea mai distractivă. Daţi aplicaţia altei
persoane şi rugaţi-o să o încerce prin orice metode, chiar
neconvenţionale. Dacă testaţi un formular, apelaţi la cineva care
nu a mai lucrat cu formulare, sau nici măcar cu calculatoare. Dacă
testaţi secvenţe de cod., apelaţi la serviciile altui programator.
Acesta va fi fericit să vă purice programul. Şi puteţi fi sigur
că, după ce descoperă câteva erori evidente, de care se bucură ca
un copil, veţi creşte nivelul verificărilor pe cont propriu. Deşi
iniţial s-ar putea să vă simţiţi frustrat, în timp, veţi deveni
un programator mai bun! (Şi veţi avea ocazia să vă răzbunaţi pe
cei care, la rândul lor, vă vor ruga să le testaţi programele).
Întreţinerea
Se spune că un programator îşi petrece 60% din timp cu
întreţinerea programelor vechi (se mai spune şi că 85% dintre
statistici sunt inventate, dar asta este o altă poveste). Când
operaţi modificări în cod, indiferent dacă este vorba despre un
program vechi sau de unul nou, este bine să luaţi în considerare
următoarele aspecte:
Modificarea pe care o efectuaţi va avea impact asupra altor
programatori? Dacă este vorba de o rutină de bibliotecă, discutaţi
cu alte persoane care folosesc rutina respectiv înainte a efectua
modificările. În cazul în care este o eroare de cod şi alţii au
tratat eroare a respectivă, dacă dumneavoastră corectaţi codul,
este posibil ca aplicaţiile lor să nu mai funcţioneze corect.
Concentraţi-vă pe corectarea problemei curente.
Efectuaţi o singură modificare la un moment dat. Imaginaţi-vă
că lucraţi la corectarea ai multor probleme, iar când rulaţi
programul, apar erori noi. Care dintre modificări a generat aceste
erori? Dacă rezolvaţi problemele pe rând şi le testaţi una câte
una, timpul total de întreţinere a aplicaţiei s-ar putea reduce
considerabil.
Nu vă pierdeţi vremea cu "aranjarea" sau îmbunătăţirea
codului decât în cazul în care acesta este principalul motiv pentru
care îl modificaţi.
Sugestiile prezentate mai sus sunt într-adevăr de bun simţ, însă
veţi fi surprins cât de repede uitaţi de ele atunci când sunteţi
concentrat asupra codului.
11. 5 Tipuri de erori
Puteţi (şi ar trebui) să urmaţi toate sugestiile anterioare
referitoare la prevenirea erorilor, însă, din păcate, este foarte
probabil ca în codul dumneavoastră să apară totuşi erori. Acestea
pot fi de mai multe feluri; este important să ştiţi cu ce tip de
eroare aveţi de-a face, pentru a putea alege cea mai bună metodă de
rezolvare. Am arătat în Capitolul 2 care sunt cele trei tipuri de
erori:
Erori de sintaxă
Erori de execuţie
Erori de semantică sau logice
În cele ce urmează, vom analiza fiecare dintre aceste tipuri de erori
şi vom vedea cum le putem corecta.
În această etapă, este important să înţelegeţi deosebirea
dintre erorile obişnuite şi erorile de programare (bugs). O eroare
poate fi un eveniment util, cum sunt erorile de acces la date (Data
Access Errors), care vă permit să rulaţi o secvenţă de cod la
apariţia unei erori în tabel. De exemplu, dacă un tabel nu permite
valori null într-un anumit câmp, ar trebui să afişaţi pe ecran o
casetă de dialog personalizată care să descrie eroarea şi locul în
care utilizatorul poate găsi informaţii de asistenţă în cazul în
care problemele persistă. Este o eroare detectabilă, care poate fi
tratată de programator. O eroare de programare (bug) este o eroare pe
care programatorul nu a prevăzut-o.
Erori de sintaxă
Sunt cele mai simple forme de erori, cauzate, în principal, de
greşelile de tastare. Cei care au depăşit stadiul de folosire a
tastaturii cu două degete, vor face, probabil, mai puţine greşeli,
însă aşa cum am menţionat, există o metodă simplă de a le
descoperi - lăsaţi această sarcină mediului Access. Dacă activaţi
opţiunea de verificare a sintaxei şi vă asiguraţi că toate
variabilele sunt declarate, Access vă va avertiza de fiecare dată
când introduceţi instrucţiuni eronate. Oricum, veţi întâlni şi
cazuri în care construcţia folosită este greşită. Şi acestea sunt
semnalate de Access.
Fig. 11.1
Să presupunem ca aţi tastat instrucţiunile For…Next sau
instrucţiunile For…Each . Access nu a găsit instrucţiunea Each
şi, ca urmare, aşteaptă apariţia unei variabile. Deoarece acesta nu
apare, când apăsaţi tasta Return, linia este evidenţiată, iar pe
ecran este afişat un mesaj de eroare. Puteţi să executaţi clic pe
butonul OK pentru a anula mesajul de avertizare şi să corectaţi
eroarea sau să reveniţi la ea ulterior. Dacă nu rezolvaţi problema,
eroarea va fi semnalată din nou la compilarea modulului.
Mai există un tip de eroare de sintaxă, care nu poate fi descoperit
imediat. Examinaţi figura următoare:
Fig. 11.2
Când executaţi clic pe butonul OK, funcţia CurrentDatabase este
evidenţiată, fie pentru că i-a scris greşit numele (în loc de
CurrentDB), fie pentru că este vorba de o funcţie care nu există sau
care nu poate fi vizualizată. Aceasta se poate întâmpla în cazul
în care creaţi într-un alt modul o procedură de tip Private, în
loc de o procedură de tip Public.
Erori de execuţie
Aşa cum sugerează şi numele lor, erorile de execuţie pot fi
descoperite numai în timpul execuţie programului. O eroare de
execuţie determină oprirea execuţiei codului, cu toate că sintaxa
este corectă, iar codul poate fi compilat. De fapt, succesul
compilării indică doar faptul că instrucţiunile din cod sunt în
ordinea corectă şi că nu s-au folosit funcţii nedefinite. Codul
poate conţine însă multe alte tipuri de erori.
Folosirea extinsă a caracteristicilor Auto Tips (sugestii automate) a
permis evitarea multor erori de execuţie, Access punând la
dispoziţie parametri de proceduri, precum şi proprietăţi şi metode
de obiecte. Totuşi, erorile sunt posibile.
Una dintre cele mai frecvente erori de aceste tip este Type Mismatch
(Nepotrivire de tip). Această eroare apare atunci când atribuiţi o
valoare de un anumit tip unei variabile de tip diferit (incompatibile).
Puteţi să opriţi execuţia programului şi să evidenţiaţi linia
de cod care a generat eroarea, executând clic pe butonul Debug. În
exemplul următor, unei variabile de tip Integer (întreg) i-a fost
atribuită o valoare de tip text - ceea ce, evident, este greşit:
Fig. 11.3
Acest exemplu ilustrează importanţa testării şi a aplicării
consecvente a unei convenţii de nume, deoarece eroarea este dificil de
detectat prin simpla trecere în revistă a codului, chiar şi de
către cei mai experimentaţi programatori.
Erori de semantică
Recent, în presă a apărut un articol despre o mică firmă din
Marea Britanie care a dezvoltat o metodă de scriere a aplicaţiilor
software fără erori. Încă nu s-a dovedit acest lucru, însă, dacă
este adevărat, proprietarii acelei firme se vor îmbogăţi. Bill
Gates, fii pe fază!
Erorile de semantică sunt cel mai dificil de descoperit, deoarece
reprezintă erori în algoritmul logic al programului; chiar şi firma
Microsoft a furnizat produse cu astfel de erori, deci vă daţi seama
cât de importante sunt. Uneori, aceste erori pot produce erori de
execuţie; în acest caz, pe ecran este afişată caseta de dialog
prezentată într-un paragraf anterior, care vă permite să
identificaţi linia de cod ce a generat eroarea. Nu trebuie să
consideraţi această informaţie literă de lege, pentru că este
posibil ca linia care a generat eroarea să nu fie şi cauza problemei.
Este cazul liniilor de cod care conţin mai multe variabile. De
exemplu, dacă una dintre variabile are o valoare incorectă, trebuie
să găsiţi locul în care a fost atribuită valoarea respectivă.
Dacă aţi scris un program modular, bine structurat, s-ar putea să
parcurgeţi trei sau patru funcţii diferite (pentru că o funcţie a
apelat alta, iar aceasta a apelat, la rândul său, altă funcţie),
astfel că trebuie să revedeţi toate procedurile implicate pentru a
descoperi cauza reală a problemei. Într-o altă secţiune din acest
capitol veţi învăţa cum să procedaţi.
Testarea erorilor de semantică este dificil de efectuat, pentru că
trebuie să testaţi ceea ce consideraţi că ar trebui să facă
programul, şi nu ceea ce face efectiv. Totuşi, testarea nu este
imposibilă, deoarece programatorii sunt persoane foarte atente. Un
programator examinează un fragment de cod şi se gândeşte: "OK,
ştiu ce face" şi trece mai departe. Încercaţi să nu vă
însuşiţi acest obicei. În procesele de testare şi depanare,
trebuie să renunţaţi la ideile preconcepute şi să analizaţi
problemele plecând de la zero. Uneori este dificil, dar merită să
încercaţi.
Haideţi să analizăm o defecţiune apărută în timpul execuţiei
unei aplicaţii, care a fost generată o eroare semantică. Acest
exemplu particular demonstrează faptul că un mesaj de eroare poate
să nu indice cauza reală a erorii.
Încercaţi singur - Erori de execuţie şi de semantică
1. Creaţi un nou modul şi adăugaţi procedura următoare:
Această procedură împarte un număr la altul.
2. Compilaţi codul executând clic pe butonul Compile Loaded Modules
şi salvaţi modulul.
3. În continuare, creaţi un formular nou, cu trei controale de text
neasociate şi un buton de comandă. Modificaţi titlurile ca în
figura alăturată şi schimbaţi proprietăţile Name ale casetelor de
text cu txtNumber1, txtNumber2, şi txtResult, iar a butonului de
comandă cu cmdDivide.
4. Acum adăugaţi următoarea linie de cod în procedura evenimentului
On Click pentru butonul de comandă:
5. Comutaţi formularul în modul de afişare Form şi introduceţi
următoarele numere: 4 şi 2
Rezultatul este cel pe care îl aşteptaţi.
6. Acum încercaţi din nou, dar introduceţi valoarea 0 pentru al
doilea număr.
Şi-a făcut apariţia cunoscuta eroare Division by zero (Împărţire
la zero).
7. Executaţi clic pe butonul Debug şi ajungeţi direct la linia de
cod din funcţia DivideNumbers în care a apărut eroarea.
Acum trebuie să decideţi dacă aceasta este linia cu probleme.
Eroarea a fost generată de numărul introdus de utilizator - în mod
evident, trebuie să verificăm dacă numărul introdus în casetă nu
este zero.
Datele au fost transferate din altă procedură, deci unde verificăm
valorile introduse de utilizator (în procedura respectivă sau în
aceasta)? În cazul de faţă, verificarea ar trebui să fie efectuată
în funcţia DivideNumbers. O funcţie trebuie să fie complet
autonomă - dacă fiecare procedură care o apelează verifică
valorile, codul se extinde foarte mult. Prin urmare, este bine să
adăugaţi secvenţa de verificare aici (în funcţie).
8. Adăugaţi următoarele linii de cod în funcţia DivideNumbers. Nu
uitaţi să salvaţi programul după ce efectuaţi modificările.
Public Function DivideNumbers (dblNum1 As Double, dbl1Num2 As Double) _
As Double
DivideNumbers = dblNum1 / dblNum2
End Function
9. Reveniţi în formular şi reluaţi ultimul exemplu (cel cu 0). De
data aceasta, nu mai apare nici un mesaj de eroare. Funcţia nu mai
încearcă să efectueze împărţirea la zero. Oricum probleme nu este
încă rezolvată. Matematicienii care vor analiza programul vor
observa că, deşi nu apare un mesaj de eroare, răspunsul nu este
corect. Rezultatul împărţirii unui număr la 0 nu este 0. Şi încă
nu am analizat toate valorile eronate care ar putea fi introduse de un
utilizator. De exemplu, ce se întâmplă dacă un utilizator introduce
o literă în loc de un număr? Veţi primi un alt mesaj de eroare, de
data aceasta Run-Time Error 13, Type Mismatch. Acest mesaj vă
comunică faptul că tipurile de variabile sunt incompatibile şi că
se încearcă împărţirea printr-o literă sau printr-un şir de
caractere. Trebuie să utilizăm o funcţie care se poate "apăra"
singură, garantând astfel că nu va mai fi generată nici o eroare de
execuţie.
10. Modificaţi funcţia DivideNumbers după cum urmează:
11. În continuare, modificaţi şi procedura de tratare a
evenimentului On Click pentru butonul de comandă:
12. Rulaţi din nou exemplul. De data aceasta, nu ar mai trebui să
apară nici o eroare, indiferent de valorile introduse.
Cum funcţionează?
La terminarea exerciţiului, funcţia acceptă trei argumente. Primele
două sunt deja cunoscute - acestea transmit cele două numere care
trebuie împărţite. Al treilea argument este folosit pentru a stoca
rezultatul împărţirii şi a transfera acest rezultat în formular
după terminarea cu succes a operaţiei. Deoarece numărul de parametri
acceptaţi de funcţie s-a modificat, a fost actualizat corespunzător
şi numărul de parametri cu care este apelată funcţia.
Rezultatul operaţiei este transmis prin variabila booleană
bolErrorCheck. Valoarea acesteia depinde de valoarea returnată de
funcţie. Dacă aceasta este True, este afişat rezultatul calculului;
dacă valoarea este False, pe ecran este afişat mesajul Semantic
Error.
Dacă în operaţia de împărţire apare o eroare, detecatrea
acesteia, care a fost permisă prin activarea opţiunii On Error GoTo
DivideNumbers_Err, redirectează execuţia programului la eticheta
DivideNumbers_Err. În acest punct, valoarea de răspuns a funcţiei
este stabilită la False şi se iese din funcţie prin intermediul
etichetei DivideNumbers_OK. Desigur, dacă operaţia este corectă,
valoarea de răspuns a funcţiei este configurată la True.
În acest fel, sarcina de a verifica valorile introduse cade în
sarcina procedurii apelante. Probabil că nu veţi folosi niciodată o
funcţie doar pentru a împărţi două numere, însă acest exemplu a
arătat care sunt principiile de lucru. Procedura trebuie să fie
capabilă să reacţioneze la datele de intrare incorecte, să nu
ascundă erorile şi să le trateze corespunzător, dacă sunt
disponibile informaţiile referitoare la codul erorii.
Localizarea erorilor
În procesul de detectare a erorilor, trebuie să vă amintiţi că
mediul Access este dirijat de evenimente, iar codul poate fi activat
în cale mai diverse zone. Să luăm ca exemplu deschiderea unui
formular. Ce evenimente credeţi că sunt generate? În total, sunt
cinci evenimente:
Open Load Resize Activate Current
Închiderea unui formular generează trei evenimente:
Unload Deactivate Close
Ca urmare, dacă la deschiderea unui formular apare o problemă,
trebuie să verificaţi toate celelalte evenimente. O metodă de a
verifica toate procedurile dintr-un modul este selectarea opţiunii
Full Module View din pagina Module a ferestrei Options, accesibilă din
meniul Tools.
Acelaşi rezultat se obţine prin executarea unui clic pe butonul
aflat în colţul din stânga-jos al ferestrei modulului.
Aceste acţiuni determină afişarea tuturor procedurilor în
fereastra modulului, separate prin câte o linie orizontală (dacă
este selectată opţiunea Procedure Separator). În cazul în care nu
aţi selectat această opţiune, puteţi trece de la o procedură la
alta folosind tasta Ctrl împreună cu săgeţile de deplasare în sus
şi în jos.
Alte erori
Această secţiune este dedicată tuturor celorlalte cauze care pot
genera o eroare într-un modul VBA. Desigur, numărul erorilor posibile
este direct proporţional cu importanţa aplicaţiei şi invers
proporţional cu timpul necesar pentru depanare!
Una dintre cauzele generatoare de erori poate fi folosirea unor
aplicaţii externe, cum ar fi bibliotecile cu legare dinamică (DLL)
sau controalele personalizate. Dacă programatorii care au scris aceste
aplicaţii le-au testat corespunzător, nu ar trebui să vă
confruntaţi cu defecţiuni de funcţionare, cu mici erori de
programare (bugs).
Există şi alte cauze, cum ar fi memoria insuficientă sau o bază de
date cu o înregistrare alterată, care pot provoca evenimente foarte
neplăcute. Depăşirea memoriei disponibile (care este posibilă chiar
şi sub Windows 95) semnifică faptul că Access nu are suficiente
resurse pentru a afişa toate elementele ecranului.
Cu toate că în astfel de situaţii nu prea aveţi ce să faceţi,
este bine să ştiţi ce tipuri de probleme care pot cauza erori
inexplicabile. Dacă vreţi un răspuns, parcurgeţi următoarele
etape:
Verificaţi în detaliu codul scris de dumneavoastră
Încercaţi să rulaţi aplicaţia pe un alt calculator
Dacă funcţionează corect, analizaţi diferenţele dintre cele
două sisteme de calcul. S-au întâlnit cazuri în acre o astfel de
eroare a fost acuzată de o bibliotecă DLL mai veche, existentă pe
unul dintre calculatoare, celălalt dispunând de o versiune
actualizată a bibliotecii.
Rugaţi pe altcineva să verifice codul sau parcurgeţi-l
dumneavoastră pas cu pas, explicând toate etapele şi procedurile.
Este uimitor cât de repede putem detecta o eroare atunci când
explicăm cuiva fiecare instrucţiune a programului.
Intraţi în panică!
Nu ar trebui să ajungeţi niciodată la ultima etapă, deoarece
puteţi găsi întotdeauna undeva sau la cineva răspunsul la problema
dumneavoastră. Dacă este posibil, folosiţi reţeaua dezvoltatorilor
de produse Microsoft (Microsoft Developer Network) sau alte servicii
on-line, cum sunt Microsoft Network, CompuServe şi Internet. Veţi
intra într-o altă lume de dimensiuni foarte mari, unde toţi (sau
majoritatea) sunt dispuşi să vă ajute.
11.6. Depanarea
După ce aţi aflat care sunt metodele de prevenire a erorilor şi
tipurile de erori care pot apărea, trebuie să ştiţi şi cum să
detectaţi erorile. Pe măsură ce câştigaţi experienţă în
programarea cu VBA, veţi vedea că instinctul vă va ajuta tot mai
mult şi veţi descoperi erorile doar pe baza intuiţiei. Până
atunci, vă vom indica direcţia în care trebuie să căutaţi.
Execuţia programului
Access vă pune la dispoziţie ,mai multe metode care permit navigarea
prin codul aflat în execuţie. Astfel, puteţi să începeţi dintr-un
loc în care să ştiţi că programul funcţionează corect şi să
avansaţi pas cu pas spre zona în care se manifestă eroarea.
Există două locuri în care găsiţi toate facilităţile pentru
depanare.
• Primul este bara cu instrumente Visual Basic
• Al doilea este meniul Debug
Prin combinarea acestora, obţineţi controlul complet asupra modului
de execuţie al programului. În următoarele secţiuni vor fi
explicate şi funcţiile tuturor butoanelor, precum şi utilizările
acestora; apoi vom trece la o aplicaţie practică.
Puncte de întrerupere
Punctele de întrerupere (breakpoints) sunt esenţiale în depanare,
pentru că vă permit să marcaţi liniile la care doriţi ca execuţia
programului să fie oprită temporar. Puteţi stabili punctele de
întrerupere în patru feluri:
Executaţi clic pe butonul Toggle Breakpoint.
Selectaţi opţiunea Toggle Breakpoint din meniul Debug.
Apăsaţi tasta F9.
Executaţi clic pe marginea din stânga a ferestrei modulului, în
dreptul instrucţiunii corespunzătoare.
Toate aceste acţiuni sunt de comutare, adică stabilesc un punct de
întrerupere acolo unde nu există şi elimină unul existent. Nu
există o limită pentru numărul de puncte de întrerupere care pot
exista la un moment dat într-un program.
Când Access întâlneşte o linie cu punct de întrerupere, programul
este oprit, pe ecran este afişată fereastra cu codul rulat în
momentul respectiv, în cadrul căreia este evidenţiată linia cu
punctul de întrerupere. Puteţi folosi fereastra de depanare pentru a
inspecta sau a stabili valorile variabilelor, sau chiar pentru a
schimba codul în fereastra modulului. Programul va rămâne activ
până când îl opriţi.
Execuţia programului poate fi oprită şi apăsând tasta Ctrl+Break
în timpul rulării codului. Această combinaţie de taste are acelaşi
efect cu un punct de întrerupere, permiţîndu-vă inspectarea
variabilelor şi chiar modificarea codului.
Continuarea execuţiei
Puteţi folosi butonul Go/Continue pentru a continua execuţia unui
program oprit temporar. Execuţia va începe de la linia curentă şi
va continua până la introducerea unei date de către utilizator sau
până ce se ajunge la un alt punct de întrerupere.
Stoparea execuţiei
Puteţi acţiona oricând butonul End pentru a opri execuţia
programului.
Reiniţializarea execuţiei
Butonul Reset opreşte execuţia programului şi reiniţializează
toate varibilele. Este cel mai util instrument în cazul în care
folosiţi variabile statice pentru memorarea valorilor. De asemenea,
puteţi folosi acest buton atunci când depanaţi module de formulare
sau de rapoarte. Când execuţia se opreşte, nu puteţi accesa
formularul sau raportul respectiv dacă nu executaţi clic pe butonul
Continue sau Reset.
Execuţia codului pas cu pas
Oprirea într-un punct de întrerupere este foarte utilă, însă cum
procedaţi dacă doriţi să analizaţi liniile de cod în timpul
execuţiei? Stabilirea unui punct de întrerupere la fiecare linie de
cod ar fi un proces foarte laborios; de aceea, a fost introdusă
posibilitatea de execuţie a codului pas cu pas. După oprirea unui
program, puteţi rula o singură instrucţiune la un moment dat, având
astfel posibilitatea să aflaţi care linii de cod sunt corecte şi
care conţine erori. Există mai multe posibilităţi de a executa
codul pas cu pas:
Butonul Step Into execută doar linia pe care este plasat cursorul.
Dacă această linie conţine apelul unei proceduri, va determina
intrarea în codul procedurii şi continuarea execuţiei pas cu pas.
Butonul Step Over execută tot linia pe care este plasat cursorul.
Dacă linia curentă conţine o procedură, codul acesteia este
executat normal - fără a fi parcurs pas cu pas. Ulterior, la
revenirea din procedură, se trece automat la execuţia pas cu pas a
programului.
Butonul Step Out continuă execuţia programului de la procedura
curentă şi opreşte execuţia la linia care urmează după procedura
apelantă. Este un fel de combinaţie între Step Out şi Step Over.
Dacă aveţi nevoie de mai multă flexibilitate, puteţi folosi
opţiunea Run To Cursor din meniul Debug. Plasaţi cursorul pe linia la
care doriţi să se oprească execuţia programului şi apoi selectaţi
Run To Cursor. Toate liniile până la cea cu cursorul vor fi parcurse
normal (nu pas cu pas), ca şi cum pe această linie a fot plasat un
punct de întrerupere temporar.
Avantajul metodei Step Into este că puteţi verifica fiecare linie de
cod din toate procedurile întâlnite în timpul execuţiei. Însă
există şi dezavantajul că este o metodă mare consumatoare de timp,
în special dacă procedurile conţin bucle. Metoda Step Over vă
permite să executaţi rapid procedurile despre care ştiţi că sunt
corecte. Şi, desigur, dacă folosiţi proceduri care au fost deja
testate şi depanate, puteţi trece peste ele pentru a vă concentra
asupra codului nou, unde vă aşteptaţi să apară erori.
Opţiunea Run To Cursor este extrem de utilă în cazul în care codul
conţine bucle (structuri ciclice) pentru că vă permite să săriţi
rapid la instrucţiunea de după buclă, economisind astfel mult timp.
Repetarea execuţiei liniei de cod
Posibilitatea de a repeta execuţia anumitor linii de cod a fost
introdusă încă din Access 95, însă a fost mult simplificată în
Access 97. Acest lucru poate reprezenta un avantaj real în cazul în
care v-aţi oprit la un punct de întrerupere şi observaţi că o
linie de cod care a fost deja executată conţine o eroare. În
această situaţie, puteţi să reveniţi la linia respectivă şi să
repetaţi execuţia codului (după corectarea erorii). În acest scop,
trageţi săgeata de pe marginea ferestrei modului în noua locaţie.
Executaţi clic pe linia la care s-a oprit execuţia codului şi apoi,
ţinând apăsat butonul mouse-ului, trageţi cursorul pe o altă
linie.
Observaţi transformarea cursorului într-o săgeată care indică noua
linie. Când ajungeţi pe linia următoare celei pe care vreţi să
poziţionaţi cursorul, eliberaţi butonul stâng al mouse-ului:
Când continuaţi execuţia programului, acest va fi reluat de la noua
linie de cod. O altă metodă de efectuare a acestei operaţii este să
plasaţi cursorul pe noua linie şi să apăsaţi combinaţia de taste
Ctrl+F9.
Saltul peste liniile de cod
Saltul peste liniile de cod poate fi util, însă presupune multă
atenţie. După plasarea cursorului pe o linie care nu a fost încă
executată, puteţi folosi opţiunea Set Next Statement din meniul
Debug pentru a comunica mediului Access că aceasta este linia pe care
doriţi să o executaţi în continuare. Toate liniile de cod
anterioare sunt ignorate.
Opţiunea Show Next Statement vă va informa ce linie de cod urmează
să fie executată. Este o informaţie utilă în cazul în care aţi
analizat alte proceduri şi aţi pierdut poziţia curentă din
fereastra de cod.
Modificarea codului
Access permite modificarea codului în timp ce execuţia este oprită,
astfel încât dumneavoastră să puteţi corecta eventualele erori
descoperite. Pentru a continua execuţia programului de la linia
corectată, executaţi clic pe butonul Continue. De fapt, chiar dacă
rescrieţi secţiuni întregi de cod, puteţi continua execuţia
programului. Totuşi, Access nu vă va permite să modificaţi o
declaraţie. Procedând astfel, înseamnă că întreaga structură a
codului se modifică (nu numai câteva linii) şi veţi primi un mesaj
prin care sunteţi întrebat dacă doriţi să abandonaţi
modificările sau să reiniţializaţi programul. Selectarea opţiunii
de reiniţializare are acelaşi efect cu executarea unui clic pe
butonul Reset - se opreşte execuţia codului, sunt reiniţializate
toate variabilele, iar punctul următor de execuţie se mută pe prima
linie de cod, pregătind o nouă pornire.
Dacă doriţi să modificaţi anumite variabile, fără să
reiniţializaţi programul, puteţi să ieşiţi din această
procedură, să modificaţi variabilele locale şi apoi să stabiliţi
următoarea instrucţiune pentru ca procedura să poată fi rulată din
nou.
Stiva de apeluri
Când depanaţi programe mari sau complexe, ori programe bine
modularizate, puteţi să pierdeţi punctul curent din program. Dacă
executaţi clic pe butonul Call Stack (Stiva de apeluri), veţi vedea
pe ecran o listă cu procedurile active:
Observaţi că acestea nu sunt procedurile care au fost rulate, ci
procedurile care sunt executate în momentul respectiv. De exemplu,
dacă procedura A apelează procedura B şi B apelează C, iar
dumneavoastră opriţi execuţia programului în C, executând un clic
pe butonul Calls, veţi vedea pe ecran C, B, A, adică procedura
executată în mod curent şi cele care au apelat-o. Dacă aţi
terminat execuţia procedurii C şi apoi aţi continuat execuţia
procedurii B, în fereastra de apeluri vor fi afişate doar B şi A.
Este una dintre situaţiile în care se recomandă folosirea opţiunii
Show Next Statement, pentru că s-ar putea să uitaţi de unde aţi
început analiza procedurilor chiar în mijlocul procesului de
depanare.
Fereastra de depanare (Debug)
Aţi văzut deja mai multe exemple de utilizare a ferestrei de
depanare, unde puteţi introduce comenzi care sunt executate imediat -
în versiunile anterioare de Access, aceasta era numită fereastra
imediată. Oricum, este fereastra folosită cel mai frecvent în
depanare. În cadrul ei, puteţi afişa datele, puteţi executa codul
şi puteţi chiar analiza variabilele.
De asemenea, puteţi folosi fereastra de depanare pentru a schimba
conţinutul variabilelor, astfel încât să corectaţi valorile care
pot genera erori. Dacă bănuiţi că o anumită valoare va determina
apariţia unor probleme în cod, puteţi să modificaţi valoarea
respectivă şi să continuaţi apoi lucrul. Este o metodă foarte
utilă în timpul testării, permiţându-vă să introduceţi valori
eronate în variabile pentru a testa răspunsul procedurilor.
Dacă aţi folosit versiuni anterioare de Access, veţi observa că
fereastra de depanare a fost considerabil modificată; haideţi să
vedem cum arată noua fereastră:
Fig. 11.4
Panoul Locals afişează variabilele şi valorile conţinute de acestea
în cadrul procedurii active la momentul respectiv. Panoul Watch
afişează variabilele pe care doriţi să le urmăriţi în cadrul
execuţiei codului. În dreapta există o casetă de text, care
afişează starea procedurii, şi butonului de construcţie, care
afişează fereastra Call Stack. Panoul de jos, Immediate Pane, a fost
folosit până acum pentru apelurile de proceduri.
Elemente de urmărire
Butonul Instant Watch (Urmărire imediată) vă permite să stabiliţi
un element de urmărire pentru variabile sau expresii. Puteţi folosi
elementele de urmărire şi ca puncte de întrerupere condiţionale.
Dacă specificaţi un element de urmărire (watch) cu opţiunile Break
When Expression Is True (opreşte execuţia când expresia este
adevărată) sau Break When Expression has Changed (opreşte execuţia
la modificarea expresiei), codul va fi oprit la execuţie,
permiţându-vă să analizaţi atât elementul de urmărire, cât şi
valorile variabilelor.
Este o metodă utilă, mai ales când aveţi o variabilă care
provoacă probleme, dar nu ştiţi unde a fost valoarea respectivă.
În acest caz, puteţi să adăugaţi o opţiune de întrerupere pentru
elementul de urmărire, iar execuţia programului va fi oprită imediat
ce valoarea este adevărată sau se modifică. Prin utilizarea acestei
variante de punct de întrerupere, execuţia programului este
încetinită, ceea ce nu reprezintă o problemă la depanare.
Încercaţi singur - Depanarea codului
Pentru acest exemplu, trebuie să deschideţi modulul Chapter 11
Debugging din fişierul Whisky11.mdb în modul de afişare pentru
proiectare (Design). Modulul conţine următoarele trei proceduri:
DisplayWhisky, care afişează toate tipurile de whisky pentru un
nume de regiune.
GetWhisky, care încearcă toate tipurile de whisky pentru o
regiune dintr-o matrice globală.
DisplayWhiskies, care afişează conţinutul matricei globale.
DisplayWhisky acceptă ca intrare o matrice cu nume de regiuni,
astrRegions(), şi apelează funcţia GetWhisky o dată pentru fiecare
regiune din matrice. Apoi apelează procedura DisplayWhiskies, care
afişează în fereastra de depanare valorile existente în matricea
globală. Pentru a găsi toate înregistrările corespunzătoare
regiunii selectate, GetWhisky creează o instrucţiune SQL şi apoi
adaugă fiecare tip de whisky în matricea globală. Există şi un
argument opţional, care permite includerea sau excluderea preţului
produsului după preferinţe.
Vom experimenta fiecare dintre aceste funcţii şi vom vedea cum le
putem depana atunci când descoperim o eroare; în plus, vom analiza
variabilele pe care le conţin. Deoarece veţi controla execuţia
funcţiilor din fereastra de depanare, este necesar să deschideţi şi
această fereastră.
1. În primul rând trebuie să stabiliţi un punct de întrerupere
şi, deoarece doriţi să executaţi codul pas cu pas, să îl plasaţi
pe prima linie executabilă din funcţia DisplayWhisky:
2. Apoi apelaţi procedura din fereastra de depanare:
Ar trebui să observaţi oprirea execuţiei codului. Executaţi clic pe
Debug Window pentru a aduce această fereastră în prim-plan:
3. Haideţi să analizăm în detaliu panoul Locals:
Acest panou afişează toate variabilele care sunt active sau care se
găsesc în domeniu. Prima linie este pentru modul, iar semnul plus
indică posibilitatea expandării pentru a afişa elementele
componente. A doua linie afişează atrRegions, o matrice locală care
nu are încă atribuite valori. A treia linie conţine strRegion, o
variabilă locală cu valoarea Empty, care are valoarea atribuită
automat la crearea variabilelor Variant.
4. Executaţi clic pe semnul plus (sau executaţi dublu-clic pe linie)
pentru a expanda linia Chapter 11 Debugging:
Pe ecran sunt afişate cele două variabile globale, împreună cu
tipurile şi valorile lor. Puteţi vedea că mastrWhiskies este o
matrice de tip typWhisky şi că strSQL este un şir (string).
Expandaţi şi astrRegions pentru a vedea ce conţine.
Deoarece astrRegions este o matrice, pe ecran va fi afişat fiecare
element al matricei, împreună cu valoarea conţinută.
5. Haideţi să încercăm o altă metodă de analiză a variabilelor.
În fereastra de depanare, puteţi introduce un semn de întrebare
urmat de numele variabilei
Pe ecran va fi afişat numele regiunii pe care l-aţi transmis ca prim
argument al procedurii. Puteţi analiza şi variabila strRegion, însă
aceasta nu conţine nimic, pentru că linia nu a fost încă executată
şi, ca urmare, nu a primit nici o valoare.
6. Acum executaţi clic pe butonul Step Into pentru a rula această
linie de cod. Poziţionaţi cursorul pe linia strRegion din buclă,
pentru a vedea o altă metodă de analiză a variabilelor.
Pe ecran apare o casetă explicativă (etichetă ToolTip) în care
este afişată valoarea variabilei.
7. Punctul de întrerupere este în continuare pe linia For Each,
însă linia curentă este următoarea, care apare evidenţiată. Acum,
să vedem ultima metodă de analiză a variabilelor, Quick Watch
(Urmărire rapidă). Poziţionaţi cursorul pe strRegion şi executaţi
clic pe butonul Quick Watch (sau folosiţi combinaţia de taste
Shift+F9):
Prin această metodă, pe ecran este afişată aceeaşi informaţie ca
în panoul Locals, însă într-un format puţin diferit. În plus,
aveţi posibilitatea de a adăuga acest element de urmărire în lista
Watch. Vom arăta imediat cum se procedează, însă deocamdată,
executaţi clic pe butonul Cancel şi ieşiţi din fereastră.
8. Folosiţi butonul Step Into pentru a trece la procedura GetWhiskies
şi executaţi clic pe Debug Window pentru a duce această fereastră
în prim – plan.
Observaţi că variabilele pentru procedura GetWhiskies sunt afişate
acum în fereastra Locals. Argumentele au valori, însă nu şi
variabilele locale, pentru că nu le-am configurat încă.
9. Acum este momentul să analizăm stiva de proceduri, aşa încât
executaţi clic pe butonul Calls pentru a vedea unde ne aflăm.
În fereastră puteţi vedea ordinea în care aţi executat
procedurile. Procedura curentă (activă) este afişată în fruntea
listei, iar procedura pe care aţi apelat-o apare imediat dedesubt.
Prima procedură este la sfârşitul listei. Chiar şi din acest
exemplu simplu, vă puteţi da seama ce se întâmplă în cazul
programelor mari.
10. Să spunem că doriţi să executaţi codul pas cu pas, până la
linia care citeşte următoarea înregistrare din setul de
înregistrări. Plasaţi cursorul pe linia
şi alegeţi Run To Cursor din meniul Debug. Execuţia continuă până
la linia selectată. Acum sunteţi în etapa în care aţi completat
deja un element al matricei, iar execuţia s-a oprit pe linia
selectată de dumneavoastră; treceţi în fereastra de depanare. În
primul rând, expandaţi variabila recR pentru a vedea setul de
înregistrări:
Remarcaţi că sunt disponibile toate proprietăţile pentru seturi de
înregistrări. Unele nu au valori sau nu pot fi aplicate în cazul
acestui tip de set de înregistrări, însă toate au fost afişate
instantaneu. Derulaţi conţinutul ferestrei. Vei vedea colecţiile
setului de înregistrări.
Observaţi că acest set de înregistrări conţine şase câmpuri
care pot fi expandate pentru a analiza detaliile corespunzătoare
fiecăruia. Veţi avea posibilitatea să examinaţi aceste detalii mai
târziu; deocamdată, să continuăm exerciţiul.
11. Derulaţi fereastra până în partea superioară şi expandaţi
Chapter 11 Debugging, apoi mastrWhiskies:
Fiind prima iniţializare a datelor, a fost creat numai primul membru
al matricei, iar cele trei elemente ale acestuia conţin valorile
corecte. Este mult mai simplu decât prin vechea metodă, care
presupunea introducerea fiecărui element în fereastra de depanare
pentru a-i vedea conţinutul.
12. Plasaţi cursorul pe linia recR.Close şi selectaţi opţiunea Run
To Cursor. Execuţia codului va continua până la linia solicitată.
Metoda este utilă mai ales la depanarea unui cod cu structuri ciclice,
când puteţi să plasaţi cursorul pe instrucţiunea de după buclă
şi apoi să săriţi peste bucla respectivă fără să mai stabiliţi
un punct de întrerupere.
13. Executaţi de două ori clic pe butonul Step Into pentru a reveni
la procedura DisplayWhisky, adică la funcţia apelantă. Parcurgeţi
câteva instrucţiuni până când ajungeţi la următoarea linie de
cod din procedura GetWhiskies:
Aţi ajuns din nou la bucla în care este completată matricea
globală. Vreţi să vedeţi numele de whisky fără ca acesta să fie
tipărit în fereastra de depanare şi fără să comutaţi panoul
Locals - astfel că stabiliţi un element de urmărire (watch) pe
această variabilă pentru a o vedea permanent.
14. Evidenţiaţi recR("WhiskyName") şi executaţi clic pe butonul
Quick Watch. Pe ecran este afişată fereastra Quick Watch, care
conţine variabila selectată şi valoarea acesteia la momentul curent.
Acum executaţi clic pe butonul Add. În urma acestei comenzi, treceţi
în panoul Watch
Aici apar aceleaşi informaţii ca în panoul Locals, însă numai
pentru variabilele care vă interesează. Dacă aveţi variabile din
mai multe proceduri, este afişat şi contextul. În acest caz,
contextul este pentru modulul curent.
15. Poziţionaţi ferestrele astfel încât să vedeţi atât variabila
urmărită cât şi codul, apoi parcurgeţi pas cu pas programul până
ajungeţi la instrucţiunea recR.MoveNext. urmăriţi modificarea
valorii variabilei în timpul execuţiei.
16. Puteţi adăuga şi alte elemente de urmărire executând clic cu
butonul drept al mouse-ului în fereastra de urmărire şi selectând
opţiunea Add Watch…Pe ecran apare următoarea casetă de dialog:
17. Acum puteţi alege nu numai ceea ce doriţi să urmăriţi, dar şi
modul în care se face urmărirea. Tipul de urmărire (Watch Type) al
unei expresii de urmărire (Watch Expression) este similar cu cel ape
care tocmai l-aţi văzut: afişează valoarea expresiei pe care o
urmăriţi. Opţiunea Break When Value Is True (Opreşte execuţia
când valoarea este adevărată) va adăuga o expresie de urmărire şi
va opri execuţia programului atunci când valoarea expresiei este
adevărată. Opţiunea Break When Value Changes (Opreşte execuţia la
modificarea valorii) va opri execuţia programului atunci când
valoarea expresiei se modifică. Această metodă poate fi foarte
utilă dacă aveţi o variabilă globală a cărei valoare este
modificată de o altă procedură, dar nu sunteţi sigur unde are loc
modificarea. În acest caz, puteţi să stabiliţi un element de
urmărire şi să rulaţi programul în mod normal; la fiecare
modificare a expresiei, execuţia codului va fi oprită.
18. Haideţi să experimentăm opţiunea Break When Value Is True,
pentru a opri execuţia programului atunci când preţul unei sticle de
whisky depăşeşte 30 de lire.
Executaţi clic pe butonul OK şi observaţi că elementul de urmărire
a fost adăugat în listă:
Valoarea curentă este falsă.
19. Executaţi clic pe butonul Go/Continue şi fereastra Watch va fi
afişată în prim-plan, indicând faptul că valoarea expresiei este
acum adevărată (True):
Programul şi-a continuat execuţia până când a găsit un preţ mai
mare de 30 de lire. Corectitudinea opririi programului poate fi
verificată în fereastra Locals sau în panoul Debug:
20. Să presupunem că preţul nu este corect. Nu puteţi modifica
valoarea în expresia recR("Price") fără a executa o instrucţiune
recR.Edit sau recR.Update, însă puteţi schimba valoarea în matrice.
Introduceţi noua valoare în panoul de depanare şi apăsaţi tasta
Return:
Este o operaţie similară cu configurarea unei variabile în cadrul
codului.
21. Acum acţionaţi butonul Continue pentru a continua execuţia, dar
nu pas cu pas. Procedura va fi finalizată, iar detaliile
corespunzătoare vor fi afişate pe ecran. Dacă derulaţi puţin
conţinutul ferestrei, găsiţi sortimentul Glengoyne, vechi de 12 ani,
adică valoarea pe care tocmai aţi modificat-o.
Observaţi că noul panou Locals oferă un mar avantaj programatorului.
În plus, este util ca instrument de instruire, pentru examinarea
proprietăţilor obiectelor pe măsură ce sunt folosite în program.
Merită să faceţi un efort pentru a învăţa să îl folosiţi,
deoarece pe termen lung, veţi economisi foarte mult timp.
11.7 Utilizarea sistemului de asistenţă (Help)
Executarea programelor pas cu pas vă poate ajuta să descoperiţi
erorile, însă nu cazul să începeţi direct cu această metodă. În
primul rând, ar trebui să consultaţi fişierul de asistenţă
(Help), deoarece conţine o listă cu cele mai frecvente tipuri de
erori şi descrierea cauzelor care le-au generat. În general, casetele
de dialog pentru mesajele de eroare, care apar supărător de des în
procesul de depanare a codului, include un buton Help. Dacă
poziţionaţi cursorul pe un cuvânt cheie din fereastra de cod şi
apăsaţi tasta F1, pe ecran este afişat textul de asistenţă
contextuală pentru cuvântul respectiv. De asemenea, puteţi selecta
opţiunea Contents and Index din meniul Help pentru a găsi informaţii
despre un anumit subiect - desigur, Access acceptă opţiunea Answer
Wizard (în acelaşi meniu), care vă permite să introduceţi
întrebări între-un limbaj natural. În plus, puteţi folosi noul
Office Assistant, care răspunde solicitărilor dumneavoastră:
Executaţi clic pe butonul de căutare (Search), iar Clipit va afişa
pe ecran o listă de subiecte:
Fig.11. 5
Fişierul de asistenţă (Help) este cu adevărat util în situaţiile
în care mesajul de eroare returnat de sistem nu descrie cauza erorii.
Să luăm ca exemplu procedura ErrorHelp:
Această procedură acceptă ca parametru de intrare un şir, care
este folosit pentru a selecta câmpul din dreapta al tabelului
Bottling. Încercaţi să rulaţi procedura cu parametrul următor:
Call ErrorHelp ("DistillationDate")
Şi veţi primi o listă cu toate datele la care au fost distilate
băuturile. Încercaţi şi cu parametrul următor:
Call ErrorHelp ("DateDistilled")
Veţi primi acest mesaj de eroare:
Fig.11.6
Nu vă spune prea mult, nu-i aşa? Executaţi clic pe butonul Help şi
veţi vedea pe ecran o fereastră de asistenţă cu un conţinut mult
mai edificator:
Fig.11.7
Al doilea paragraf este important, indicând faptul că încercaţi să
selectaţi un nume de câmp necunoscut.
Tratarea erorilor
Acum, după ce aţi aflat cum puteţi să preveniţi greşelile şi
cum să le detectaţi pe cele care nu pot fi anticipate, trebuie să
învăţaţi cum să trataţi erorile într-un mod cât mai elegant.
Reţineţi că greşelile şi erorile sunt lucruri diferite. Un proiect
bun, o testare şi o depanare corespunzătoare ar trebui să elimine
toate greşelile din codul dumneavoastră. Însă acesta nu înseamnă
că nu vor apărea erori.
De exemplu, să ne imaginăm că programul pe care l-aţi scris
accesează un anumit fişier de pe disc - să presupunem că este vorba
de un fişier legat. Ştiţi că în cod nu există greşeli, aşa
încât va accesa întotdeauna corect fişierul respectiv şi va
prelucra datele fără nici o problemă. Însă erori pot apărea în
continuare - dacă cineva mută fişierul în altă locaţie pe disc
sau îl şterge, veţi primi un mesaj de eroare.
Există situaţii în care doriţi să ignoraţi o anumită eroare sau
să declanşaţi o altă acţiune decât cea prevăzută de Access 97
pentru eroarea respectivă. În acest caz, este necesar să
împiedicaţi mediul Access să oprească execuţia codului şi să
afişeze mesajul standard de eroare - trebuie să trataţi personal
erorile, pe măsură ce apar.
Erori în Visual Basic
Probabil aţi întâlnit secvenţe de cod pentru tratarea erorilor,
în special dacă aţi folosit la crearea formularelor programul
asistent (wizard) Command Button. Dacă nu includeţi o rutină proprie
de tratare a erorilor, Access foloseşte o rutină prestabilită, care
afişează un mesaj de eroare şi opreşte execuţia codului. Prin
introducerea instrucţiunii On Error, comunicaţi mediului Access că
veţi folosi o rutină proprie pentru afişarea erorilor. De exemplu,
citiţi următoarea secvenţă de cod:
Această este schema recomandată pentru majoritatea rutinelor.
Instrucţiunea On Error specifică o etichetă la care trece automat
execuţia codului în cazul apariţiei unei erori. Etichetele sunt
simple marcaje existente în cod şi respectă aceleaşi convenţii de
nume ca şi variabilele, exceptând faptul că la sfârşit au semnul
două puncte (:). Prin convenţie, pentru numele etichetelor de erori
folosiţi numele procedurii, la care adăugaţi _Err.
Prin comanda Resume, comunicaţi mediului Access că tratarea erorilor
s-a terminat şi că ar trebui să continue execuţia din rutina
principală. După procesarea codului pentru rutina de eroare,
efectuaţi una dintre acţiunile următoare:
Încercaţi din nou instrucţiunea care a produs eroarea, folosind
comanda Resume. Aceasta comunică mediului Access că trebuie să
revină la instrucţiunea care a cauzat eroarea şi să o ruleze din
nou. Folosiţi această metodă numai dacă sunteţi sigur că eroarea
nu se va produce în mod repetat. Comanda Resume este utilizată de
obicei împreună cu o casetă de mesaj, în care utilizatorul este
întrebat dacă doreşte să repete o anumită acţiune.
Dacă eroarea poate fi tratată fără oprirea execuţiei,
continuaţi cu linia următoare procedurii principale. În acest caz,
folosiţi comanda Resume Next; procesarea rutinei continuă de la linia
care urmează celei în care a apărut eroarea. Această metodă ar
trebuie folosită numai dacă eroarea nu va acuza probleme ulterioare
în aplicaţie.
Dacă procesarea rutinei nu mai poate continua, ieşiţi din
procedură. În acest caz, ar trebui să folosiţi comanda Resume
ErrorHandling_Exit pentru a comunica rutinei să treacă la eticheta de
ieşire.
Dacă eroarea a fost atât de gravă încât a oprit execuţia
întregului program, ieşiţi din program folosind comanda End.
Acum puteţi să începeţi scrierea propriei dumneavoastră proceduri
de tratare a erorilor. Vom folosi un exemplu simplu, cu o casetă de
intrare în care se cere utilizatorului să introducă un număr şi
apoi se împarte valoarea 10 la numărul respectiv.
Încercaţi singur - Crearea unei proceduri de tratare a erorilor
1. Creaţi următoarea subrutină ErrorHandling:
Fig.11.8
2. Rulaţi subrutina în fereastra de depanare. Procedura afişează pe
ecran un mesaj în care se cere introducerea unui număr. Apoi atribuie
variabilei dblResult valoarea obţinută împărţind 10 la numărul
introdus de utilizator şi afişează rezultatul. Introduceţi câteva
numere pentru a testa subrutina.
Fig.11.9
Fig.11.10
3. Introduceţi cifra 0 - veţi vedea mesajul de eroare Divide By Zero
(Împărţire la zero). Apoi lăsaţi caseta de intrare necompletată -
va fi afişat mesajul de eroare Type mismatch.
Fig.11.11
Eroarea Type mismatch apare din cauză că este returnat un şir -
funcţia InputBox returnează un şir vid (empty) dacă nu introduceţi
nici o valoare în casetă. Când Access încearcă să împartă 10 la
acest şir, realizează că tipurile de variabile sunt incompatibile.
Avem nevoie de o rutină de tratare a erorii.
4. Modificaţi codul ca mai jos şi mai încerca o dată:
Într-un exerciţiu anterior, am filtrat erorile cu ajutorul unor
variabile booleene, însă nu am făcut deosebire între tipurile de
erori, numindu-le pe toate erori semantice. Această rutină de tratare
a erorilor afişează mesajul de eroare şi numărul erorii şi apoi
face saltul la instrucţiunea de ieşire. În anumite circumstanţe,
este o metodă preferabilă celei care afişează mesajul de eroare
prestabilit, pentru că vă permite editarea textului mesajului. Acum,
dorim să detectăm două erori distincte şi să declanşăm în
fiecare caz o acţiune specifică.
Obiectul Err a fost introdus în Access 95. Dacă doriţi, puteţi
continua să folosiţi Error$ şi Err pentru descrierea şi numărul
erorii, însă noul obiect conţine mai multe informaţii şi este mult
mai clar. Ar fi bine să folosiţi obiectul Err în toate programele pe
care le scrieţi de acum înainte.
5. Modificaţi din nou codul de tratare a erorilor, astfel încât să
fie ceva mai "inteligent" decât înainte:
6. Încercaţi să introduceţi 0 sau o literă şi vedeţi ce se
întâmplă. Dacă doriţi să ieşiţi din această procedură,
introduceţi un număr diferit de 0.
Cum funcţionează?
În loc să lăsaţi mediul Access să afişeze meniul standard de
eroare, puteţi să specificaţi mult mai clar acţiunea care va avea
loc.
Select Case Err.Number
Prima instrucţiune verifică dacă Err.Number conţine numărul de
eroare.
Case 13 ' Type mismatch - empty entry (Incompatibilitate - sir vid)
Resume
Eroarea indică o nepotrivire a tipurilor de variabile: fie caseta de
intrare a rămas necompletată, fie a fost introdus un şir de
caractere ce nu reprezintă un număr. În acest caz, caseta este
afişată din nou pe ecran - instrucţiunea Resume cere revenirea la
linia care a cauzat eroarea. Dacă încercaţi să apăsaţi butonul
Escape, vă veţi da seama că nu are nici un efect. Acelaşi lucru
este valabil şi pentru butonul Cancel din caseta de intrare. Funcţia
InputBox returnează un şir vid dacă nu se introduce nici o valoare,
aşa încât este generată aceeaşi eroare. Din acest motiv, nu se
recomandă să folosiţi rezultatele unei funcţii cum este InputBox
direct în expresii numerice, fără o verificare preliminară a
conţinutului acestora.
Case 11 ' Divide by zero (Impartire la zero)
dblResult = 0
Resume Next
Eroarea 11 apare dacă în caseta de intrare a fost introdusă
valoarea 0, situaţie în care putem ignora pur şi simplu eroarea.
Atribuiţi rezultatului valoarea 0 şi introduceţi instrucţiunea
Resume Next, care cere continuarea execuţiei programului de la linia
aflată imediat după cea care a generat eroarea. Aceasta este linia ce
conţine MsgBox.
Case Else
MsgBox Err.Description & " - " & Err.Number
Resume ErrorHandling_Exit
Chiar dacă nu ne aşteptăm să apară alte tipuri de erori, este
bine să avem în vedere şi tratarea acestora. În astfel de cazuri,
pe ecran este afişat un mesaj şi se iese din procedură.
Adevărata problemă din acest exemplu este faptul că va fi
returnată valoarea 0 pentru o eroare de împărţire la 0, fără a fi
afişat un mesaj de eroare. Amintiţi-vă că am menţionat această
problemă ceva mai devreme în cadrul capitolului de faţă. Ar trebui
să modificaţi secvenţa de cod astfel încât toate erorile să fie
returnate, sau măcar semnalate prin afişarea unor mesaje pe ecran,
deoarece forma actuală este evident greşită şi poate indica o
eroare anterioară de program.
Cu toate că este un exemplu foarte simplu, veţi vedea cât de uşor
poate fi personalizată rutina de tratare a erorilor, conferindu-i un
grad mai mare de flexibilitate.
Utilizarea instrucţiunilor Exit Function şi Exit Sub în rutinele de
tratare a erorilor
În rutinele de tratare a erorilor, puteţi include alte două
instrucţiuni Access - Exit Function şi Exit Sub. Acestea vă permit
să renunţaţi la folosirea etichetelor, astfel că rutinele devin mai
uşor de citit şi de depanat. De exemplu, am putea rescrie funcţia
ErrorHandling astfel:
Public Sub ErrorHandling()
Dim dblResult As Double
On Error GoTo ErrorHandling_Err
dblResult = 10 / InputBox("Introduceti un numar:")
MsgBox "rezultatul este " & str$(dblResult)
ErrorHandling_Err:
Select Case Err.Number
Case 11 ' Divide by zero (Impartire la zero)
dblResult = 0
Resume Next
Case Else
MsgBox Err.Description & " - " & Err.Number
End Select
End Sub
Această metodă permite şi folosirea butonului Cancel, care, în
versiunea anterioară a rutinei, nu a funcţionat. Când este detectat
numărul de eroare 13, folosim instrucţiunea Exit Sub pentru a
determina ieşirea din subrutină. Deşi pare o procedură simplă,
deoarece sunt mai puţine etichete în cod, vă recomand prima metodă
dintr-un motiv foarte important - există un singur punct de ieşire
din procedură. Aceasta înseamnă că puteţi introduce instrucţiuni
de cod înainte de procedura de ieşire, ştiind sigur că acestea vor
fi rulate, ceea ce nu se întâmplă în cazul inserării
instrucţiunilor Exit Sub în diverse porţiuni ale codului.
Erori în formulare şi rapoarte
În Access, există erori care sunt asociate cu formularele -
formularele au un eveniment Error asociat. În mod normal, acesta este
gol (nu are cod scris) şi, în cazul apariţiei erorii este executată
rutina prestabilită; însă, la fel ca în procedurile normale,
puteţi adăuga propria dumneavoastră secvenţă de cod. Evenimentul
de eroare preia două argumente:
Fig.11.12
Primul argument, DataErr, reprezintă numărul erorii şi este folosit
în acelaşi fel ca Err în exemplul anterior.
Al doilea argument, Response, indică dacă doriţi sau nu ca mesajul
de eroare prestabilit să fie afişat pe ecran. Dacă atribuiţi
acestui argument valoarea acDataErrContinue, Access va ignora eroarea
şi va continua execuţia codului - ceea ce vă permite să afişaţi
pe ecran propriul dumneavoastră mesaj de eroare. Dacă atribuiţi
argumentului valoarea implicită, acDataErrDisplay, pe ecran este
afişat mesajul prestabilit pentru eroarea respectivă. Haideţi să
vedem cum a fost implementat acest procedeu în baza de date şi să
schimbăm mesajul afişat pe ecran la apariţia unei anumite erori.
Erori DAO
Aşa cum am arătat în capitolele anterioare, colecţia Errors (care
a fost introdusă în versiunea Access95) conţine toate erorile
referitoare la obiectele de acces la date. Dacă bănuiţi că eroarea
provine de la un obiect de acces la date, verificaţi mesajele de
eroare din toată colecţia, dar şi obiectul eroare.
Erori definite de utilizator
S-au spus multe lucruri despre erorile din Access, însă puteţi
defini propriile dumneavoastră erori. Este o metodă foarte utilă,
pentru că permite crearea unei erori specifice într-o procedură
atunci când se întâmplă un anumit lucru, apoi o tratează la fel ca
pe erorile interne. De asemenea, permite declanşarea rutinelor pentru
erori prestabilite, chiar fără apariţia efectivă a unei erori.
Prin utilizarea metodei Raise a obiectului Err, sunt generate erori
definite de utilizator. Obiectul va raporta eroarea în modul
obişnuit. Diferenţa este că dumneavoastră trebuie furnizaţi
numărul de eroare. Acesta poate fi un număr de eroare standard din
VBA, cum ar fi 13 pentru Type Mismatch (Incompatibilitatea tipurilor de
date), sau un număr care nu face parte din gama celor utilizate în
VBA. Numărul maxim este 65535, însă VBA nu foloseşte valori de
peste 32000, ceea ce înseamnă că aveţi de unde alege.
Încercaţi singur - Definirea unor erori proprii
1. Deschideţi procedura ErrorHandling pe care aţi analizat-o ceva mai
devreme şi modificaţi codul astfel:
Public Sub ErrorHandling()
Dim dblResult As Double
MsgBox "rezultatul este " & str$(dblResult)
ErrorHandling_Exit:
Exit Sub
ErrorHandling_Err:
Select Case Err.Number
Case 13 ' Type mismatch - empty entry
Resume
Case 11 ' Divide by zero
dblResult = 0
Resume Next
Case Else
MsgBox Err.Description & " - " & Err.Number
Resume ErrorHandling_Exit
End Select
End Sub
Acum, dacă valoarea de intrare nu este numerică, rutina de tratare a
erorii este apelată cu numărul de eroare 32000. Pentru a preveni
apariţia unor conflicte cu mediul Access, folosiţi întotdeauna în
cod numere mai mari de 32000.
2. Modificaţi rutina de tratare a erorilor, adăugând o secţiune
suplimentară:
3. Lansaţi în execuţie procedura şi introduceţi în caseta de
intrare o literă. Noua rutină de tratare a erorilor procesează
eroarea cu numărul 32000 la fel ca pe celelalte. Ca urmare, funcţia
va afişa pe ecran propriul dumneavoastră mesaj.
Dacă nu trataţi explicit erorile definite de utilizator şi folosiţi
o simplă casetă de mesaj pentru a afişa textul standard, veţi
obţine mesajul de eroare Application-defined or object-defined error.
De exemplu, în procedura anterioară ar fi afişat mesajul
Application-defined or object-defined error - 32000.
Stiva de erori
Deoarece Access este un mediu dirijat de evenimente, procesează
periodic mici secvenţe de cod care corespund evenimentelor. Pe
măsură ce este introdusă fiecare procedură, rutina de tratare a
erorilor este reiniţializată şi orice eroare este tratată
independent. Access nu trebuie să păstreze o stivă de erori,
răspunzându-le pe măsură ce apar. Deşi acest mod de lucru este
destul de simplu, trebuie să fiţi atent unde anume caută Access
codul de tratare a erorilor.
La apariţia unei erori, Access parcurge în sens invers procedura
activă curentă în căutarea unei rutine de tratare a erorilor şi o
execută pe prima pe care o găseşte. Dacă nu găseşte nici una,
apelează rutina implicită de tratare a erorilor.
De exemplu, să presupunem că avem trei proceduri: A, B şi C. A
apelează B şi B, la rândul său apelează C. Dacă C generează o
eroare, Access va reveni la B şi apoi la A în căutarea unei rutine
de tratare a erorii. Dacă nu găseşte nimic în B sau A, apelează
rutina prestabilită.
Reţineţi că acest mod de lucru nu afectează în nici un fel fluxul
de control al programului în care procedura C este încă activă.
Săgeţile de revenire în procedurile apelante indică unde caută
Access o rutină de tratare a erorii.
Să presupunem acum că v-aţi hotărât să creaţi propria
dumneavoastră rutină de tratare a erorii. Veţi plasa câte o rutină
în A, B şi C sau vă veţi baza pe facilitatea de backtracking
(revenire) şi veţi plasa rutina doar în procedura A? Dacă aveţi
de-a face cu erori similare, este foarte normal să creaţi o singură
rutină şi, datorită capacităţii de backtracking, să o plasaţi la
cel mai înalt nivel.
De exemplu, puteţi avea următorul cod de tratare a erorilor doar în
procedura A:
Deşi codul este foarte simplu, există o problemă serioasă, care
poate schimba fluxul programului. Nici Resume şi nici Resume Next nu
vor continua execuţia cu procedura C, aşa cum aţi putea crede, cu
linia curentă din procedura care tratează eroarea.
Deci Resume va relua execuţia de la linia care a apelat procedura B -
aceasta este linia curentă în procedura A.
În mod similar, Resume Next va continua execuţia cu linia care
urmează după apelul procedurii B. Observaţi că nici una dintre
metode nu va returna execuţia în procedura C. Haideţi să examinăm
puţin diagrama următoare pentru a vedea ce se întâmplă:
Diagrama ilustrează riscul utilizării unei singure rutine pentru
tratarea erorilor. Totuşi, există şi situaţii în care această
metodă este utilă - trebuie să cunoaşteţi aceste aspecte şi să
faceţi o planificare (proiectare) corespunzătoare. De exemplu,
puteţi să plasaţi o rutină de plasare a erorilor în A şi alta în
C. Rutina din C tratează erorile generate în procedura respectiv (C),
permiţând continuarea execuţiei programului în condiţii normale,
în timp ce rutina din A poate fi folosită pentru erorile din A şi B.
De asemenea, puteţi folosi instrucţiunea Err.Raise în procedura C
pentru a forţa Access să mute rutina de tratare a erorilor pe nivelul
imediat superior. Iată un exemplu în acest sens:
Această procedură are o rutină care verifică numărul erorii.
Dacă este vorba de eroarea 13 (Type Mismatch), mesajul de eroare este
afişat aici, dar orice altă eroare este transmisă înapoi pe lanţul
de apeluri. Pentru aceasta se foloseşte metoda Raise obiectului Err,
care are ca efect regenerarea erorii. Cele trei argumente sunt numărul
de eroare, sursa (în acest caz, procedura "c") şi descrierea. Codul
propriu-zis este format doar din două linii, ambele fiind generatoare
de erori. Prima atribuie unei variabile întregi o valoare foarte mare,
care va acuza o depăşire (overflow) - nu este eroarea 13, deci vom
genera eroarea din nou. A doua linie este eroarea 13, care poate fi
tratată aici. Oricum, în acest exemplu aţi putea comenta faptul că
se atribuie o valoare mare variabilei înainte de generarea erorii,
deoarece cele două evenimente nu pot avea loc simultan. Haideţi să
vedem ce conţinut ar avea o posibilă procedură apelantă:
Această procedură nu conţine decât apelul procedurii c şi
generează propria sa eroare - o depăşire. Deoarece nu are o rutină
proprie de tratare a eroii, Access va căuta înapoi în lanţul de
apeluri pentru a găsi o rutină corespunzătoare; în exemplul nostru,
această rutină se găseşte în procedura a:
Această procedură conţine o rutină de tratare a erorilor, care
afişează sursa erorii, precum şi numărul şi descrierea acesteia.
Să facem o recapitulare a procedurilor:
a apelează b, care apelează c.
c are propria sa rutină de tratare a erorilor, dar se ocupă doar
de eroarea 13 - toate celelalte sunt retrimise procedurii b.
b nu are o rutină proprie, deci transmite eroarea înapoi la a.
Rutina de tratare a erorilor din a afişează pe ecran mesajul de
eroare.
Acest exemplu demonstrează că puteţi trata anumite erori local,
însă trebuie să aveţi şi o procedură generală, care să se ocupe
de celelalte erori posibile. Proprietatea Source a obiectului Err vă
permite să identificaţi locul unde a fost generată eroarea.
11.7 Depanarea codului de depanare
Uneori, introduceţi în cod rutine de tratare a erorilor, dar chiar
acestea sunt generatoare de erori. În astfel de cazuri, deschideţi
meniul Tools, alegeţi Options şi apoi selectaţi panoul Advanced. În
grupul Coding Options găsiţi opţiunea Break on All Errors (Opreşte
execuţia la orice eroare).
Dacă activaţi această opţiune, Access va ignora rutinele de
tratare a erorilor scrise de dumneavoastră şi le va folosi
întotdeauna pe cele prestabilite. Astfel, puteţi să scrieţi
rutinele de tratare a erorilor chiar la crearea aplicaţiei, însă
aveţi posibilitatea de a le dezactiva în etapa de depanare.
Controlul de versiune
Probabil vă veţi întreba ce caută o secţiune dedicată
controlului de versiune într-o carte despre VBA, mai ales în
secţiunea referitoare la depanare şi testare. Unii dintre
dumneavoastră se vor întreba ce este controlul de versiune. Pentru
cei care nu ştiu, controlul de versiune reprezintă capacitatea de a
marca aplicaţiile modificate ca versiuni distincte. Astfel, aveţi
posibilitatea de a păstra un istoric al modificărilor, fiecare cu un
număr de versiune, de a analiza diferenţele dintre versiunile
succesive, şi chiar de a anula modificările.
Vă veţi întreba la ce vă folosesc toate acestea. Ei bine, acest
control este foarte important. Ca dezvoltator de aplicaţii, trebuie
să efectuaţi deseori modificări în cod: corectarea unor erori de
programare, îmbunătăţiri, şi chiar încercări de genul "să vedem
dacă merge aşa". În trecut, nu exista nici o posibilitate de
identificare a modificărilor, în afară de comentarii, care nu
oferă, totuşi, siguranţa necesară. După apariţia controlului de
versiune, lucrurile au devenit mult mai simple. Poate că am exagerat
puţin, însă am vrut să vă daţi seama ce reprezintă controlul de
versiune şi de ce vorbim despre el în prezentul capitol.
Dacă nu v-am convins încă, urmăriţi raţionamentul următor. Să
ne imaginăm o situaţie de lucru obişnuit. Aţi realizat o aplicaţie
de baze de date care a fost bine primită de utilizatori. Totuşi, în
cadrul procesului de modernizare, trebuie să mai parcurgeţi trei sau
patru faze de lucru şi să corectaţi erorile de programare. Cum
procedaţi? Poate ar fi bine să faceţi câte o copie a bazei de date
pentru fiecare fază în parte. Sau poate că trebuie să scrieţi
codul cu funcţionalitatea corect pentru fiecare fază. Ce faceţi cu
erorile de programate? Cum separaţi o corectură de alta? Şi ce se va
întâmpla dacă implementaţi o corectură, dar apoi sunteţi nevoit
să o ştergeţi? Vă puteţi aminti cu exactitate ce aţi modificat?
Sunt locuri unde aceste evenimente au loc zilnic (nu numai în
programare) şi se aplică nu doar pentru departamentele IT, ci şi
pentru programatori individuali.
Una dintre cele mai solicitate facilităţi pentru noua versiune de
Access a fost Version Control (controlul de versiune). Mulţi
utilizatori au aşteptat-o încă de la Access 95, însă nu au
beneficiat de ea. Acum, în sfârşit, această facilitate este
disponibilă.
Haideţi să aruncăm o privire asupra noilor caracteristici de control
de versiune din Access97 şi să vedem cum vă pot ajuta acestea în
activitatea de programare.
Controlul de versiune în Access 97
Voi începe prin a spune că acest control de versiune nu este o
caracteristică automată în Access, şi nici o facilitate de care
beneficiaţi gratuit. Pentru a putea folosi controlul de versiune,
aveţi nevoie de produsele software Office Developer Edition Tools şi
Microsoft Visual SourceSafe.
Visual SouceSafe este produsul care realizează efectiv controlul
de versiune. A fost lansat pe piaţă de câţiva ani şi este folosit
în special de programatorii în Visual Basic.
Office Developer Edition Tools vă oferă, printre multe alte
instrumente, programul de completare care conectează Access la Visual
SourceSafe.
Ambele produse sunt componente suplimentare, pe care trebuie să le
cumpăraţi, însă puteţi să le consideraţi o investiţie. Vă vor
ajuta să economisiţi mult timp. Garantat.
Visual SourceSafe
Visual SourceSafe efectuează controlul de versiune pentru orice tip de
fişier: fişiere Visual Basic, documente, fişiere binare etc. este un
produs orientat pe proiect şi permite organizarea şi partajarea
codului, ca şi controlul asupra editării. În figura următoare este
prezentat ecranul principal:
Prima observaţie este asemănarea evidentă cu Windows Explorer. În
panoul din stânga puteţi vedea o listă de proiecte. $/ reprezintă
directorul rădăcină, la fel ca C:\ pentru unitatea de disc. Sub
directorul rădăcină se află o listă de proiecte care, la rândul
lor, conţin subproiecte. Observaţi că aici apare cartea de faţă,
incluzând baza de date, documentele Word şi imaginile grafice. Panoul
din dreapta afişează lista de fişiere asociate unui proiect, numele
de utilizator şi data ultimei modificări.
Deci ce face Visual SourceSafe? Gândiţi-vă la acest program ca la un
bibliotecar. Puteţi să căutaţi cărţile pe care le are, să
verificaţi dacă numele dumneavoastră este scris pe ele, iar în
cazul în care aţi efectuat modificări, le puteţi anula. Observaţi
în figura de mai sus că am găsit două fişiere modificate. Fiecare
modificare pe care o efectuaţi asupra unui fişier este adăugată ca
o versiune distinctă.
De exemplu, în figura anterioară există trei versiuni ale
fişierului ReadMe.txt. Puteţi vedea cine le-a căutat şi când. Una
dintre cele mai importante facilităţi ale programului Visual
SourceSafe este că vă permite să vizualizaţi modificările care au
apărut de la o versiune la alta.
Visual SourceSafe evidenţiază liniile şterse, liniile modificate şi
liniile nou introduse, astfel încât dumneavoastră puteţi vedea ce
s-a modificat. Acest lucru este foarte util în situaţiile în care nu
vă amintiţi exact ce aţi modificat, sau dacă lucraţi în echipă
şi doriţi să vedeţi ce modificări au efectuat colegii
dumneavoastră.
Programul de completare Access SourceSafe
Componenta Visual SourceSafe pentru Access este furnizată ca un
program de completare, care este adăugat la meniul Tools.
Când adăugaţi o bază de date în Visual SourceSafe, fiecare
element al acesteia este blocat, nepermiţând nici o modificare.
În imaginea alăturată, puteţi vedea cum s-a modificat pictograma,
indicând faptul că elementul este blocat. Pentru a anula blocarea
unui fişier, apăsaţi butonul drept al mouse-ului şi selectaţi
opţiunea Check Out din meniu.
În acest fel, veţi introduce în baza de date o copie editabilă a
obiectului. Din nou, pictograma asociată obiectului se modifică,
astfel încât să puteţi vedea starea în care se găseşte acesta.
Acum puteţi edita obiectul şi, după ce aţi terminat, marcaţi-l
din nou, ştiind sigur că tot ce aţi modificat se păstrează separat
de orice altă modificare. De asemenea, puteţi folosi Visual
SourceSafe pentru a introduce observaţii referitoare la versiune şi o
listă de modificări.
Cu aceasta, am încheiat scruta prezentare a produsului Visual
SourceSafe şi a modului în care poate fi folosit în Access; deşi nu
este o componentă standard, merită să o achiziţionaţi. Odată, am
pierdut trei zile căutând o greşeală de programare într-un proiect
de dimensiuni mari. Dacă aş fi avut la dispoziţie controlul de
versiune, probabil că aş fi descoperit eroarea în câteva ore.
Posibilitatea de a controla modificările reprezintă o latură
importantă a dezvoltării de aplicaţii, aşa încât lăsaţi puţin
cartea şi mergeţi repede să cumpăraţi produsul prezentat.
11.9 Rezumat
Chiar dacă aţi citi printre rânduri, v-aţi dat seama că acest
capitol se referă la planificare. Detectarea şi rezolvarea
problemelor software consumă multe resurse, dar printr-un mic efort de
planificare, puteţi economisi mult timp.
La fel de importantă ca planificarea aplicaţiei este şi anticiparea
cerinţelor şi nevoilor utilizatorului. Încercaţi să vă puneţi
în locul acestuia, să vă imaginaţi ce va face, astfel încât să
construiţi un program cât mai simplu de utilizat. Nu ar trebui să
puneţi niciodată un utilizator în situaţia de a primi un mesaj de
eroare care îi creează impresia că a greşit ceva, deoarece poate
deveni reticent faţă de software, ajungând chiar să refuze
utilizarea programului. Alan Cooper, inventatorul limbajului Visual
Basic, spunea: "Petrecem atâta timp lucrând cu calculatoarele,
încât nu ne dăm seama că, deşi este plăcut să umilim un
calculator, nu ne putem permite să umilim un utilizator".
În acest capitol au fost prezentate următoarele subiecte:
Modul de proiectare a aplicaţiei în scopul reducerii la minimum a
numărului de erori
Tehnici orientate pe obiect care pot fi folosite pentru prevenirea
erorilor
Testele pe care ar trebui să le efectuaţi pentru orice aplicaţie
nouă
Tipurile de erori şi modul de corectare acestora
Depanarea codului prin execuţie pas cu pas, folosind punctele de
întrerupere şi elementele de urmărire
Scrierea propriilor rutine de tratare a erorilor
Controlul de versiune
Prin prevenirea şi detectarea erorilor, veţi îmbunătăţi cu
siguranţă performanţele oricărui program pe care îl scrieţi.
Puteţi atinge nivelul de aplicaţie fără erori. Acest proces este
cunoscut sub numele de optimizare şi îl vom prezenta în capitolul
următor.
CAP: 12.OPTIMIZAREA BAZEI DE DATE
Chambers 20th Century English Dictionary defineşte optimizarea ca
fiind:
Pregătirea sau revizuirea unui sistem sau program de calculator în
vederea obţinerii eficienţei maxime.
Vom analiza diferite metode prin care un programator se poate asigura
că aplicaţia de baze de date funcţionează cu eficienţă maximă.
Vor fi prezente următoarele subiecte specifice:
Eficienţa unei secvenţe de cod
Cum se măsoară viteza unui program?
Câteva sugestii de scriere a codului pentru a crea programe mai
rapide
Ce trebuie să avem în vedere când scriem aplicaţii de reţea?
12.1 Eficienţa
Instrumentul Performance Analyzer (care poate fi activat din bara de
meniuri, executând clic pe Tools/Analyze şi selectând opţiunea
Performance) este foarte util în cazul aplicaţiilor de baze de date
cu performanţe scăzute. Totuşi, Performance Analyzer nu vă ajută
să rezolvaţi toate problemele, una dintre acestea fiind optimizarea
codului VBA.
Dacă scopul nostru este să obţinem o eficienţă maximă, se pune
întrebarea: "Prin ce se caracterizează eficienţa?". Este o
întrebare mult mi complexă decât pare la prima vedere. Iată care
sunt cele mai importante criterii de evaluare a eficienţei unei
aplicaţii de baze de date:
Viteza reală de execuţie
Viteza aparentă
Amprenta de memorie (adică dimensiunea)
Traficul de reţea
Aproape întotdeauna este posibil să optimizaţi o aplicaţie potrivit
unuia dintre aceste criterii de evaluare a performanţelor, însă cum
procedaţi pentru ca aplicaţia să le respecte pe toate patru?
Răspunsul este simplu: nu puteţi face acest lucru şi nici nu ar
trebui să încercaţi.
Una dintre sarcinile pe care le aveţi de rezolvat când începeţi un
proiect de dezvoltare este să stabiliţi o listă de priorităţi.
Care dintre cei patru factori menţionaţi anterior sunt cei mai
importanţi pentru implementarea cu succes a aplicaţiei? Care sunt de
dorit şi care sunt lipsiţi de relevanţă?
La criteriile de performanţă prezentate anterior puteţi adăuga
încă patru:
Protabilitatea
Robusteţea
Mentenabilitatea
Refolosirea
Nici unul dintre aceşti factori nu conduc neapărat la creşterea
eficienţei aplicaţiei - optimizarea unei secvenţe de cod potrivit
criteriilor de portabilitate sau robusteţe va determina micşorarea
vitezei de execuţie a programului sau un consum mai mare de memorie.
De fapt, aceşti opt factori acţionează în direcţii diferite. Să
considerăm următoarele secvenţe de cod:
Sau:
Ambele exemple conduc la acelaşi rezultat. Totuşi, primul dintre ele
are un timp de execuţie de patru ori mai mare decât al doilea. Dacă
optimizaţi codul în privinţa vitezei, ar trebui să alegeţi o a
doua variantă.
Pe de altă parte, s-ar putea ca mulţi programatori, în special cei
fără experienţă, să opteze pentru primul exemplu. Dacă
optimizaţi mentenabilitatea, alegeţi această variantă (în special
dacă, pe un calculator obişnuit, ambele secvenţe de cod sunt
executate într-o fracţiune de secundă).
În capitolul de faţă, nu veţi afla metoda optimă de scriere a
unui program. Aceasta va depinde de priorităţile determinate pentru
fiecare aplicaţie în parte. În schimb, vom prezenta impactul
fiecăruia din cei patru factori de optimizare menţionaţi anterior.
12.2 Reducerea supraîncărcării memoriei
Un calculator desktop modern care rulează Access 97 are, de obicei,
între 16 şi 64 M de memorie (RAM). În acest spaţiu de memorie este
executat codul aplicaţiei dumneavoastră. Cu cât calculatorul are mai
multă memorie, cu atât scade frecvenţa de citire şi de scriere pe
disc (procese relativ lente) şi, ca urmare, programul are o viteză
mai mare de execuţie.
Ca regulă generală, mai multă memorie înseamnă performanţe mai
bune. În trecut, calculatoarele erau limitate la 32 sau 64 kiloocteţi
de memorie. Pentru a face o comparaţie, aceasta reprezintă de
aproximativ 2000 de ori mai puţin decât memoria calculatorului pe
care îl folosesc eu pentru a scrie acest capitol. În acele timpuri,
chiar dacă nu aţi fi avut un sistem de operare sau un program capabil
să folosească 96 M de RAM - ceea ce depăşeşte cu mult capacitatea
calculatoarelor mainframe - costul memoriei ar fi reprezentat o avere.
De aceea, nu este surprinzător faptul că, având la dispoziţie o
cantitate de memorie limitată, programatorii consumau foarte mult timp
pentru a face ca aplicaţiile să încapă (şi să lucreze) pe
minusculele resurse ale calculatoarelor lor. Sintagma la modă era
"programare disciplinată"; limbajul folosit de obicei era limbajul de
asamblare sau codul maşină (aproape ilizibil pentru un nespecialist),
iar rezultatele obţinute constituiau o dovadă de ingeniozitate şi de
perseverenţă.
Astăzi, aceste probleme au dispărut. Dacă un program este prea
lent, nu aveţi decât să adăugaţi 16 M de RAM pe calculator!
Preţurile sunt modice. Oricum, ar costa mult mai mult să rescrieţi
codul programului astfel încât acest să ruleze pe un calculator cu
12 M de memorie la fel de rapid ca vechea versiune pe un calculator cu
24 M de memorie!
Nu am amintit toate acestea pentru a vă încuraja să construiţi
aplicaţii dezordonate. Memoria, deşi relativ ieftină, este
preţioasă. Cu cât consumă mai puţină memorie, programul este mai
rapid şi permite execuţia simultană a altor programe.
În plus, dacă scrieţi o aplicaţie care va fi folosită de o mie de
utilizatori, fiecare megaoctet suplimentar de memorie necesar
aplicaţiei echivalează cu 1000 M de memorie pe toate calculatoarele
pe care va rula programul.
Cu alte cuvinte, pentru majoritatea proiectelor, scrierea unei
aplicaţii cu o amprentă mică de memorie constituie în continuare o
prioritate esenţială în programare.
Ca urmare, la dezvoltarea unei aplicaţii, ar trebui să ţineţi cont
de următoarele recomandări:
Alegeţi corect tipurile de date.
Grupaţi procedurile pe module.
Eliminaţi comentariile şi secvenţele de cod inutile.
Eliberaţi memoria ori de câte ori este posibil.
Nu încărcaţi în memorie module / biblioteci care nu sunt
necesare.
Salvaţi baza de date ca fişier MDE.
12.2.1 Alegerea corectă a tipurilor de date
Diverse tipuri de date ocupă spaţii diferite de memorie.
Dimensiunile spaţiului de memorie ocupat de fiecare tip de date sunt
prezentate în tabelul următor:
Tipul de date Dimensiunea de stocare Domeniul de valori
Byte (Octet) 1 octet 0 până la 255
Boolean 2 octeţi True sau False
Integer (Întregi) 2 octeţi -32.768 până la 32.767
Long (Lungi) 4 octeţi -2.147.483.648 până la 2.147.483.647
Single (Simple) 4 octeţi -3,403E38 până la -1,401E-45;
0; 1,401E-45 până la 3,403E38
Double (Duble) 8 octeţi -1,798E308 până la -4,941E-324; 0;
4,941E-324 până la 1,798E308
Tipul de date Dimensiunea de stocare Domeniul de valori
Currency (Monetare) 8 octeţi -922.337.203.685.477,5808 la
922.337.203.685.477,5807
Decimal (Zecimale) 14 octeţi -7,923E28 până la 7,923E28 (variază
în funcţie de numărul de zecimale din număr)
Date (Date calendaristice) 8 octeţi Ianuarie 1, 10 până la Decembrie
31, 9999
Object (Obiect) 4 octeţi O referinţă la orice tip de obiect
Fixed string (Şir de lungime fixă) 1 octet pentru fiecare
caracter Până la aproximativ 65.400 caractere
Variable Length String (Şir de lungime variabilă) 10 octeţi +
lungimea şirului Până la aproximativ 2 miliarde de caractere
Variant (Numeric) 16 octeţi Acelaşi domeniu ca pentru variabilele de
tip Double
Variant (Şir) 22 octeţi + lungimea şirului Acelaşi domeniu ca
pentru şirurile de lungime variabilă
Aşa cum puteţi vedea, variabilele de tip Double ocupă de patru ori
mai multă memorie decât variabilele de tip întreg. Însă, şi
aici, optimizarea este o chestiune de compromis - variabilele duble şi
simple pot păstra valori dintr-un domeniu mult mai mare decât
variabilele întregi.
Problema utilizării memoriei devine şi mai importantă când se
lucrează cu matrice. Linia de cod:
ocupă aproximativ 800 de octeţi de memorie, în timp ce linia
următoare ocupă în jur de 200 de octeţi:
Ca regulă generală, dacă dimensiunea amprentei de memorie este o
prioritate de programare - şi de obicei este - alegeţi cele mai mici
variabile care pot memora valorile respective. Pentru a nu uita să
atribuiţi explicit tipuri de variabile, ar trebui să selectaţi
opţiunea Require Variable Declaration din caseta de dialog
Tools/Option…
Am mai spus acest lucru - dar merită să îl repetăm - folosiţi cu
prudenţă tipul de date Variant.
12.2.2 Gruparea procedurilor în module
VBA încarcă modulele numai când este apelată o procedură din
modulul respectiv. Acest procedeu se numeşte încărcare la cerere.
Rin urmare, dacă aveţi o rutină care apelează trei proceduri
acestea se găsesc în module separate, în memorie vor fi încărcate
toate cele trei module. Prin gruparea judicioasă a procedurilor cu
funţii înrudite în acelaşi modul, puteţi reduce la minimum
numărul de module încărcate simultan în memorie.
12.2.3 Eliminarea comentariilor şi secvenţelor de cod inutile
Aşa cum am arătat, este bine să comentaţi codul pe care îl
scrieţi. Chiar dacă înţelegeţi instrucţiunile în momentul în
care le scrieţi, s-ar putea ca peste şase luni să nu vă mai
amintiţi rolul fiecăreia. În plus, comentarea liniilor de cod ajută
la înţelegerea acestuia de către alte persoane. Inserarea
comentariilor în momentul scrierii codului nu necesită prea mult
timp, însă vă poate scuti de un efort mult mai mare în viitor (de
exemplu, în cazul depanării). Desigur, şi comentariile au preţul
lor.
Fiecare comentariu inserat în cod este încărcat în memorie
împreună cu procedura la care se referă. Pentru a evita
supraîncărcarea memoriei de către aplicaţia dumneavoastră, puteţi
lua în considerare şi varianta copierii fişierului cu baza de date
originală şi eliminării tuturor comentariilor din copia destinată
clienţilor. Astfel, veţi obţine o versiune de dimensiuni reduse pe
care o puteţi folosi şi distribui utilizatorilor, şi o versiune
comentată, cu care puteţi lucra atunci când sunteţi nevoit să
modificaţi ceva în aplicaţie. O soluţie şi mai bună o constituie
salvarea bazei de date în format MDE. Acest proces asigură eliminarea
tuturor comentariilor din cod şi compilarea automată a acestuia.
Fişierele MDE vor fi prezentate în Capitolul 18.
Oricum, nu justificaţi lipsa comentariilor din cod prin argumentul:
"Nu este suficientă memorie" atunci când adevăratul motiv este că
nu aveţi chef să le introduceţi. Lăsaţi lenea la o parte!
Acelaşi principiu se aplică şi în cazul procedurilor nefolosite,
sau aşa-numitul "cod mort". Procesul de dezvoltare a aplicaţiilor
presupune o mulţime de experimente şi, uneori, vă veţi da seama că
programul este plin de proceduri inutile sau de proceduri pe care
le-aţi păstrat pentru orice eventualitate. Ştergeţi şi aceste
porţiuni de cod din versiunea de aplicaţie care va fi distribuită
clienţilor.
12.2.4. Eliberarea memoriei ori de câte ori este posibil
Pentru a elibera memoria folosită de o matrice dinamică, puteţi
folosi instrucţiunea Erase. După terminarea lucrului cu matricea,
instrucţiunea Erase va elimina datele din matrice şi va elibera
memoria folosită de aceasta.
Instrucţiunea Erase nu eliberează spaţiul folosit de matricele
statice (cum sunt cele de dimensiune fixă). În schimb, le
reiniţializează.
Puteţi elibera şi memoria folosită de variabilele obiect de care nu
mai aveţi nevoie. Această operaţie se realizează prin configurarea
tuturor variabilelor la o valoarea specială, numită Nothing.
Reţineţi că memoria folosită de un obiect nu poate fi eliberată
dacă mai există o referinţă la obiectul respectiv în cod. Într-un
exemplu din capitolul precedent, am folosit această proprietate pentru
a împiedica distrugerea unei instanţe a unui formular pop-up, prin
plasarea unei referinţe la acesta în colecţia declarată la nivelul
modulului unui alt formular. Referinţa respectivă a împiedicat
distrugerea primului formular înainte de închiderea celui de-al
doilea şi de ieşirea colecţiei din domeniu.
12.2.5 Nu încărcaţi în memorie module / biblioteci care nu sunt
necesare
Vom vedea în capitolul următor că bazele de date biblioteci pot
reprezenta o soluţie utilă pentru stocarea şi refolosirea
procedurilor de care aveţi nevoie frecvent. Aceste biblioteci pot fi
folosite şi pentru a păstra aplicaţii wizard şi programe de
completare, cum ar fi aplicaţiile wizard de control şi de proiectare
a formularului, care sunt distribuite împreună cu produsul Access.
Fiecare dintre aceste baze de date biblioteci trebuie să fie
încărcată în memorie atunci când este folosită, ceea ce măreşte
substanţial spaţiul necesar de memorie. Ca urmare, pentru a reduce
cantitatea de memorie necesară instalării aplicaţiei, ar trebui să
nu încărcaţi bazele de date biblioteci sau programele de completare
care nu sunt absolut necesare.
12.2.6 Salvarea bazei de date ca fişier MDE
Către sfârşitul cursului, vom analiza ultimele retuşuri pe care ar
trebui să le efectuaţi asupra aplicaţiei înainte de a o distribui
utilizatorilor finali ai bazei de date. Unul dintre acestea constă în
conversia bazei de date într-un fişier MDE. Prin operaţia de
conversie, se compilează toate modulele din baza de date şi se
elimină comentariile, instrucţiunile inutile etc. din codul sursă.
Rezultă două avantaje majore: creşte siguranţa bazei de date şi
scade cantitatea de memorie necesară pentru rularea aplicaţiei.
Reţineţi faptul că nu puteţi modifica formatul fişierelor MDE şi
că este bine să păstraţi întotdeauna o versiune originală a bazei
de date în format MDB.
12.2.7 O ultimă recomandare - cumpăraţi mai multă memorie
Nu este nici o păcăleală! Pentru a rula, Access 97 are nevoie de
minimum 12 M de RAM într-un sistem Windows 95 şi de 16 M de RAM pe o
staţie de lucru Windows NT. Am făcut experimente pe sisteme cu 12 M,
16 M, 24 M şi 32 M şi pot să afirm că pentru a obţine performanţe
acceptabile, limita inferioară de memorie este de 16 M pentru rularea
independentă sub Windows 95 şi de 24 M pentru Windows NT.
Dacă lucraţi într-o reţea sau dacă folosiţi şi alte aplicaţii
Windows simultan, vă veţi da seama că merită să cheltuiţi nişte
bani pentru a suplimenta memoria cu 8 M de RAM (în ambele cazuri).
12.3 Creşterea vitezei de execuţie
Reducerea cantităţii de memorie ocupată de baza de date Access şi
codul acesteia poate avea ca rezultat creşterea vitezei de lucru,
atât a aplicaţiei dumneavoastră, cât şi a altor aplicaţii
Windows. Dacă viteza de execuţie este o prioritate de programare,
există şi alte metode pe care puteţi să le luaţi în considerare:
Folosiţi constante
Folosiţi tipuri specifice de obiecte (asociere iniţială)
Folosiţi tranzacţii acolo unde este cazul
Folosiţi variabile, şi nu proprietăţi
Evitaţi structurile lente
Folosiţi funcţii şir
Evitaţi instrucţiunea IIf
Folosiţi operaţii aritmetice cu întregi ori de câte ori este
posibil
Folosiţi cod in-line
Folosii judicios instrucţiunea DoEvents
Folosiţi cicluri For Each…
Folosiţi metoda Requery, nu acţiunea Requery
Folosiţi cuvântul cheie Me
Creaţi formularele pe baza unor interogări salvate
Creşteţi viteza operaţiilor cu baza de date
Vom analiza în detaliu aceste procedee şi vom prezenta câteva
secvenţe de cod demonstrative. Exemplele de cod vă vor ajuta să
evaluaţi impactul acestor tehnici de lucru (asupra performanţei).
Calculatoarele diferă foarte mult în privinţa dimensiunii memoriei
RAM, a vitezei procesorului, a dimensiunii memoriei cache, a vitezei
discului etc. Aceste diferenţe se reflectă în performanţele codului
VBA rulat pe fiecare maşină în parte. Nu mă credeţi pe cuvânt;
parcurgeţi singur toate aceste exemple.
Analizând rezultatele de mai jos, s-ar putea să vă întrebaţi dacă
are rost să vă pierdeţi vremea pentru a implementa unele dintre
aceste îmbunătăţiri. Dacă o operaţie nu durează decât trei
milisecunde, de ce v-aţi strădui să optimizaţi codul pentru ca
durata operaţiei respective să se reducă la o milisecundă? Cine va
observa acest lucru? Ei bine, trebuie să spunem că, deşi s-ar putea
ca diferenţa să nu fie sesizabilă pentru o singură linie de cod,
în cazul executării repetate a codului, diferenţa devine evidentă.
De exemplu, să presupunem că parcurgeţi ciclic toate controalele
unui formular pentru verificarea unei anumite condiţii; sau să
parcurgeţi ciclic toate înregistrările dintr-un set de
înregistrări. Obişnuiţi-vă să scrieţi întotdeauna un cod
eficient - astfel, veţi putea depăşi fără nici o problemă şi
situaţiile în care acest aspect este cu adevărat important.
12.3.1 Cronometrarea execuţiei codului
Pentru a testa viteza de execuţie a unei secvenţe de cod, există mai
multe opţiuni disponibile. O metodă foarte simplă este folosirea
funcţiei Timer. De exemplu, am putea utiliza secvenţa următoare de
cod pentru a afla cât durează parcurgerea unei structuri ciclice
For...Next...pentru 32.000 de valori.
Funcţia Timer returnează numărul de secunde care s-au scurs de la
miezul nopţii (de la ora 0). În exemplul de mai sus, am salvat
valoarea funcţiei Timer în variabila lngStart înainte de începerea
ciclului de instrucţiuni:
lngStart = Timer
După terminarea ciclului, am salvat valoarea funcţiei Timer în
variabila lngEnd:
lngEnd = Timer
Prin scăderea primei valori din a doua, putem determina durata
procesului de ciclare:
MsgBox lngEnd - lndStart & " secunde"
În cazul în care încercaţi singur acest exemplu, veţi observa
repede o limitare evidentă. Deoarece funcţia Timer face rotunjirea la
nivel de secundă, pe ecran va apărea, probabil, următoarea casetă
de mesaj la rularea codului.
Fig.12.1
Deci exemplul nu este relevant dacă testaţi un cod a cărui
execuţie durează mai puţin de o secundă! . Adăugaţi încă trei
de zero la 32000 si să rulăm codul .
Fig.12.2
O altă soluţie este să apelaţi pentru cronometrare o funcţie API.
Biblioteca winmm.dll conţine o funcţie numită timeGetTime, care
returnează numărul de milisecunde trecute de la pornirea sistemului
Windows. Am văzut această funcţie la lucru în capitolul dedicat
tehnicilor de programare avansată. Funcţia returnează o valoare cu
precizia de o milisecundă (1/1000 dintr-o secundă), fiind mult mai
adecvată pentru cronometrarea execuţiei unei secvenţe de cod. În
plus, este uşor de implementat. Următorul exemplu de convenţii de
denumire vă arată cum puteţi declara şi folosi funcţia pentru a
determina durata de execuţie a aceluiaşi cod:
Option Compare Database
Option Explicit
Dim lngStart As Long
Dim lngEnd As Long
Sub ShowTime()
End Sub
Dim i As Integer
For i = 0 to 32000
Next i
ShowTime
End Function
Modificarea semnificativă este adăugarea declaraţiei funcţiei
timeGetTime, ceea ce permite apelarea acesteia direct din Access ca
funcţie TimeIt:
Declare Function TimeIt Lib "winmm.dll" Alias "timeGetTime" ()_
As Long
De data aceasta, rezultatul va fi ceva mai clar: 20 miliseconds.
12.3.2 Folosirea constante
Dacă folosiţi în cod valori care nu se modifică, ar trebui să le
atribuiţi unor constante, nu unor variabile. Când întâlneşte o
variabilă într-o linie de cod VBA, Access trebuie să acceseze
locaţia de memorie care conţine variabila pentru a determina valoarea
acesteia. Pe de altă parte, valoarea unei constate este determinată
şi trecută în cod în etapa de compilare. Astfel, citirea valorilor
din constante durează mult mai puţin decât a celor din variabile:
Procedura Comentarii Număr de
iteraţii Rezultate (ms)
Total Pe iteraţie
VarsAndConstants (Partea 1) Utilizând variabile
locale 100000 67,8 0,0007
VarsAndConstants (Partea 2) Utilizând constante
locale 100000 50,0 0,0005
12.3.3 Folosiţi tipuri specifice de obiecte (asociere iniţială)
În versiunile anterioare de Access, puteaţi întâlni frecvent linii
de cod ca acestea:
Deşi codul poate fi executat, nu este eficient. Datorită faptului
că variabila obiect frm a fost declarată As Object, Access nu ştie
cu ce tip de obiect are de-a face. Aceasta înseamnă că ori de câte
ori încercăm să inspectăm sau să configurăm valoarea unei
proprietăţi, ori să apelăm în timpul execuţiei o metodă a acelui
obiect, Access trebuie să verifice mai întâi dacă proprietatea sau
metoda respectivă corespund obiectului. Această tehnică este
cunoscută sub numele de asociere ulterioară. O metodă mai bună de
scriere a acestui cod este:
De data aceasta, Access ştie ce tip de obiect este frm. Ca urmare,
poate determina încă din etapa de compilare ce proprietăţi şi
metode corespund obiectului. Această tehnică este numită asociere
iniţială. Deoarece Access trebuie să facă verificarea o singură
dată, înainte de rulare, diferenţa dintre vitezele de execuţie ale
secvenţelor de cod prin cele două metode poate fi semnificativă.
Un alt avantaj al tehnicii de asociere iniţială este faptul că
Access poate determina încă din faza de compilare ce proprietăţi
şi metode corespund obiectului. Orice eroare cauzată de scrierea
greşită a unor nume de proprietăţi sau metode este detectată în
etapa de compilare şi nu apare ca eroare de execuţie.
Procedura Comentarii Număr de
iteraţii Rezultate (ms)
Total Pe iteraţie
SpecificObjects (Partea 1) Utilizând sintaxa As
Object 100000 35796,5 0,3580
SpecificObjects (Partea 2) Utilizând variabile obiect
specifice 100000 7507,1 0,0751
12.3.4 Folosiţi variabile, nu proprietăţi
Puteţi obţine performanţe similare folosind variabile pentru a face
referire la formulare, controale şi proprietăţi. Dacă urmează să
includeţi într-o procedură mai multe referinţe la un formular,
raport sau control, este indicat să creaţi pentru obiectul respectiv
o variabilă obiect şi apoi să faceţi referire la variabilă, şi nu
la obiectul propriu-zis.
Se poate folosi şi structura With.
Codul scris cu una din cele două sintaxe prezentate mai sus va fi
rulat mult mai repede decât codul care foloseşte sintaxa lungă.
În această situaţie, sintaxa With…End With este rulată mai
încet decât prima metodă, care foloseşte variabile obiect. Aceasta
se datorează supraîncărcării pe care o presupune configurarea
structurii With. Totuşi, dacă veţi adăuga între instrucţiunile
With şi End With din ce în ce mai multe referinţe la obiectul
specificat, această structură poate deveni mai eficientă.
12.3.5 Folosiţi funcţii şir
Utilizarea funcţiilor şir este un alt domeniu în care se poate
manifesta imprecizia. Majoritatea funcţiilor şir au versiuni de tip
Variant. De exemplu, funcţia Format returnează pentru un anumit
format o valoare Variant.
Pe de altă parte, funcţia Format$ returnează un şir formatat.
De fapt, orice funcţie care are ca sufix caracterul $ returnează o
valoare String. Dacă formataţi o variabilă sau un grup de caractere
ce vor fi atribuite unei variabile şir, veţi obţine rezultate mai
bune folosind versiunea şir a funcţiei (în loc de versiunea
Variant).
Procedura Comentarii Număr de
iteraţii Rezultate (ms)
Total Pe iteraţie
StringFunctions
(Partea 1) Utilizând funcţia Format 100000 7141,3 0,0714
StringFunctions
(Partea 2) Utilizând funcţia Format$ 100000 6749,9 0,0675
12.3.6 Evitaţi folosirea structurilor lente
O altă modalitate de a mări viteza de execuţie a codului VBA este
evitarea structurilor lente. Ce înseamnă aceasta? Majoritatea
limbajelor oferă programatorului mai multe metode de a efectua o
anumită operaţie. Dacă viteza reală de execuţie este o prioritate
de programare, ar trebui să testaţi viteza obţinută prin aplicarea
fiecăreia dintre aceste metode şi să o alegeţi pe cea
corespunzătoare (adică pe cea mai rapidă). În practică s-ar putea
să vă daţi seama că metoda cea mai rapidă intră în conflict cu o
altă prioritate de programare, aşa încât trebuie să recurgeţi la
un compromis. Chiar şi într-o astfel de situaţie, cronometrarea
secvenţelor de cod este utilă, pentru că veţi putea folosi
informaţiile obţinute în proiectele viitoare.
12.3.7 Funcţia Immediate If (IIf)
Funcţia Immediate If (IIf) este considerată, de obicei, o metodă
rapidă şi simplă de a returna una din două valori, ca urmare a
evaluării unei expresii ca adevărată sau falsă.
Dacă Expression are valoarea True, se returnează TruePart, iar dacă
Expression este False, se returnează FalsePart. Instrucţiunea este
echivalentă cu secvenţa de cod următoare:
Principala diferenţă între cele două formate este că funcţia IIf
va evalua întotdeauna atât TruePart, cât şi FalsePart, în timp ce
structura If normală va evalua doar partea care este returnată.
Pentru a vedea ce implicaţii au aceste metode, să luăm în
considerare următoarele secvenţe de cod:
Si:
Ambele proceduri fac acelaşi lucru: evaluează variabila lngNumber.
Dacă aceasta are valoare 5, procedura atribuie variabilei lngRetVal
valoarea 10. Altfel, procedura atribuie variabilei lngRetVal o valoare
căutată în tabelul Order.
Deosebirea dintre proceduri este că a doua va căuta întotdeauna
înregistrarea din tabelul Order, indiferent dacă este necesară sau
nu. Prin urmare, dacă cele două proceduri sunt apelate cu argumentul
lngNumber egal cu 5, a doua va fi considerabil mai lentă.
Procedura Comentarii Număr de
iteraţii Rezultate (ms)
Total Pe iteraţie
IfAndIIf
(Partea 1) IIf, unde lngNumber = 5 100 4918,5 49,185
IfAndIIf
(Partea 2) If, unde lngNumber = 5 100 1,0 0,01
IfAndIIf
(Partea 1) IIf, unde lngNumber = 10 100 4634,3 46,343
IfAndIIf
(Partea 2) If, unde lngNumber = 10 100 4596,4 45,9638
12.3.8.Folosiţi operaţii aritmetice cu întregi ori de câte ori este
posibil
Viteza cu care se efectuează operaţiile aritmetice depinde de tipul
de date al variabilelor folosite în calcul şi de tipul operaţiei
efectuate.
În general, calculele cu variabile Integer şi Long sunt mai rapide
decât cele cu variabile Single şi Double. Acestea, la rândul lor,
sunt mai rapide decât calculele cu variabile Currency. Majoritatea
operaţiilor cu variabile de tip Variant durează de două ori mai mult
decât cele în care sunt folosite alte tipuri de variabile.
Cu toate că timpii de execuţie pentru o singură operaţie diferă
foarte puţin, în cazul operaţiilor repetitive (cum ar fi în
ciclurile de mari dimensiuni), diferenţa devine semnificativă.
12.3.9 Folosiţi cod in-line
Ceva mai devreme, am arătat că variabilele pot fi transmise ca
argumente în proceduri fie prin referinţă, fie prin valoare. Când o
variabilă este transmisă prin referinţă (cazul implicit), procedura
apelată transferă un pointer către locaţia de memorie a variabilei
transmise. În schimb, când o variabilă este transmisă prin valoare,
se face o copie a variabilei şi aceasta este transmisă procedurii.
Deşi transferul variabilelor prin valoare are câteva avantaje, este
mai lent decât transferul prin referinţă.
Oricum, ambele metode sunt mai lente decât plasarea secvenţei de cod
corespunzătoare in-line şi renunţarea la apelul unei proceduri.
Dezavantajul principal al folosirii codului in-line este dificultatea
de întreţinere în cazul în care aceeaşi secvenţă de cod apare
in-line în mai multe proceduri. Însă dacă principala prioritate de
programare este viteza de execuţie, ar trebui ca utilizarea codului
in-line să constituie o opţiune serioasă.
12.3.10 Folosiţi structura For Each…
Visual Basic include o structură de ciclare numită For
Each…Next…, care permite parcurgerea succesivă a tuturor
elementelor unei matrice sau unei colecţii de date.
Înainte de introducerea limbajului VBA, metoda standard folosită în
practică consta în determinarea numărului de elemente din colecţie
sau matrice şi utilizarea structurii For…Next… pentru a inspecta
fiecare element cu ajutorul unui contor de ciclare pe post de index al
colecţiei.
Ori de câte ori este posibil, folosiţi prima structură. Un ciclu
For Each…Next… este mult mai rapid decât un ciclu obişnuit care
foloseşte un contor de ciclare ca index al colecţiei sau al matricei.
Procedura Comentarii Număr de
iteraţii Rezultate (ms)
Total Pe iteraţie
For Each
(Partea 2) Utilizând o structură ciclică
tradiţională 10 592,3 59,2250
For Each
(Partea 1) Utilizând structura For…Each 10 237,8 23,7750
12.3.11 Folosiţi judicios instrucţiunea DoEvents
Dacă nu schimbaţi condiţiile implicite de lucru, o procedură VBA
aflată în execuţie acţionează foarte egoist, acaparând toate
resursele Access. De exemplu, dacă rulaţi următoarea secvenţă de
cod, vă veţi da seama rapid că Access este blocat până la
terminarea execuţiei codului.
Pe calculatorul meu, execuţia acestei rutine durează aproximativ
2,8 secunde. Este bine să treceţi controlul sistemului Windows cât
mai des posibil. De exemplu, s-ar putea ca în timpul execuţiei
acestei rutine să doriţi anularea ei, oprirea temporară sau chiar
efectuarea unei alte operaţii. Nu este prea plăcut ca rutina
respectivă să ignore toate solicitările dumneavoastră. Aveţi
nevoie de o modalitate de a permite şi procesarea altor evenimente în
timpul execuţiei rutinei.
Acest lucru este posibil prin utilizarea instrucţiunii DoEvents.
Aceasta cere sistemului Windows să trateze toate mesajele sau
apăsările de taste care se găsesc în coada de aşteptare. În
secvenţa următoare de cod, ori de câte ori ciclul ajunge la
instrucţiunea DoEvents, sistemul Windows preia controlul execuţiei
şi verifică dacă în alte aplicaţii există mesaje sau apăsări de
taste care aşteaptă să fie procesate. După tratarea acestora,
sistemul de operare transferă din nou controlul procedurii.
Cu toate că este folositoare în programare, această metodă
consumă mult timp. În condiţiile în care se face o verificare a
evenimentelor la fiecare parcurgere a ciclului, durata de execuţie a
rutinei depăşeşte 55 de minute! Dacă doriţi să folosiţi
instrucţiunea DoEvents, fiţi ceva mai rezervat. Secvenţa anterioară
de cod poate fi rescrisă astfel:
În acest caz, Windows preia controlul la fiecare 50.000 de cicluri,
adică de 20 de ori în 4,13 secunde (durata de execuţie a rutinei).
Aceasta înseamnă un comportament corespunzător al rutinei, dar şi o
viteză de execuţie destul de mare. Instrucţiunea DoEvents adaugă
doar 1,34 secunde la timpul de execuţie al secvenţei de cod.
În tabelul următor sunt prezentate rezultatele obţinute rulând
cele trei variante de cod pe un calculator din clasa Pentium. Le
puteţi testa şi dumneavoastră cu ajutorul procedurii DoEventsTest
din baza de date Whisky14.mdb de pe CD-ul ataşat cărţii, însă nu
uitaţi că efectuarea testului cu câte o instrucţiune DoEvents la
fiecare iteraţie va fi foarte lentă.
Procedura Comentarii Număr de
iteraţii Rezultate (ms)
Total Pe iteraţie
DoEventsTest
(Partea 1) Fără DoEvents 100000 2785,0 0,0279
DoEventsTest
(Partea 2) 20 de apeluri DoEvents 100000 4127,0 0,0413
DoEventsTest
(Partea 3) 100000 de apeluri DoEvents 100000 3348986,0 33,4899
12.3.12 Folosiţi metoda Requery, nu acţiunea Requery
O altă metodă de accelerare a execuţiei procedurilor este evitarea
utilizării acţiunii Requery pentru afişarea unor valori actualizate
într-un formular sau control şi folosirea, în schimb, a metodei
Requery. Aceasta este mai rapidă, deoarece nu efectuează decât o
simplă repetare a execuţiei interogării pe care se bazează
formularul sau controlul respectiv (deci nu reface setul de operaţii
pe care le presupune acţiunea Requery - închiderea formularului,
redeschiderea acestuia şi apoi repetarea execuţiei).
Trebuie să ştiţi că, uneori, metoda Requery şi acţiunea Requery
pot genera rezultate diferite. Metoda Requery extrage din memorie
valorile actualizate, fără cheie, în setul de înregistrări al
formularului, pe baza setului de chei existent, sau a setului de valori
cheie. În schimb, acţiunea Requery reface setul de chei şi apoi
extrage din memorie valorile fără cheie.
12.3.13 Folosiţi cuvântul cheie Me
În cazul în care folosiţi cuvântul cheie Me pentru a face referire
la un formular în procedura unui eveniment, Access caută formularul
respectiv în spaţiul de nume local. Aceasta înseamnă că formularul
va fi găsit mult mai repede decât în cazul specificării sale
printr-o referinţă completă.
12.4 Creşterea vitezei de execuţie a operaţiilor cu baza de date
Dacă optimizările pe care le realizaţi prin modificarea sintaxei
instrucţiunilor VBA sunt uneori insesizabile, optimizarea apelurilor
bazei de date conduce aproape întotdeauna la îmbunătăţirea
performanţelor. Motivule este foarte simplu. Apelurile bazei de date
sunt executate, de obicei, într-un timp mai lung decât
instrucţiunile VBA normale, astfel că o creştere cu 10% a
performanţelor va fi mult mai uşor vizibilă în cazul apelului bazei
de date. În continuare, vom analiza câteva modalităţi prin care
puteţi îmbunătăţi interacţiunea codului VBA cu baza de date.
12.4.1 Folosiţi indexuri
Adăugarea unui index la un câmp reprezintă o metodă de
îmbunătăţire a performanţelor de căutare în câmpul respectiv.
Cu toate că adăugarea indexurilor încetineşte actualizările şi
măreşte riscul apariţiei conflictelor de blocare, această
supraîncărcare este de obicei compensată de performanţele obţinute
la căutarea frecventă în câmpurile respective în cadrul
interogărilor. Puteţi sesiza aceste avantaje rulând procedura
UsingIndexes. Procedura deschide de două ori un set de înregistrări
prin următoarea secvenţă de cod:
La prima deschidere a setului de înregistrări, câmpul OrderDate nu
este indexat; a doua oară, este indexat. Tabelul următor prezintă
timpii de execuţie pentru această funcţie, însă dacă doriţi,
puteţi testa rutina personal.
Procedura Comentarii Număr de
iteraţii Rezultate (ms)
Total Pe iteraţie
UsingIndexes
(Partea 1) OrderDate nu este indexat 100 4653,0 46,5300
UsingIndexes
(Partea 2) OrderDate este indexat 100 2163,0 21,6300
12.4.2. Folosiţi semne de carte
La deschiderea unui set de înregistrări, fiecărei înregistrări
îi este atribuită automat o proprietate Bookmark (semn de carte).
Dacă aţi deschis un set de înregistrări şi ştiţi că veţi
reveni la înregistrarea curentă, este bine să salvaţi într-o
variabilă semenul de carte (Bookmark) corespunzător înregistrării
respective. Atribuind proprietăţii Bookmark a obiectului Recordset
valoarea pe care aţi salvat-o în variabilă, veţi putea reveni la
înregistrare mult mai rapid decât prin metodele Find sau Seek.
Semnele de carte (Bookmark) sunt stocate ca matrice de octeţi şi ar
trebui să fie salvate în acest format, şi nu ca şiruri. Cu toate
că puteţi salva proprietatea Bookmark într-o variabilă şir, este
posibil ca prin compararea valorii Bookmark a unei înregistrări cu o
valoare Bookmark memorată de o variabilă şir să nu obţineţi
rezultate corecte (cu excepţia cazului în care are loc o comparare
binară).
12.4.3. Folosiţi ca sursă pentru formulare interogări salvate
Interogările salvate sunt rulate mult mai rapid decât cele create
dinamic cu ajutorul instrucţiunilor SQL, pentru că sunt deja
compilate. De aceea, un formular care se bazează pe o interogare
salavată va fi deschis mult mai repede decât unul care are ca sursă
de înregistrări (RecordSource) o instrucţiune SQL.
Dezavantajul acestei metode este dificultatea întreţinerii. Dacă
exportaţi în altă bază de date un formular bazat pe o interogare
salvată, trebuie să exportaţi şi interogarea corespunzătoare. Pe
de altă parte, dacă formularul are ca sursă de înregistrări
(RecordSource) o instrucţiune SQL, nu trebuie exportat decât
formularul.
12.5. Creşterea vitezei aparente
Până acum, aţi aplicat diverse metode de creştere a vitezei reale
de execuţie a codului VBA şi a apelurilor bazei de date. Cum
procedaţi însă dacă aţi optimizat aplicaţia pentru o viteză
reală de execuţie, dar aceasta continuă să fie lentă? Una dintre
opţiunile posibile este creşterea vitezei aparente a aplicaţiei.
Este vorba de viteza cu care crede utilizatorul că va fi rulată
aplicaţia, nu de viteza reală de execuţie.
Pentru a face ca aplicaţia să pară mult mai rapidă, aveţi la
dispoziţie următoarele modalităţi de optimizare:
Utilizarea unui formular de început
Utilizarea indicatoarelor care ilustrează progresul operaţiei
Ştergerea codului din modulele de formular
Preîncărcarea şi ascunderea formularelor
Memorarea locală a datelor
12.5.1 Un formular simplu de început
Una dintre cele mai sigure metode de a distrage atenţia
utilizatorilor atunci când o aplicaţie efectuează o operaţie
într-un interval de timp prea mare este afişarea unor imagini grafice
atrăgătoare. De fapt, aşa procedează Microsoft. Ce se întâmplă
când porniţi Access, Word sau Excel? Vedeţi un formular de început
sau un ecran de descriere cu menţiunea de copyright:
Când vedeţi imaginea respectivă, vă spuneţi în gând: "Arată
bine. Aş vrea ca şi aplicaţia mea să aibă un aspect atât de
profesional!". Şi până să vă treziţi din reverie, aplicaţia s-a
şi încărcat.
Dacă nu aţi vedea un ecran de deschidere, probabil că v-aţi
întreba: "Oare ce se întâmplă? De ce durează aşa de mult
încărcarea aplicaţiei?". Ecranele de deschidere îşi îndeplinesc
rolul pentru care au fost concepute.
Vestea bună este că, în Access 97, puteţi realiza foarte uşor
ecrane de deschidere. Nu trebuie decât să creaţi un formular şi să
specificaţi numele său în rubrica Display Form din caseta de dialog
Tools/Startup…
Un mic sfat: nu încărcaţi formularul de început cu prea multe
controale sau cu un cod prea complex pentru evenimentul Load, deoarece
riscaţi ca afişarea formularului să dureze prea mult şi nu vă mai
atingeţi scopul!
12.5.2 Folosiţi indicatoare care ilustrează progresul operaţiei
O altă modalitate de a distrage atenţia utilizatorilor - şi de a-i
asigura că se întâmplă ceva - este afişarea pe ecran a unui
indicator care prezintă progresul operaţiilor efectuate. Funcţia
SysCmd oferă o metodă simplă de a realiza acest lucru. Pentru a
afişa un indicator de progres pe bara de stare a aplicaţiei, trebuie
parcurse trei etape:
Iniţializarea contorului (indicatorului) de progres, cu
specificarea valorii maxime şi a textului care trebuie afişat
Actualizarea repetată a contorului pentru a ilustra progresul
operaţiei
Ştergerea indicatorului de progres
Următoarea secvenţă de cod reprezintă una dintre metodele de
afişare a indicatorului de progres:
Această procedură determină afişarea unui indicator de progres,
care se umple gradual, precum şi a testului "Testing…".
Desigur, pentru actualizarea indicatorului, dumneavoastră nu trebuie
să scrieţi un ciclu de instrucţiuni. Vă puteţi structura procedura
astfel:
Cele trei constante, acSysCmdInitMeter, acSysCmdUpdateMeter şi
acSysCmdRemoveMeter, care sunt folosite pentru iniţializarea,
actualizarea şi ştergerea indicatorului de progres de pe bara de
stare, sunt intrinsece mediului Access. Cu alte cuvinte, fac parte din
limbaj şi nu trebuie declarate nicăieri.
12.5.3 Ştergeţi codul din modulele de formulare
Utilizatorii încep să se agite dacă execută clic pe un buton
pentru a deschide un formular şi afişarea acestuia întârzie. Aşa
se întâmplă de obicei când un formular are foarte mult cod în
modulul său, care măreşte durata de încărcare. În acest caz, ar
trebui să ştergeţi codul din modulul de formular şi să îl
plasaţi într-un modul de cod standard. Ca urmare, formularul va fi
afişat mult mai repede, iar codul va fi încărcat numai la cerere,
după deschiderea formularului.
12.5.4 Preîncărcaţi şi ascundeţi formularele
Pe lângă metoda prezentată anterior, dacă folosiţi frecvent un
anumit formular care necesită mult timp pentru încărcare şi
descărcare, puteţi să încărcaţi formularul în timpul lansării
în execuţie a aplicaţiei şi apoi să îl afişaţi şi să îl
ascundeţi, în loc să îl încărcaţi şi descărcaţi în memorie.
Această tehnică va încetini lansarea în execuţie a aplicaţiei,
dar va creşte substanţial performanţa de ansamblu. Puteţi
întârzia încărcarea formularului chiar şi după afişarea pe ecran
a formularului principal al aplicaţiei. În timp ce utilizatorul
priveşte formularul principal, în fundal poate fi încărcat al
doilea formular.
Metoda prezentată este utilă dacă viteza aparentă este o
prioritate de programare, însă reţineţi că mai multe formulare
încărcate concomitent vor spori cantitatea de memorie necesară
aplicaţiei.
12.5.5. Stocaţi datele în memoria locală
O zonă cache este o zonă de memorie (sau spaţiu pe hard-disc)
utilizată pentru a stoca valori provenite din altă parte şi
pregătite pentru a fi refolosite. De exemplu, Windows 95 plasează
datele provenite de pe hard-disc într-o zonă cache reprezentată de o
porţiune din memorie. Sunt frecvente situaţiile în care un program
foloseşte în mod repetat aceleaşi date. Prin această metodă,
programul va citi datele direct din zona cache şi nu va mai pierde
timp căutându-le de fiecare dată pe hard-disc. În plus, citirea din
memorie este mai rapidă şi mai eficientă decât citirea de pe
hard-disc.
Prin urmare, puteţi îmbunătăţi performanţele unei aplicaţii
utilizând zone cache pentru stocarea datelor. În ordinea
descrescătoare a vitezei, cele trei metode de obţinere a datelor
sunt:
Citirea datelor din memorie (de exemplu, variabile, matrice)
Citirea datelor din tabele stocate
Citirea datelor din tabele stocate pe calculatoare legate într-o
reţea
Dacă doriţi să creşteţi viteza aparentă de rulare a aplicaţiei,
gândiţi-vă la un nivel superior de stocare a datelor (adică la
schimbarea tipului de memorie cache).
Dacă păstraţi date accesate frecvent - dar care nu se modifică des
- într-un tabel de pe un sever de reţea ar trebui să aveţi în
vedere copierea datelor pe calculatorul client local pentru ca
aplicaţia să ruleze mai repede. Totuşi, va trebui să vă asiguraţi
că, ori de câte ori sunt actualizate pe server, datele vor fi
actualizate şi pe calculatoarele client (şi invers).
În mod similar, dacă aveţi date într-un tabel de căutare (de
exemplu, Region) pe care îl accesaţi frecvent prin codul VBA, puteţi
crea cu ajutorul metodei GetRows o matrice pentru stocarea datelor
respective. Această tehnică poate mări semnificativ viteza de
obţinere a datelor. Bineînţeles, va creşte şi necesarul de memorie
pentru aplicaţia dumneavoastră.
12.5.6. Consideraţii referitoare la lucrul în reţea
Până acum, ne-am concentrat atenţia asupra scrierii unui program
care să încapă într-o zonă redusă de memorie şi să poată fi
executat cât mai repede posibil - sau măcar să creeze această
impresie. Însă unul din motivele esenţiale pentru care aplicaţiile
de baze de date Access sunt lente nu are nici o legătură cu
dimensiunea memoriei necesare sau cu viteza de execuţie a codului. De
cele mai multe ori, rularea lentă este cauzată de cantitatea enormă
de date care trebuie să fie citite de pe disc şi apoi transferate
prin reţea.
Lucrul în reţea are două neajunsuri importante. În primul rând,
performanţa obţinută la transferul datelor - în special printr-o
reţea lentă - poate fi mai slabă decât în cazul folosirii
tabelelor locale. În al doilea rând, s-ar putea ca aplicaţia
dumneavoastră să genereze un intens trafic de reţea. Acest fapt îi
va deranja pe ceilalţi utilizatori ai reţelei, care vor observa că
aplicaţiile lor sunt încetinite considerabil din cauza aglomerării
traficului. Dacă unul dintre cele două aspecte menţionate
reprezintă o problemă pentru dumneavoastră, puteţi aplica
următoarele tehnici:
Căutarea după câmpuri indexate în tabele ataşate
Plasarea pe calculatorul local a obiectelor care nu sunt de tip
tabel
Dezactivarea opţiunii AutoExpand
12.6. Ultimele retuşuri
Toate sugestiile de până acum au fost analizate ca priorităţi
specifice de programare: creşterea vitezei reale de execuţie,
reducerea traficului de reţea sau micşorarea amprentei de memorie a
aplicaţiei de baze de date.
În unele cazuri, o singură măsură de optimizare poate aduce mai
multe avantaje. De exemplu, schimbarea tipului unei variabile de la
Variant la întreg va reduce considerabil necesarul de memorie şi va
creşte viteza de execuţie.
Totuşi, există şi situaţii în care o măsură de optimizare are
efecte antagonice: atât pozitive, cât şi negative. De exemplu,
tehnica de încărcare şi ascundere a formularelor va mări viteza
aparentă de execuţie a aplicaţiei, dai şi amprenta de memorie a
acesteia. În această situaţie, trebuie să vă stabiliţi
priorităţile şi să acţionaţi în consecinţă.
Secţiunea finală din acest capitol prezintă câteva tehnici care
îmbunătăţesc întotdeauna performanţele aplicaţiei dumneavoastră
- indiferent de priorităţile de programare.
Acestea sunt:
Compactarea bazei de date
Compilarea tuturor modulelor
Deschiderea bazelor de date în mod exclusiv
12.6.1 Compactarea bazei de date
După o perioadă de timp, este posibil să constaţi că
performanţele aplicaţiei dumneavoastră sunt în scădere. Cauza ar
putea fi procesul de fragmentare a bazei de date.
Fragmentarea se produce la ştergerea unor obiecte din baza de date,
în situaţia în care spaţiul folosit de aceste obiecte nu este
recuperat. Baza de date va fi ca un şvaiţer - cu o mulţime de
spaţii goale - şi, în acelaşi timp, va deveni mai lentă. Deşi nu
este deteriorată în nici un fel, performanţele scad. Aceasta pentru
că citirea datelor necontigue (fragmentate) de pe disc este mai lentă
decât a datelor contigue.
Prin compactarea unei baze de date, este eliminat tot spaţiul
nefolosit (găurile din şvaiţer), iar paginile de date devin
contigue. Aplicarea acestei tehnici prezintă două avantaje:
Îmbunătăţirea performanţelor bazei de date
Reducerea dimensiunii fişierului bazei de date
Compactarea unei baze de date se poate realiza cu ajutorul opţiunii
specifice din meniu, dar şi prin cod VBA, folosind metoda
CompacteDatabase a obiectului DBEngine:
Pentru a obţine performanţe optime, înainte de compactarea bazei de
date ar trebui să folosiţi un program de defragmentare a discului (de
exemplu Disk Defragmenter, care este distribuit împreună cu Windows
95).
12.6.2 Compilarea tuturor modulelor
Aţi lucrat cu înfrigurare tot weekend-ul pentru a termina aplicaţia
de baze de date, în vederea prezentării de luni în faţa
consiliului. Aţi testat aplicaţia azi-noapte - într-un mediu
obişnuit de lucru - şi aceasta a funcţionat bine. Mai aveţi la
dispoziţie o oră şi vă gândiţi să rulaţi o mică rutină
proprie de bibliotecă pentru a adăuga procedurilor nişte anteturi de
efect. Durează doar câteva minute şi aţi rulat-o de multe ori, aşa
încât ştiţi sigur că nu conţine erori de programare.
Momentul aşteptat a sosit; membrii consiliului se aşează în jurul
mesei, dumneavoastră executaţi clic pe pictograma aplicaţiei… şi
aşteptaţi… aşteptaţi… aşteptaţi…
"Ce este asta?" vă întrebaţi în gând. "Ce s-a întâmplat cu
aplicaţia mea? Se mişcă de parcă ar fi un câine şchiop… aflat
în comă". Poate că aţi uitat să recompilaţi aplicaţia!
Când efectuaţi modificări (de orice fel) într-un modul de cod
standard sau într-un modul de clasă (inclusiv modulele de formulare
şi rapoarte), modulul respectiv trebuie să fie recompilat înainte de
a fi lansat în execuţie. Pentru a compila codul din toate modulele
bazei de date, selectaţi opţiunea Compile and Save All Modules din
meniul Debug.
Dacă nu compilaţi explicit codul prin această metodă, sistemul
Access compilează codul în timpul de execuţie, ceea ce poate
determina o întârziere semnificativă, în special dacă modulele
compilate conţin multe linii de cod. Întârzierea este limitată
dacă aţi validat caseta Compile On Demand (Compilare la cerere) din
pagina etichetei Module a casetei de dialog Tools/Options… În acest
caz, Access compilează secvenţele de cod apelate de procedura
executată - prin arborele de apeluri. Ca urmare, întârzierea este
mai mică. Pentru siguranţă, ar trebui ca înainte de distribuirea
aplicaţiei, să compilaţi întotdeauna întregul cod. Prin compilare,
vor fi detectate o serie de erori, cum ar fi o instrucţiune For…
care nu este urmată de instrucţiunea Next.
12.6.3 Deschiderea bazelor de date în mod exclusiv
Dacă sunteţi singura persoană care va folosi baza de date la un
moment dat, ar trebui să o deschideţi în mod exclusiv. Aplicaţia va
fi executată mai rapid, deoarece Access nu va mai pierde timpul cu
monitorizarea altor utilizatori care doresc să blocheze
înregistrări. Pentru a vă asigura că baza de date va fi deschisă
în mod exclusiv, selectaţi opţiunea Exclusive ca Defalut Open Mode
în pagina etichetei Advanced a casetei de dialog Tools/Options…
Dacă doriţi să deschideţi o singură bază de date în mod
exclusiv atunci când este prestabilit modul partajat, executaţi clic
în caseta de validare Exclusive din caseta de dialog Open Database.
Dacă lansaţi aplicaţia din linia de comandă, puteţi folosi
opţiunea /Excl pentru a obţine acelaşi rezultat.
Dacă deschideţi baza de date în VBA, configuraţi argumentul
Exclusive la valoarea True atunci când folosiţi metoda OpenDatabase:
12.7 Rezumat
Crearea unei aplicaţii este o mare realizare. Construirea unei
aplicaţii care rulează rapid (sau măcar dă această impresie) şi u
ocupă toată memoria calculatorului înseamnă însă cu totul altceva
- este ceea ce va consacra sau va invalida aplicaţi. Utilizatorii sunt
fiinţe nerăbdătoare şi, pentru ei, nimic nu este mai rău decât un
program ineficient.
Acest capitol a prezentat o serie de sugestii şi trucuri pentru
creşterea vitezei generale de execuţie a codului. Înainte de a
începe scrierea secvenţelor de cod, ar trebui să stabiliţi care
sunt priorităţile de programare şi apoi să urmaţi sugestiile
prezentate în carte. Nu uitaţi că optimizarea unei priorităţi, cum
ar fi mentenabilitatea, poate afecta un obiectiv secundar, a de exemplu
viteza de execuţie a codului - numai dumneavoastră puteţi decide
care prioritate este mai importantă.
În capitolul de faţă, s-a prezentat:
Cum poate fi redusă supraîncărcarea memoriei prin alegerea
corespunzătoare a tipurilor de date, recuperarea memoriei şi
renunţarea la comentariile de prisos
Tehnicile de programare prin care puteţi mări viteza de execuţie
Diverse trucuri, cum ar fi utilizarea unui ecran de început şi a
unor indicatoare care să ilustreze progresul unei operaţii, pentru a
distrage atenţia utilizatorului şi a crea impresia că aplicaţia
rulează mai rapid
Cum să măriţi eficienţa unei aplicaţii de reţea
În capitolul următor, vom discuta despre avantajele codului
refolosibil, arătând cum puteţi folosi bibliotecile de rutine şi
programe de completare pentru a reduce timpul de dezvoltare şi de
testare a aplicaţiei.
CAP: 13 .INTERNET
Iată subiectul cel mai fierbinte şi controversat din lumea
calculatoarelor. Mulţi văd în Internet salvatorul societăţii
noastre - prin crearea unei comunităţi globale, care are la
dispoziţie o abundenţă de informaţii, 24 de ore pe zi. Alţii văd
în Internet un monstru care aşteaptă să ne înghită după ce îi
vom cădea cu toţii în capcanele ademenitoare.
Indiferent de care parte vă situaţi, realitatea este că reţeaua
Internet există, va exista încă mulţi ani şi, cel mai important,
poate constitui un instrument de lucru foarte util.
Acest capitol este dedicat modalităţilor în care puteţi folosi
facilităţile Internet în Access 97. Vom prezenta următoarele
subiecte:
Ce este Internetul?
Cum se utilizează hiperlegăturile?
Cum se pot publica date în Internet?
Crearea unui browser Web
13.1 Ce este Internetul?
Termenul Internet denumeşte o colecţie de calculatoare legate între
ele - o reţea foarte mare, dat atâta tot. Înainte de a vedea cum
putem folosi caracteristicile Access pentru a ne conecta în şi din
Internet, vom defini câteva noţiuni:
HyperText Markup Language, HTML, este formatul în care sunt
stocate documentele Internet. Este un limbaj foarte simplu, care
iniţial, era destinat aranjării textului pe ecran, formatărilor etc.
caracteristica hipertext permite stabilirea unor legături între
documente, astfel încât dumneavoastră să puteţi trece uşor de la
un document la altul, urmărind legăturile şi referinţele existente.
HTML evoluează continuu, incluzând din ce în ce mai multe
facilităţi; deocamdată, gândiţi-vă la HTML ca la o posibilitate
de formatare a documentelor.
Un browser (program de navigare în Web) este un program care
afişează documente HTML. Cele mai cunoscute browsere sunt Microsoft
Internet Explorer şi Netscape.
Un sit Web este un calculator (sau un grup de calculatoare) din
Internet care păstrează documente HTML. De exemplu, situl Web al
editurii Wrox se găseşte la adresa http://www.wrox.com. Expresia www
provine de la World Wide Web, numit uneori doar Web; wrox este numele
companiei, iar com prescurtarea de la companie sau sit comercial. Alte
sufixe des întâlnite sunt .edu (pentru situri educaţionale, cum sunt
cele ale universităţilor şi colegiilor) şi .gov (pentru situri
guvernamentale).
O adresă URL (Uniform Resource Locator) este numele atribuit unui
anumit sit Web sau a unui document din situl respectiv. Documentele
sunt stocate la fel ca pe un hard-disc obişnuit, într-o structură de
directoare. Pentru pagina Access a firmei Microsoft, adresa URL ar fi
http://www.microsoft.com/access.
Un server Web este maşina care controlează un sit Web. Acest
server primeşte cereri de la browserele Web şi le pune la dispoziţie
documentele solicitate.
13.2 Protocoale
Pentru a evita orice confuzie, haideţi să vedem care sunt
principalele proto-coale folosite în Internet şi cum funcţionează.
Un protocol este numele limbajului prin care calculatoarele comunică
între ele. Într-o reţea sistemele componente se înţeleg prin
intermediul unui protocol de reţea. Când comunicaţi cu un calculator
din Internet, folosiţi tot un protocol de reţea. De când prin
Internet se furnizează şi alte materiale decât pagini HTML, au
apărut şi protocoale care indică activitatea pe care doriţi să o
desfăşuraţi. De exemplu:
Când folosiţi un browser Web pentru a accesa documentele HTML,
utilizaţi un protocol de transfer pentru hipertext (HxperText Transfer
Protocol - HTTP). Este motivul pentru care adresele URL încep cu
http:. În acest fel, se comunică serverului Web tipul de serviciu pe
care doriţi să îl folosiţi.
Un alt protocol important este protocolul pentru transferul
fişierelor (File Transfer Protocol - FTP). Acest vă permite să
transferaţi în şi dintr-un server Web programe şi documente. În
acest caz, adresa URL va începe cu ftp:.
Un alt protocol pe care îl veţi folosi, probabil, în Access este
protocolul MailTo, care ajută programul dumneavoastră de poştă
electronică să transmită mesaje e-mail. În acest caz, adresa va
începe cu mailto:.
Desigur, există multe alte protocoale, însă acestea nu sunt folosite
atât de frecvent precum cele prezentate anterior.
13.3 Date de tip hiperlegătură (Hyperlink)
Access 97 are un nou tip de date pentru lucrul în Internet -
Hyperlink. Ca urmare, puteţi introduce o adresă URL ca un câmp
într-un tabel sau într-un formular. Hiperlegătura poate conţine
trei informaţii: un text de afişare, o adresă şi o sub-adresă.
Textul de afişare este textul pe care doriţi să îl afişaţi pe
ecran. Aţi observat probabil în timpul navigării prin Web că multe
legături sunt descrise prin text, şi nu prin adrese URL.
Adresa este URL-ul materialului care va fi vizualizat.
Sub-adresa este secţiunea din cadrul materialului.
Cele trei părţi sunt separate prin semnul diez (#); prin urmare, o
hiperlegătură arată astfel:
Display Text#Address#Sub Address
Pentru clarificare vom prezenta câteva exemple:
Adresa URL Textul afişat pe ecran Acţiune
http://www.microsoft.com http://www.microsoft.com Sare la pagina
iniţială Microsoft
Microsoft on the Web#www.microsoft.com# Microsoft on the Web Sare la
pagina iniţială Microsoft
Hyperlinks#C:\Wrox\
BegVBA97\Internet.doc#
Hyperlinks Hyperlinks Deschide documentul C:\Wrox\BegVBA97\
Internet.doc şi sare la semnul de carte
Hyperlinks
Whiskies#C:\Wrox\
BegVBA97\Whisky.mdb#
Form frmMaintWhisky Whiskies Deschide formularul frmMaintWhisky din
baza de date
C:\Wrox\BegVBA97\
Whisky.mdb
Whiskies## Form
frmMaintWhisky Whiskies Deschide formularul frmMaintWhisky din
baza de date curentă
Observaţi că tipul de date hiperlegătură nu limitează adresele
URL doar la documente HTML. Puteţi indica şi documente Word, foi de
calcul Excel, formulare Access etc. Beneficiind de posibilitatea de a
deschide formulare, puteţi chiar să înlocuiţi codul butoanelor care
deschid alte formulare cu o adresă de hiperlegătură. Aceasta va
deschide un formular nou fără a folosi vreo instrucţiune de cod.
13.4. Cum se utilizează hiperlegăturile?
Gândiţi-vă cât de utile ar fi hiperlegăturile în aplicaţia
dumneavoastră, pentru ca utilizatorii, cu un singur clic de mouse, să
poată ajunge într-un sit Web. Din fericire, hiperlegăturile sunt
extrem de simplu de implementat, pentru că Access permite folosirea
tipului de date Hyperlink în tabele şi formulare.
13.5 Hiperlegături în VBA
După ce aţi văzut câte de uşor este să adăugaţi hiperlegături
în tabele şi formulare, vă întrebaţi, probabil, cum puteţi
implementa prin program aceste elemente. Ei bine, şi tipul de date
Hyperlink are câteva metode şi proprietăţi, la fel ca toate
celelalte obiecte.
Element Tip Descriere
Hyperlink Proprietate O proprietate a controlului asociat cu coloana
de hiperlegături care face referire la obiectul hiperlegătură.
Address Proprietate Adresa principală a hiperlegăturii.
SubAddress Proprietate Sub-adresa hiperlegăturii.
Follow Metodă Urmăreşte hiperlegătura până la destinaţie. Are o
acţiune similară cu executarea unui clic pe control.
AddToFavorities Metodă Adaugă hiperlegătura în dosarul Favorites.
FollowHyperlink Metodă Urmăreşte hiperlegatura direct prin adresă.
Este folosită pentru controalele care nu au proprietatea
HyperlinkAddress.
HyperlinkPart Metodă Desparte hiperlegătura în părţile
componente.
Datorită utilizării simple a hiperlegăturilor din tabele şi
formulare, s-ar putea să nu aveţi nevoie să folosiţi aceste
funcţii prin cod VBA. Aşa cum aţi văzut, executarea unui clic pe o
hiperlegătura în Access este acelaşi lucru cu deschiderea de pagini
Web cu ajutorul unei hiperlegături. Totuşi, s-ar putea să existe
situaţii în care să doriţi manipularea hiperlegăturilor prin cod -
în acest scop, puteţi folosi metodele din tabelul de mai sus, care
sunt foarte simple. Există o funcţie care vă uşurează munca;
aceasta se numeşte HyperlinkPart.
13.6. Publicarea în Web
Acum, după ce aţi văzut că datele pot fi legate şi din surse
externe, vă întrebaţi probabil cum să puneţi la dispoziţia celor
interesaţi datele din Access. Este foarte simplu, însă, şi în
acest caz, vom începe prin a prezenta câteva aspecte teoretice.
13.6.1 Documente HTML statice
O pagină HTML statică este un document HTML independent, care
prezintă datele din momentul în care a fost creat. Documentul nu este
legat la o bază de date şi nu reflectă modificările din cadrul
acesteia. Pentru a actualiza datele dintr-un document HTML static, va
trebui să îl creaţi din nou. Documentele HTML statice sunt foarte
bune pentru texte cu caracter general, însă nu şi în cazul bazelor
de date, deoarece nu afişează cele mai recente informaţii. Aceste
documente au sufixul .html şi pot fi folosite pe orice server Web.
În documentele HTML statice puteţi salva tabele, interogări,
formulare şi rapoarte. În cazul rapoartelor, formatarea se
păstrează, astfel că documentul rezultat va arăta exact ca un
raport Access, însă pentru celelate tipuri de obiecte, documentul va
avea aspectul unei foi de date.
Există două metode de a salva datele ca document HTML. Prima metodă
este următoarea: selectaţi elementul dorit şi alegeţi Save
As/Export…din meniul File. Apoi selectaţi opţiunea To an External
File or Database (Într-un fişier extern sau într-o bază de date)
din caseta de dialog afişată pe ecran.
Pe ecran va fi afiată caseta de dialog Save standard. Schimbaţi
opţiunea Save as type în HTML Documents (Documente HTML).
Introduceţi un nume de fişier şi executaţi clic pe butonul de
Export; cu aceasta, aţi terminat. Acum puteţi deschide fişierul
într-un browser Web. Trebuie remarcat că în câmpurile de căutare
sunt afişate numele de identificare, şi nu datele de căutare.
13.6.2 Aplicaţia wizard HTML Export
A doua metodă de a exporta obiecte ale unei baze de date în
documente HTML constă în folosirea aplicaţiei wizard HTML Export.
Pentru a o lansa în execuţie, alegeţi Save As HTML din meniul File.
Aplicaţia vă va conduce prin etapele procesului de creare a
documentului HTML, permiţându-vă să alegeţi obiectele pe care
doriţi să le salvaţi şi tipul de export pe care doriţi să îl
realizaţi. Există şi alte opţiuni, care vă permit să alegeţi
şabloane, o sursă de date ODBC sau o bază de date Access, precum şi
locul unde doriţi să salvaţi documentul.
Nu vom studia toate aceste detalii; amintim doar că aplicaţia wizard
reuneşte trei metode de salvare a informaţiilor în documente HTML.
Internet Data Connector
Internet Data Connector - IDC permite afişarea unei pagini dinamice,
create dintr-un document HTML, care interoghează baza de date şi
afişează informaţiile căutate. La fiecare deschidere sau
împrospătare a paginii, are loc o nouă interogare a bazei de date.
Această bază de date poate fi orice sursă de date ODBC, însă
serverul Web trebuie să fie Microsoft Internet Information server
(IIS). Sunt necesare două fişiere: un fişier .idc şi unul .htx.
În fişierele IDC puteţi exporta tabele, interogări şi formulare,
însă toate acestea vor arăta ca nişte foi de date. Urmaţi acelaşi
algoritm ca în cazul documentelor HTML statice, însă de data aceasta
selectaţi în câmpul Save as type opţiunea Microsoft IIS 1-2.
Active Server Pages
Active Server Pages (pagini server active), succesorul lui IDC, este o
tehnologie de creare a paginilor dinamice, care afişează baza de date
în starea sa curentă. Spre deosebire de IDC, aceste pagini sunt
similare cu formularele, permiţând introducerea, editarea şi
ştergerea datelor dintr-o pagină Web. Datele pot proveni din orice
sursă ODBC, însă serverul Web trebuie să fie Internet Information
Server, de data aceasta cel puţin versiunea 3.0, având instalată
opţiunea Active Server Pages. Fişierele Active Server Pages sunt
înregistrate cu extensia .asp. spre deosebire de metoda IDC, care
creează două fişiere, metoda Active Server Pages creează un singur
fişier pentru fiecare foaie de date.
În fişierele ASP puteţi exporta tabele, interogări şi formulare.
Tabelele şi interogările sunt afişate ca foi de date, iar
formularele sunt afişate în format HTML, având un aspect similar cu
formularele din Access. Controalele din formular sunt înlocuite cu
controale ActiveX, însă codul VBA al formularului nu este convertit.
Pentru a poziţiona controalele în pagina HTML, Access foloseşte
controlul Microsoft HTML Layout. Acest program este distribuit
împreună cu Internet Explorer 3.0 sau o versiune ulterioară (şi
este disponibil în situl Web Microsoft), însă nu poate rula
independent. Prin urmare, pentru a crea pagini ASP aveţi nevoie de
Internet Explorer, cel puţin versiunea 3.0.
Lista următoare prezintă controalele Access care sunt înlocuite cu
controale ActiveX.
Controlul Access Controlul ActiveX corespunzător
Casetă de text Casetă de text
Casetă de text asociată unui câmp cu o hiperlegătură Casetă de
text care afişează textul hiperlegăturii. Cu toate acestea,
hiperlegătura nu poate fi urmărită.
Casetă cu listă Casetă cu listă (cu o singură coloană)
Casetă combinată Casetă combinată
Controlul Access Controlul ActiveX corespunzător
Etichetă Etichetă. Dacă eticheta are configurate proprietăţile
HyperlinkAddress şi/sau HyperlinkSubAddress, este creată o
hiperlegătură pentru etichetă.
Buton de comandă Buton de comandă, dar secvenţa de cod
corespunzătoare butonului nu este salvată. Dacă butonul de comandă
are configurate proprietăţile HyperlinkAddress şi/sau
HyperlinkSubAddress, este creată o hiperlegătură pentru buton.
Grup de opţiuni Grup de opţiuni, însă fără un cadru de grup
Buton de opţiune Buton de opţiune
Casetă de validare Casetă de validare
Buton comutator Buton comutator
Control ActiveX Control ActiveX, însă secvenţa de cod
corespunzătoare
controlului este salvată.
Următoarele controale nu sunt convertite la salvarea unui formular ca
fişier ASP şi, de aceea, sunt ignorate:
Controale Tab
Dreptunghiuri
Linii
Separatori de pagini
Cadre de obiecte neasociate
Cadre de obiecte asociate
Controale de imagine
Fundalurile de formulare configurate cu ajutorul proprietăţii
Picture
În ciuda acestor lipsuri, obţineţi un formular funcţional.
Pentru a salva datele într-un fişier ASP, folosiţi acceaşi metodă
ca mai înainte, însă de data aceasta, selectaţi în câmpul Save as
type opţiunea Microsoft Active Server Pages.
Executaţi clic pe butonul Export pentru a afişa pe ecran următoarea
casetă de dialog:
Şi aici există spaţii speciale pentru introducerea şablonului HTML
şi a informaţiilor despre sursa de date ODBC, însă apare şi un
câmp pentru adresa serverului, unde trebuie să introduceţi adresa
completă la care va fi stocat documentul. În exemplul nostru, este o
adresă la care este instalat Personal Web Server, care acceptă şi
paginile server active (Active Server Pages).
Dacă aţi salvat un formular, puteţi să deschideţi fereastra
aplicaţiei Internet Explorer 3.0 pentru a-l vizualiza:
Deşi nu este perfectă, această tehnică a permis parcurgerea unor
paşi importanţi în direcţia realizării unor aplicaţii pentru Web.
Crearea unui browser
Până acum, aţi văzut cât de uşor vă puteţi publica datele din
Access în sistemul Web; însă cum includeţi funcţii Web în
aplicaţiile dumneavoastră? Este un proces la fel de simplu, deoarece
firma Microsoft a realizat un control de navigare Web (Web Browser
Control) care poate fi adăugat în formularele dumneavoastră. Astfel,
formularele vor avea propriul browser şi nu veţi mai fi nevoit să
rulaţi unul separat. Oricum, pentru a folosi acest control, trebuie
să aveţi instalat produsul Internet Explorer 3.0 sau o versiune
ulterioară.
Încercaţi singur - Un browser Web
1. Deschideţi tabelul Company în modul de afişare pentru proiectare
(Design) şi adăugaţi un câmp nou, numit WebSite, de tip Hyperlink.
Salvaţi şi închideţi tabelul.
2. Deschideţi formularul frmMaintCompany în modul de afişare pentru
proiectare. Măriţi puţin dimensiunea formularului.
3. Selectaţi butonul More Controls (Alte controale) din caseta de
instrumente.
4. Acum derulaţi lista de constroale plasând cursorul pe săgeata din
partea de jos a formularului şi selectaţi opţiunea Microsoft Web
Browser Control.
5. Adăugaţi acest control în formularul dumenavoastră, aşa cum
procedaţi cu orice alt control. S-ar putea să fie necesară
redimensionarea formularului pentru a face loc noului control.
Denumiţi controlul ctlBrowser.
6. Adăugaţi un buton de comandă, denumiţi-l cmdWeb şi completaţi
titlul (Caption) View Web Page (Vizualizare pagină Web).
7. Editaţi codul pentru evenimentul Click al noului buton, adăugând
următoarea linie de cod:
Această instrucţiune foloseşte metoda Navigate a controlului
Browser pentru a naviga către hiperlegătură.
8. Închideţi formularul şi salvaţi-l.
9. Deschideţi tabelul Company şi adăugaţi următoarea adresă în
câmpul WebSite pentru produsul Bacchanalia:
Această adresă indică pagina iniţială a produsului Bacchanalia,
memorată local pe hard-discul calculatorului dumneavoastră.
10. Acum deschideţi formularul frmMaintCompany în modul de afişare
Form şi selectaţi înregistarea Bacchanalia; executaţi clic pe
butonul View Web Page. Browserul va afişa imediat pagina Web
corespunzătoare.
Din păcate, există o serie de probleme legate de controlul Browser
şi de Internet Explorer 3.0. Probabil aţi observat că dimensionarea
este inadecvată, astfel că paginile Web au un aspect necorespunzător
şi nu execută corect operaţia de împrospătare. Ar fi mult mai bine
dacă aţi indica un sit Web prin http, şi nu prin file. Aceste
neajunsuri sunt cunoscute şi sperăm că vor fi rezolvate curând.
Totuşi, controlul Web Browser poate vizualiza documente HTML care
includ:
Elemente HTML standard şi îmbunătăţiri HTML, cum ar fi cadrele
mobile şi foile afişate în cascadă
Alte controale ActiveX
Majoritatea produselor de completare Netscape
Scripturi, cum sunt Microsoft Visual Basic Scripting Edition
(VBScript) sau JavaScript
Elemente multimedia, de exemplu secvenţe audio şi video
Imagini virtuale tridimensionale create cu Virtual Reality Modeling
Language (VRML)
Documente Microsoft Office
Cred că acest control este mult mai util pentru aplicaţiile
intranet, care vă oferă posibilitatea de combinare a conţinutului.
Pentru cei care au deja aplicaţii Access, dar dezvoltă aplicaţii noi
bazate pe Internet/intranet, controlul Browser poate constitui un
sprijin important în trecerea la o aplicaţie combinată.
Rezumat
În acest capitol au fost prezentate câteva facilităţi oferite de
Access 97 pentru lucrul în Internet. Utilizarea pe scară largă a
Internetului în viaţa de zi cu zi şi interesul public general
constituie premise pentru dezvoltarea şi îmbunătăţirea unor astfel
de caracteristici.
Subiectele principale din acest capitol au fost:
Hiperlegăturile şi utilizarea lor în Access
Importul şi exportul documentelor HTML
Crearea unui browser Web în Access
Exerciţii
1. Scrieţi o procedură care creează săptămânal o listă HTML de
preţuri şi o copiază într-un sit Web.
2. Dacă aveţi acces la un server Web care rulează produsul Microsoft
Internet Information Server sau Microsoft Peer Web Services, creaţi un
fişier IDC pentru ca lista de preţuri să fie întotdeauna corectă.
CAP: 1. NOŢIUNI GENERALE DESPRE BAZE DE DATE 5
1.1 BAZĂ DE DATE. BAZE DE DATE RELAŢIONALE 5
1.1.1 Chei primare, chei secundare 5
1.1.2 Relaţii 6
1.1.3 Teoria normalizării 6
1.2 SISTEME DE GESTIUNE A BAZELOR DE DATE 7
1.2.1 Limbaje de interogare. SQL 8
1.3 MODELUL RELAŢIONAL 9
1.3.1. Scurtă descriere a modelului relaţional 9
1.3.2 Reguli de fidelitate ale bazelor de date 10
CAP:2. BAZE DE DATE, TABELE ŞI RELAŢII 14
2.1 CREAREA UNEI BAZE DE DATE 14
2.2. CREAREA TABELELOR 15
2.2.1 Crearea manuală a tabelelor 16
2.2.2 Datasheet View: avantaje 16
2.2.3 Design View: 17
2.2.4 Definirea coloanelor 18
2.2.5 Stabilirea proprietăţilor câmpurilor 19
2.2.6 Lookup wizard 20
2.2.7 Value List 23
2.2.8 Definirea cheilor primare şi a indecşilor 24
2.2.9 Crearea unei tabele folosind experţii Access. 26
2.3 STABILIREA RELAŢIILOR ÎNTRE TABELE 26
2.3.1. Fereastra Relationships 27
2.3.2 Crearea relaţiilor dintre tabele. 28
2.3.3 Proprietăţile relaţiilor 29
2.3.4. Tipuri de asociere 30
2.3.5 Asigurarea integrităţii referenţiale 31
2.3.6. Modificarea relaţiilor existente 32
2.4.1 Importul datelor 32
2.4.2 Exportul datelor 33
2.4.3. Formate standard 33
CAP:3. INTEROGĂRI 35
3.1. FOLOSIREA FERESTREI QBE 35
3.1.1. Specificarea surselor de date 35
3.1.2. Proprietăţile interogărilor 36
3.2. TIPURI DE INTEROGĂRI 39
3.2.1. Interogări agregat 39
3.2.2. Interogări de tip totals 39
3.2.2.1 Sortarea rezultatelor unei interogări de tip totals 41
3.2.2.2 Stabilirea criteriilor 42
3.2.3. Interogări de tip Crosstab 43
3.2.3.1 Crearea totalurilor pe linii 44
3.2.3.2 Limitările intergărilor Crosstab 45
3.2.4. Interogări pentru definirea şi modificarea datelor 46
3.2.4.1. Interogări de tip Make Table 46
3.2.5. Interogări de tip Append 47
3.2.6 Interogări de tip Update 47
3.2.7 Interogări de tip Delete 48
3.2.8 Interogări cu parametri 48
3.3. EXPRESII ŞI FUNCŢII ÎN INTEROGĂRI 48
3.3.1. Părţile componente ale expresiilor 48
Operatori 49
Constante 50
Funcţii 50
3.4. LUCRUL CU DATE ŞI ORE 51
3.5. FUNCŢIA IIF ÎN EXPRESII 53
3.6. STRATEGII DE PARCURGERE A TABELELOR DE BAZĂ 53
3.7. GREŞELI FRECVENTE 54
3.8. IMPORTANŢA COMPACTĂRII 54
CAP: 4. CREAREA ŞI LUCRUL CU FORMULARELE 55
4.1 SURSELE DE ÎNREGISTRĂRI ALE FORMULARELOR 55
4.2. CREAREA UNUI FORMULAR SIMPLU 56
4.3. SECŢIUNILE UNUI FORMULAR 58
4.4. LUCRUL CU FORMULARELE 59
4.5. DESPRE CONTROALE 61
4.5.1. Tipuri de controale 61
Controale neataşate 62
Controale ataşate 62
Controale calculate 62
4.5.2. Casete combinate, casete listă şi grupuri de opţiuni 62
4.6. SUBFORMULARE 66
CAP: 5. MODELUL ORIENTAT PE EVENIMENTE 68
5.1. TIPURI DE EVENIMENTE ÎN ACCESS 69
5.1.1. Evenimente generate de accesarea datelor 69
5.1.2. Evenimente legate de focus 70
5.1.3. Evenimente legate de tastatură 71
5.1.4. Evenimente legate de activitatea cu mouse-ul 72
5.1.5. Evenimente legate de tipărire 73
5.1.6. Evenimentele ferestrelor 73
5.1.7. Evenimente generate de erori 74
5.1.8. Evenimentele legate de timer 74
5.2. ORDINEA PRODUCERII EVENIMENTELOR ÎN ACCESS 74
5.2.1. Ordinea producerii evenimentelor legate de controale 74
5.2.2. Ordinea producerii evenimentelor legate de lucrul cu
înegistrările unui formular 75
5.2.3 Ordinea producerii evenimentelor legate de formulare 76
5.2.4. Ordinea producerii evenimentelor legate de tastatură şi
mouse 76
5.2.5. Ordinea producerii evenimentelor rapoartelor 77
5.3. TRATAREA EVENIMENTELOR 77
CAP:6. MACROCOMENZI 78
6.1. CREAREA UNEI MACROCOMENZI 78
6.2. GRUPURI DE MACROCOMENZI 79
6.3. MACROCOMENZI IMBRICATE 80
6.3.1. Condiţii în macrocomenzi 81
6.4. MACROCOMENZI SPECIALE 81
6.4.1. Macrocomanda AutoKeys 81
6.4.2. Macrocomanda AutoExec 83
6.5. Crearea meniurilor şi a barelor cu instrumente personalizate 84
6.6. Rularea şi depanarea macrocomenzilor 86
CAP:7. VISUAL BASIC FOR APPLICATIONS (VBA) 88
7.1 MEDIUL DE PROGRAMARE ACCESS 88
Ce conţin modulele 88
(General) 89
Opţiuni 89
Declaraţii (Declarations) 89
Proceduri pentru tratarea evenimentelor 90
7.2 PROCEDURI 90
7.2.1 Declararea procedurilor 90
7.2.2. Lucrul cu argumente opţionale 91
7.2.3. Funcţii predefinite 92
7.3. VARIABILE 92
7.3.1 Tipuri de date 92
7.3.2 Declararea variabilelor 93
7.3.2.2 Option Explicit 96
7.3.3 Constante 97
7.3.4 Vizibilitatea şi durata de viaţă a variabilelor 98
7.3.4.1 Variabile statice 99
7.3.4.2 Variabile publice 99
7.4. INSTRUCŢIUNI DE CONTROL 101
7.4.1 Instrucţiunea If…Then 102
7.4.2 Instrucţiunea If…Then…Else 103
7.4.3 Instrucţiunea ElseIf 104
7.4.4 Instrucţiunea Select Case 104
7.4.5 Instrucţiunea IIf (Immediate If) 105
7.5 INSTRUCŢIUNI ITERATIVE 106
7.5.1 Instrucţiunea For…Next 106
7.5.2 Instrucţiunea Do…Loop 107
7.5.3 Întreruperea iterării 108
7.6 MATRICE 108
7.6.1 Matrice statice 108
Indici 110
7.6.2 Matrice dinamice 110
7.6.3 Detectarea matricelor 111
7.6.4 Matrice multidimensionale 113
7.6.4.1 Matrice multidimensionale dinamice 113
7.6.4.2 Accesarea componentelor unei matrice multidimensionale 114
7.6.5 Ştergerea matricelor dinamice 115
7.6.6 Folosirea matricelor ca parametri pentru proceduri 116
7.7 Lucrul cu biblioteci DLL şi cu funcţii Windows API 116
7.7.1 Declararea funcţiilor API 117
7.7.1.1 Domeniul de vizibilitate al funcţiei API 117
7.7.1.2 Denumirea funcţiei API 118
7.7.1.3 Specificarea bibliotecii DLL 118
7.7.1.4 Clauza Alias 118
7.7.1.5 Argumente 118
CAP:8. LUCRUL CU OBIECTE 122
Proprietăţi 122
Metode 122
Clase 122
8.1 OBIECTELE DIN ACCESS 97 123
Application 123
Container 123
8.1.1 Colecţii 124
Obiectul DBEngine (motorul Jet Engine) 126
Colecţia Errors (Erori) 127
Colecţia Workspaces (Sesiuni de lucru) 127
Colecţia Databases (Baze de date) 127
Colecţia Users (Utilizatori) 127
Colecţia Groups (Grupuri) 127
Colecţia QueryDefs (Interogări) 127
Colecţia TableDefs (Tabele) 127
Colecţia Indexes (Indecşi) 128
Colecţia Fields (Câmpuri) 128
Colecţia Recordsets (Seturi de înregistrări) 128
Colecţia Relations (Relaţii) 128
Colecţia Parameters (Parametri) 128
Colecţia Properties (Proprietăţi) 128
8.1.2 Containere şi documente 128
8.2 LUCRUL CU VARIABILE DE TIP OBIECT 129
Când folosim semnul exclamării (!) şi când punctul (.) 131
8.3 COLECŢII IMPLICITE 131
Container 132
8.4 LUCRUL CU PROPRIETĂŢILE OBIECTELOR 132
8.4.1 Tipuri de proprietăţi 132
8.4.2. Accesul la proprietăţi 132
8.4.3. Stabilirea proprietăţilor 133
8.5. CREAREA ŞI MANIPULAREA OBIECTELOR CU DAO 133
8.5.1. Crearea obiectelor 133
8.5.1.1. Crearea unei tabele 135
8.5.1.2 Crearea unui index 135
8.5.1.3 Crearea unei relaţii 138
8.5.1.4. Crearea proprietăţilor-utilizator 139
8.5.2. Modificarea obiectelor 139
8.6. OBIECTE DEFINITE DE UTILIZATOR 140
8.6.1. Proprietăţile şi metodele obiectului 140
8.6.2 Crearea instanţelor obiectului 143
8.6.3. Durata de viaţă a obiectelor 144
8.7 LUCRUL CU OBIECTE DE TIP RECORDSET 144
8.7.1. Tipuri de seturi de înregistrări 146
8.7.1.1. Seturi de înregistrări de tip tabelă 147
8.7.1.2. Seturi de înregistrări de tip dynaset 147
8.7.1.3. Seturi de înregistrări de tip snapshot 147
8.7.2. Actualizarea datelor unui set de înregistrări 148
8.7.3. Parcurgerea seturilor de înregistrări 148
8.7.4. Regăsirea numărului de înregistrări ale unui set de
înregistrări 148
8.7.5. Poziţia absolută şi poziţia procentuală 149
8.7.6. Poziţiile de început şi de sfârşit ale setului de
înregistrări (BOF şi EOF) 150
8.7.7. Regăsirea valorilor câmpurilor unui set de înregistrări 150
8.7.8. Căutarea înregistrărilor 152
8.7.8.1. Căutări în seturi de înregistrări de tip tabelă 152
8.7.8.2. Căutări în seturi de înregistrări de tip dynaset şi
snapshot 153
8.7.8.3. Criterii ce conţin şiruri de caractere şi date 154
8.7.9 Semne de carte 156
8.7.10 Metoda Clone (clonare) 157
8.7.11 Proprietatea RecordsetClone 157
8.7.12 Sortarea şi filtrarea unui set de înregistrări 158
8.7.13 Editarea înregistrărilor unui set de înregistrări 160
8.7.13.1. Modificarea înregistrării curente 160
8.7.13.2 Adăugarea unei noi înregistrări la un set de
înregistrări 161
8.7.13.3 Ştergerea unei înregistrări a unui set de
înregistrări 161
8.8. OBIECTE SPECIALE 162