Modul de Realizare Si Utilizare a Unei Aplicatii de Tip Gestiune Intr O Policlinica

CUPRINS

INTRODUCERE

CAPITOLUL I – ASPECTE TEORETICE

1.1 Limbajul Java. Noțiuni de bază

1.2 Interfața grafică cu utilizatorul

1.3 Lucru cu baze de date în Java

CAPITOLUL II – MODUL DE REALIZARE A APLICAȚIEI

2.1 Proiectarea aplicației pe baza cerințelor

2.2 Baza de date

2.3 Ferestrele aplicației

2.4 Calendarul

2.5 Rapoarte

2.6 Blocarea de ore sau zile

CAPITOLUL III – MODUL DE UTILIZARE A APLICAȚIEI

3.1. Meniul Programări

3.2. Meniul Încasări

3.3. Meniul Evidențe

3.4. Meniul Ore blocate

BIBLIOGRAFIE

INTRODUCERE

Domeniul medical este unul dintre cele mai importante pentru dezvoltarea și prosperare economiilor și țărilor. Pe fondul descoperirilor ca urmare a cercetarii în domeniu, sectorul medical a cunoscut în ultimii ani o creștere semnificativă a calității serviciilor medicale.

Informatica medicală susține ritmul accelerat de dezvoltare și ajută persoanele implicate prin metode moderne de asistență și îndrumare în procese.

Astfel, informatica medicală se ocupă cu obținerea și mentenanța resurselor, dispozitivelor și metodelor necesare pentru a optimiza achiziționarea, stocarea, recuperarea și utilizarea de informații în domeniul sănătății și biomedicinei în zonele de asistență și îngrijire medicală, stomatologie, farmacie, cercetare și asigurare medicală obligatorie.

În această lucrare este prezentat modul de realizare și utilizare a unei aplicații de tip gestiune într-o policlinică. Aspectele vizate țin în mare măsură de operațiile de programare și încasare a pacienților.

Aplicația a fost realizată cu ajutorul limbajului de programare Java, iar baza de date este de tip MySql.

Modul de realizare al aplicației este conform cerințelor unei policlinici private existente, ținând astefel cont de cerințele și necesitățile acesteia. De menționat faptul că s-a dorit realizarea unei aplicații care să îi afere clinicii exact ceea ce are nevoie, menținându-se un nivel cât mai simplu de utilizare a aplicației.

Aplicația nu este neapărat una complexă, dispune de aproximativ 17 posibile operații, este realizată folosind o interfață grafică cât mai simplă și mai plăcută.

Baza de date nu este nici ea foarte complexă, conținând date despre programări, încasări și medicii din cadrul policlinicii.

Este de menționat faptul că alegerea limbajului Java pentru realizarea aplicației a ținut cont de faptul că acest limbaj nu necesită licență și este independent de platforma pe care rulează. După cum se va detalia și în cadrul prezentei lucrării, aceste aspecte pozitive atrag dupa ele și unele negativ, care ar face în alte situații să se aleagă de exemplu un limbaj dedicat platformei Windows (cum ar fi de exemplu Microsoft Access) care are încorporate facilități pe care Java nu le are și care trebuiesc create de către programator (cum ar fi de exemplu rapoartele).

CAPITOLUL I – ASPECTE TEORETICE

1.1 Limbajul Java. Noțiuni de bază

Java este un limbaj de programare orientat-obiect, puternic tipizat, conceput de către James Gosling la Sun Microsystems (acum filială Oracle) la începutul anilor ’90, fiind lansat în 1995.

Limbajul împrumută o mare parte din sintaxă de la C și C++, dar are un model al obiectelor mai simplu și prezintă mai puține facilități de nviel jos. Un program Java compilat, corect scris, poate fi rulat fără modificări pe orice platformă care e instalată o mașină virtuală Java (engleză Java Virtual Machine, prescurtat JVM). Acest nivel de portabilitate (inexistent pentru limbaje mai vechi cum ar fi C) este posibil deoarece sursele Java sunt compilate într-un format standard numit cod de octeți (engleză byte-code) care este intermediar între codul mașină (dependent de tipul calculatorului) și codul sursă.

Mașina virtuală Java (JVM) este mediul în care se execută programele Java. În prezent, există mai mulți furnizori de JVM, printre care Sun, IBM, Bea, Oracle, FSF. În 2006, Sun a anunțat că face disponibilă varianta sa de JVM ca open-source.

Există 3 platforme Java furnizate de Sun Microsystems:

Java Platform, Micro Edition (Java ME) — pentru hardware cu resurse limitate, gen PDA sau telefoane mobile

Java Platform, Standard Edition (Java SE) — pentru sisteme gen workstation, este ceea ce se gaseste pe PC-uri

Java Platform, Enterprise Edition (Java EE) — pentru sisteme de calcul mari, eventual distribuite.

În ceea ce privește Java SE, este în lucru varianta Java JDK 7.

Pe data de 27 ianuarie 2010, Oracle anunța că a finalizat preluarea firmei Sun Microsystems. Oracle anunța că va asigura în continuare dezvoltarea produselor Sun cum ar fi SPARC, Solaris, Java și MySQL.

Dintre caracteristicile principale ale limbajului amintim: simplitate, elimina supraincarcarea operatorilor, mostenirea multipla și toate "facilitatile" ce pot provoca scrierea unui cod confuz; robustete; elimina sursele frecvente de erori ce apar in programare prin eliminarea pointerilor, administrarea automata a memoriei și eliminarea fisurilor de memorie printr-o procedura de colectare a 'gunoiului' care ruleaza in fundal. Complet orientat pe obiecte – elimină complet stilul de programare procedural; usurință în ceea ce privește programarea în rețea securitate (este cel mai sigur limbaj de programare disponibil in acest moment), asigurând mecanisme stricte de securitate a programelor concretizate prin: verificarea dinamică a codului pentru detectarea secvențelor periculoase, impunerea unor reguli stricte pentru rularea programelor lansate pe calculatoare aflate la distanță, etc; este neutru din punct de vedere arhitectural; portabililtate, cu alte cuvinte Java este un limbaj independent de platforma de lucru, aceeași aplicație rulând, fără nici o modificare pe sisteme diferite cum ar fi Windows, UNIX sau Macintosh, lucru care aduce economii substanțiale firmelor care dezvoltă aplicații pentru Internet; compilat și interpretat; asigură o performanță ridicată a codului de octeți; permite programarea cu fire de execuție (multitheaded).

La baza conceptului de programare orientată obiect stau clasele și obiectele.

Clasa grupează datele și unitățile de prelucrare a acestora într-un modul, unindu-le astfel într-o entitate mult mai naturală. Deși tehnica se numește "programare orientată pe obiecte", conceptul de bază al ei este clasa. Aceasta, pe lângă faptul că abstractizează foarte mult analiza/sinteza problemei, are proprietatea de generalitate, ea desemnând o mulțime de obiecte care împart o serie de proprietăți. Odată identificate entitățile (în speță clasele) ele nu rămân izolate; ele vor fi grupate în module, pachete, programe, etc., care vor stabili legături între ele. Aceste legături reflectă relațiile care se stabilesc între clasele/obiectele problemei pe care am preluat-o din natură.

Clasele reprezintă o modalitate de a introduce noi tipuri de date într-o aplicație Java, cealaltă modalitate fiind prin intermediul interfețelor. Declararea unei clase respectă următorul format general:

[modificatori clasa] class NumeClasa

[extends NumeSuperclasa]

[implements Interfata1 [, Interfata2 … ]]

{

// Corpul clasei

}

Corpul unei clase urmează imediat după declararea clasei și este cuprins între acolade. Conținutul acestuia este format din:

• Declararea și, eventual, inițializarea variabilelor de instanță și de clasă (cunoscute împreună ca variabile membre).

• Declararea și implementarea constructorilor.

• Declararea și implementarea metodelor de instanța și de clasă (cunoscute împreună ca metode membre).

• Declararea unor clase imbricate (interne).

Spre deosebire de alte limbaje de programare orientate-obiect, Java permite doar moștenirea simplă, ceea ce înseamnă că o clasă poate avea un singur părinte (superclasă). Evident, o clasă poate avea oricâti moștenitori (subclase), de unde rezultă că mulțimea tuturor claselor definite în Java poate fi vazută ca un arbore, rădăcina acestuia fiind clasa Object. Așadar, Object este singura clasă care nu are părinte, fiind foarte importantă în modul de lucru cu obiecte și structuri de date în Java. O subclasă moștenește de la părintele său toate variabilele și metodele care nu sunt private.

Crearea obiectelor se realizează prin instanțierea unei clase și implică următoarele lucruri:

• Declararea: Presupune specificarea tipului acelui obiect, cu alte cuvinte specificarea clasei acestuia (vom vedea că tipul unui obiect poate fi și o interfață).

NumeClasa numeObiect;

• Instanțierea: Se realizează prin intermediul operatorului new și are ca efect crearea efectivă a obiectului cu alocarea spațiului de memorie corespunzător.

numeObiect = new NumeClasa();

• Inițializarea: Se realizează prin intermediul constructorilor clasei respective. Inițializarea este de fapt parte integrantă a procesului de instanțiere, în sensul că imediat după alocarea memoriei ca efect al operatorului new este apelat constructorul specificat.

Mai general, instanțierea și inițializarea apar sub forma:

numeObiect = new NumeClasa([argumente constructor]);

Odată un obiect creat, el poate fi folosit în următoarele sensuri: aflarea unor informații despre obiect, schimbarea stării sale sau executarea unor acțiuni. Aceste lucruri se realizeaza prin aflarea sau schimbarea valorilor variabilelor sale, respectiv prin apelarea metodelor sale. Referirea valorii unei variabile se face prin obiect.variabila.

1.2 Interfața grafică cu utilizatorul

Interfața grafică cu utilizatorul (GUI), este un termen cu înțeles larg care se referă la toate tipurile de comunicare vizuală între un program și utilizatorii săi. Aceasta este o particularizare a interfeței cu utilizatorul (UI), prin care vom întelege conceptul generic de interacțiune dintre program și utilizatori.

Limbajul Java pune la dispoziție numeroase clase pentru implementarea diverselor funcționalitati UI, însă ne vom ocupa în continuare de cele care permit realizarea intefeței grafice cu utilizatorul (GUI).

De la apariția limbajului Java, bibliotecile de clase care oferă servicii grafice au suferit probabil cele mai mari schimbări în trecerea de la o versiune la alta. Acest lucru se datorează, pe de o parte dificultății legate de implementarea noțiunii de portabilitate, pe de altă parte nevoii de a integra mecanismele GUI cu tehnologii apărute și dezvoltate ulterior, cum ar fi Java Beans. În momentul actual, există două modalități de a crea o aplicație cu interfață grafică și anume:

• AWT (Abstract Windowing Toolkit) – este API-ul inițial pus la dispoziție începând cu primele versiuni de Java;

• Swing – parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) creat în urma colaborării dintre Sun, Netscape și IBM, Swing se bazează pe modelul AWT, extinzând funcționalitatea lui și adăugând sau înlocuind componente pentru dezvoltarea aplicațiilor GUI.

În principiu, crearea unei aplicații grafice presupune următoarele lucruri:

• Design:

– Crearea unei suprafețe de afișare (cum ar fi o fereastră) pe care vor fi așezate obiectele grafice (componente) care servesc la comunicarea cu utilizatorul (butoane, controale pentru editarea textelor, liste, etc);

– Crearea și așezarea componentelor pe suprafața de afișare la pozițiile corespunzătoare;

• Funcționalitate:

– Definirea unor acțiuni care trebuie să se execute în momentul când utilizatorul interacționează cu obiectele grafice ale aplicației;

– ”Ascultarea” evenimentelor generate de obiecte în momentul interacțiunii cu utilizatorul și executarea acțiunilor corespunzătoare, așa cum au fost ele definite.

1.2.1 Suprafețe de afișare

Crearea obiectelor grafice nu realizează automat și afișarea lor pe ecran. Mai întâi ele trebuie așezate pe o suprafață, care poate fi o fereastră sau suprafața unui applet, și vor deveni vizibile în momentul în care suprafața respectivă va fi vizibilă. O astfel de suprafața pe care sunt plasate componentele se numește suprafață de afișare sau container și reprezintă o instanța a unei clase derivată din Container. Clasa Container este o subclasă aparte a lui Component, fiind la rândul ei superclasa tuturor fișare

Crearea obiectelor grafice nu realizează automat și afișarea lor pe ecran. Mai întâi ele trebuie așezate pe o suprafață, care poate fi o fereastră sau suprafața unui applet, și vor deveni vizibile în momentul în care suprafața respectivă va fi vizibilă. O astfel de suprafața pe care sunt plasate componentele se numește suprafață de afișare sau container și reprezintă o instanța a unei clase derivată din Container. Clasa Container este o subclasă aparte a lui Component, fiind la rândul ei superclasa tuturor suprafetelor de afișare Java.

O parte din clasele a căror părinte este Container este prezentată mai jos:

• Window – este superclasa tututor ferestrelor. Din această clasă sunt derivate:

– Frame – ferestre standard;

– Dialog – ferestre de dialog modale sau nemodale;

• Panel – o suprafață fără reprezentare grafică folosită pentru gruparea altor componente. Din această clasă derivă Applet, folosită pentru crearea appleturilor.

• ScrollPane – container folosit pentru implementarea automată a derulării pe orizontală sau verticală a unei componente.

1.2.2 Gestionarea poziționării

Un gestionar de poziționare (layout manager) este un obiect care controlează dimensiunea și aranjarea (poziția) componentelor unui container.

Așadar, modul de aranjare a componentelor pe o suprafața de afișare nu este o caracteristică a containerului. Fiecare obiect de tip Container (Applet, Frame, Panel, etc.) are asociat un obiect care se ocupă cu dispunerea componentelor pe suprafața sa și anume gestionarul său de poziționare.

Sunt însă situații când dorim să plasăm componentele la anumite poziții fixe iar acestea să ramâna acolo chiar dacă redimensionăm containerul. Folosind un gestionar această poziționare absolută a componentelor nu este posibilă și deci trebuie cumva să renunțăm la gestionarea automată a containerul. Acest lucru se realizează prin trimitera argumentului null metodei setLayout.

La instanțierea unui container se creează implicit un gestionar de poziționare asociat acestuia. De exemplu, pentru o fereastră gestionarul implict este de tip BorderLayout, în timp ce pentru un panel este de tip FlowLayout.

Cei mai utilizați gestionari de poziționare din pachetul java.awt sunt:

• FlowLayout: așează componentele pe suprafața de afișare în flux liniar, mai precis, componentele sunt adăugate una după alta pe linii, în limita spațiului disponibil. În momentul când o componentă nu mai încape pe linia curentă se trece la următoarea linie, de sus în jos. Adăugarea componentelor se face de la stânga la dreapta pe linie, iar alinierea obiectelor în cadrul unei linii poate fi de trei feluri: la stânga, la dreapta și pe centru.

• BorderLayout: împarte suprafața de afișare în cinci regiuni, corespunzătoare celor patru puncte cardinale și centrului. O componentă poate fi plasată în oricare din aceste regiuni, dimeniunea componentei fiind calculata astfel încât să ocupe întreg spațiul de afișare oferit de regiunea respectivă. Pentru a adăuga mai multe obiecte grafice într-una din cele cinci zone, ele trebuie grupate în prealabil într-un panel, care va fi amplasat apoi în regiunea dorită. La adăugarea unei componente pe o suprafață gestionată de BorderLayout, metoda add va mai primi pe lânga referința componentei și zona în care aceasta va fi amplasată, care va fi specificată prin una din constantele clasei: NORTH, SOUTH, EAST, WEST, CENTER. BorderLayout este gestionarul implicit pentru toate containerele care descind din clasa Window, deci al tuturor tipurilor de ferestre.

• GridLayout: organizează containerul ca un tabel cu rânduri și coloane, componentele fiind plasate în celulele tabelului de la stânga la dreapta, începând cu primul rând. Celulele tabelului au dimensiuni egale iar o componentă poate ocupa doar o singură celulă.

• CardLayout: tratează componentele adăugate pe suprafața sa într-o manieră similară cu cea a dispunerii cărților de joc într-un pachet. Suprafața de afișare poate fi asemănată cu pachetul de cărți iar fiecare component ă este o carte din pachet. La un moment dat, numai o singură componentă este vizibilă (”cea de deasupra”).

• GridBagLayout: Este cel mai complex și flexibil gestionar de poziționare din Java. La fel ca în cazul gestionarului GridLayout, suprafața de afișare este considerată ca fiind un tabel însă, spre deosebire de acesta, numărul de linii și de coloane sunt determinate automat, în funcție de componentele amplasate pe suprafața de afișare. De asemenea, în funcție de componentele gestionate, dimensiunile celulelor pot fi diferite cu singurele restricții ca pe aceeași linie să aibă aceeași înălțime, iar pe coloană aibă aceeași lățime. Spre deosebire de GridLayout, o componentă poate ocupa mai multe celule adiacente, chiar de dimensiuni diferite, zona ocupată fiind referită prin ”regiunea de afișare” a componentei respective.

1.2.3 Componentele Swing

Toate componentele Swing sunt definte de clase proprii ce se găsesc în pachetul javax.swing, clasa JComponent fiind superclasa abstractă a tuturor acestor clase.

• JButton – butoane cu eticheta formată dintr-un text pe o singură linie;

• JCheckBox – componentă ce poate avea două stări; mai multe obiecte de acest tip pot fi grupate folosind clasa JCheckBoxGroup;

• JComboBox – liste în care doar elementul selectat este vizibil și care se deschid la apăsarea lor;

• JLabel – etichete simple ce pot conține o singură linie de text needitabil;

• JList – liste în care toate elementele sunt vizibile, cu selecție simplă sau multiplă;

• JTextField – casete de text (pe o singură linie) și JTextArea (pe mai multe linii).

• JTable – Clasă care folosește la afișarea datelor sub formă tabelară, opțional permițând și modificarea datelor.

Frecvent, pentru a crea un tabel este nevoie de datele pe care le va conține (reprezentate într-o matrice) și de un vector de tip String care va conține numele coloanelor tabelului.

Exemplu:

Object data[][] = … ;

String antet[] = …

JTable tabel = new JTable(data, antet);

Mai există și alte variante de contructori pentru JTable, însă cea de mai sus este mai des întâlnită.

Modul în care sunt reprezentate datele în tabel este dat de modelul tabelului. Implicit un JTable folosește clasa DefaultTableModel, însă este posibil să se creeeze și clase personalizate, prin implementarea interfeței TableModel. Deobicei, o clasă creată de utilizator în aceste sens va fi o subclasă a clasei AbstractTableModel.

Lățimea coloanelor: Implicit, toate coloanele tabelului au aceeași lățime. În momentul în care utilizatorul modifică manual lățimea unei coloane, toate coloanele din dreapta acesteia se modifică.

Pentru a seta manual lățimea inițială a coloanelor, trebuie apelată metoda setPreferredWidth() pentru fiecare coloană. În acest caz, fiecare coloană va fi reprezentată de un obiect de tip TableColumn.

Exemplu:

TableColumn column = null;

for (int i = 0; i < 5; i++) {

column = table.getColumnModel().getColumn(i);

if (i == 2) {

column.setPreferredWidth(100); //a treia coloană

} else {

column.setPreferredWidth(50);

}

}

Selectarea elementelor din tabel: Implicit, utilizatorul poate selecta una sau mai multe rânduri din tabel. În cazul selecției multiple, rândurile pot și continue sau nu.

Pentru a selecta un singur rând se poate face click cu mouse-ul undeva în cadrul acestuia sau se poate deplasa cu săgețile sus/jos de pe tastatură.

Pentru a selecta o zonă continuă sau arbitrară de mai multe rânduri se procedează în stilul clasic, folosind tasta Shift pentru o zonă continuă de rânduri sau tasta Ctrl pentru o zonă arbitrară de rânduri.

Pentru a seta unul din modul de selecție a rândurilor se va apela metoda setSelectionMode() cu unul din parametrii: MULTIPLE_INTERVAL_SELECTION,  SINGLE_INTERVAL_SELECTION sau SINGLE_SELECTION.

Lucrurile sunt similare și pentru cazul selecției coloanelor.

Rendere:

Un tabel folosește un renderer pentru toate celulele care conțin același tip de date. Astfel, toate acele celule vor fi afișate unitar.

Sunt câteva moduri predefinite de afișare a datelor în celule după cum urmează:

tipul Boolean este afișat ca și Checkbox

tipurile numerice sunt afișate aliniat la dreapta

tipul Date este afișat folosind o instanță a clasei DateFormat pentru formatarea datei

tipurile ImageIcon, Icon sunt afișate aliniat centrat

tipul Object este afișat aliniat la stânga sub formă de String

În mod implicit, toate coloanele tabelului sunt considerate a fi de tip Object.

Modul de afișare a datelor în celule poate fi personalizat prin crearea de noi rendere. Acest lucru se realizează prin extinderea clasei DefaultTableCellRenderer sau implementarea interfeței TableCellRenderer.

Sortarea datelor dintr-un tabel: Pentru a permite sortarea datelor dintr-un tabel este nevoie de un obiect sorter care este o instanță a clasei TableRowSorter. Acest lucru se poate realiza apelând pentru un tabel metoda autoCreateRowSorter(true). Prin aceasta se obține faptul că atunci când utilizatorul va face click pe o coloană din antetul tabelului, acesta va fi sortat crescător sau descrescător după elementele din acea coloană.

Există și modalități mai sofisticate de sortare a datelor, însă nu le vom detalia în această lucrare.

Listarea la imprimantă a tabelelor: JTable pune la dispoziție un API simplu pentru listarea tabelelor. Practic pentru un anumit tabela se va apela metoda print().

Exemplu:

try {

if (!table.print()) {

System.err.println("Utilizator a anulat listarea");

}

} catch (java.awt.print.PrinterException e) {

System.err.format("Nu se poate lista %s%n", e.getMessage());

}

La rularea unui astfel de cod se va deschide o fereastră standard de listare la imprimantă.

Pe lângă această variantă simplă de listare mai există și altele, cum ar fi setarea unui antet pentru pagină.

Exemplu:

MessageFormat header = new MessageFormat("Page {0,number,integer}");

try {

table.print(JTable.PrintMode.FIT_WIDTH, header, null);

} catch (java.awt.print.PrinterException e) {

System.err.format("Cannot print %s%n", e.getMessage());

}

Pentru setări mai complexe ale listării se va personaliza un obiect de tip Printable obținut prin apelarea metodei JTable.getPrintable().

1.2.4 Tratarea evenimentelor

Un eveniment este produs de o acțiune a utilizatorului asupra unei componente grafice și reprezintă mecanismul prin care utilizatorul comunică efectiv cu programul. Exemple de evenimente sunt: apăsarea unui buton, modificarea textului într-un control de editare, închiderea sau redimensionarea unei ferestre, etc. Componentele care generează anumite evenimente se mai numesc și surse de evenimente.

Interceptarea evenimentelor generate de componentele unui program se realizează prin intermediul unor clase de tip listener (ascultător, consumator de evenimente). În Java, orice obiect poate ”consuma” evenimentele generate de o anumită componentă grafică.

Așadar, pentru a scrie cod care să se execute în momentul în care utilizatorul interactionează cu o componentă grafică trebuie să facem următoarele lucruri:

• să scriem o clasă de tip listener care să ”asculte” evenimentele produse de acea componentă și în cadrul acestei clase să implementăm metode specifice pentru tratarea lor;

• să comunicăm componentei sursă că respectiva clasa îi ”ascultă” evenimentele pe care le generează, cu alte cuvinte să înregistrăm acea clasă drept ”consumator” al evenimentelor produse de componenta respectivă.

Pentru ca evenimentele unei componente să fie interceptate de către o instanță a unei clase ascultător, această clasă trebuie înregistrata în lista ascultătorilor componentei respective. Inregistrarea unei clase în lista ascultătorilor unei componente se face cu metode din clasa Component de tipul addTipEvenimentListener, iar eliminarea ei din această listă cu removeTipEvenimentListener.

Tipuri de evenimente

Evenimentele se împart în două categorii: de nivel jos și semantice.

Evenimentele de nivel jos reprezintă o interacțiune de nivel jos cum ar fi o apăsare de tastă, mișcarea mouse-ului, sau o operație asupra unei ferestre.

În tabelul de mai jos sunt enumerate clasele ce descriu aceste evenimente și operațiunile efectuate (asupra unei componente) care le generează:

O anumită acțiune a utilizatorului poate genera mai multe evenimente. De exemplu, tastarea literei ’A’ va genera trei evenimente: unul pentru apăsare, unul pentru eliberare și unul pentru tastare. În funcție de necesitățile aplicației putem scrie cod pentru tratarea fiecărui eveniment în parte.

Evenimentele semantice reprezintă interacțiunea cu o componentă GUI: apăsarea unui buton, selectarea unui articol dintr-o listă, etc.

Clasele care descriu aceste tipuri de evenimente sunt:

Următorul tabel prezintă componentele AWT și tipurile de evenimente generate, prezentate sub forma interfețelor corespunzătoare.

1.2.5 Meniuri

Elementele care pot constitui un meniu în Swing sunt: bara de meniu, meniuri, itemi de meniu, butoane radio, checkbox-uri și linii separatoare. În dreptul textului dintr-un item de meniu poate apărea și o imagine. Pot exista submeniuri care se vor deschide din cadrul unui item de meniu. Orice meniu sau item de meniu poate avea atașată o tastă fierbinte (Alt+literă, Ctrl+literă) pentru accesul rapid.

Exemplu de meniu cu diverse elemente:

Mai există și o variantă aparte a meniurilor, numite meniuri de tip popup, care apar pe suprafața de afișare în locul în care utilizatorul face click dreapta cu mouse-ul.

Ierarhia claselor care descriu meniurile este următoarea:

Ce se poate remarca din această ierarhie este faptul că itemi de meniu provin defapt din butoane, deci vor fi tratați ca și atare, inclusiv la partea de evenimente care vor fi tot de tip ActionEvent, interceptate de ActionListener ca și în cazul butoanelor.

Exemplu de setare a unei taste fierbinți (mnemonic):

//Setarea tastei la crearea item-ului de meniu:

menuItem = new JMenuItem("Un item", KeyEvent.VK_U);

// Setarea tastei dupa creare:

menuItem.setMnemonic(KeyEvent.VK_U);

//Setarea combinatiei de taste (accelerator):

menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U,

ActionEvent.ALT_MASK));

La rularea acestui cod se va obține un item de meniu cu numele Un item care va putea fi accesat cu combinația de taste Alt+U. Pentru a accesa item-ul cu combinația Ctrl+tasta se va folosi CTRL_MASK.

După crearea completă a unui meniu, acesta va fi plasat pe suprafața de afișare apelând pentru aceasta metoda setJMenuBar(menuBar).

1.2.6 Culori și imagini

Orice culoare este formată prin combinația culorilor standard roșu (red), verde (green) și albastru (blue), la care se adaugă un anumit grad de transparență (alpha). Fiecare din acești patru parametri poate varia într-un interval cuprins fie între 0 și 255 (dacă dorim să specificăm valorile prin numere întregi), fie între 0.0 și 1.0 (dacă dorim să specificăm valorile prin numere reale). Valoarea 255 (sau 1.0) pentru transparență specifică faptul că respectiva culoare este complet opacă, iar valoarea 0 (sau 0.0) specifică transparență totală. Implicit, culorile sunt complet opace.

Pentru a crea o culoare avem două posibilități: să folosim una din constantele definite în cele două clase; sau să folosim unul din constructorii clasei Color.

Putem crea noi culori prin intermediul constructorilor clasei Color:

Color(float red, flot green, float blue)

Color(flot red, float green, float blue, float alpha)

Color(int red, int green, int blue)

Color(int red, int green, int blue, int alpha)

Color(int rgb)

Parametrul ”rgb” de la ultimul constructor reprezintă un întreg format din biții: 16-23 pentru roșu, 8-15 pentru verde, 0-7 pentru albastru.

Afișarea unei imagini presupune realizarea următoarilor doi pași:

1. Crearea unui obiect de tip Image;

2. Afișarea propriu-zisă într-un context grafic;

Crearea unui obiect de tip Image se face folosind o imagine dintr-un fișier fie aflat pe mașina pe care se lucrează, fie aflat la o anumită adresă Web (URL). Metodele pentru încărcarea unei imagini dintr-un fișier se găsesc în clasele Applet și Toolkit, având însă aceeași denumire getImage().

Pentru a obține un obiect de tip Toolkit se va folosi metoda getDefaultToolkit, ca în exemplul de mai jos:

Toolkit toolkit = Toolkit.getDefaultToolkit();

Image image1 = toolkit.getImage("poza.gif");

Metoda getImage() nu verifică dacă fișierul sau adresa specificata reprezintă o imagine validă și nici nu încarcă efectiv imaginea în memorie, aceste operațiuni fiind făcute abia în momentul în care se va realiza afișarea imaginii pentru prima dată. Metoda nu face decât să creeze un obiect de tip Image care face referință la o anumită imagine externă.

Afișarea unei imagini într-un context grafic se realizează prin intermediul metodei drawImage din clasa Graphics și, în general, va fi făcută în metoda paint() a unei componente.

Cele mai uzuale formate ale metodei sunt:

boolean drawImage(Image img, int x, int y, ImageObserver observer)

boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer)

boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)

boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)

unde:

• img este obiectul ce reprezintă imaginea;

• x, y sunt coordonatele stânga-sus la care va fi afișată imaginea, relative la spațiul de coordonate al contextului grafic;

• observer este un obiect care ”observă” încărcarea imaginii și va fi informat pe măsura derulării acesteia;

• width, heigth reprezintă înalțimea și lățimea la care trebuie scalată imaginea (dacă lipsesc, imaginea va fi afișată la dimensiunile ei reale);

• bgColor reprezintă culoarea cu care vor fi colorați pixelii transparenți ai imaginii (poate să lipsească).

1.3 Lucru cu baze de date în Java

În Java există JDBC (Java Database Connectivity) care este o interfață standard SQL de acces la baze de date. JDBC este constituită dintr-un set de clase și interfețe scrise în Java, furnizând mecanisme standard pentru proiectanții aplicațiilor ce folosesc de baze de date.

Folosind JDBC este ușor să transmitem secvențe SQL către baze de date relaționale. Cu alte cuvinte, nu este necesar să scriem un program pentru a accesa o bază de date Oracle, alt program pentru a accesa o bază de date Sybase și asa mai departe. Este de ajuns să scriem un singur program folosind API-ul JDBC și acesta va fi capabil să comunice cu drivere diferite, trimițând secvențe SQL către baza de date dorită. Bineînțeles, scriind codul sursă în Java, ne este asigurată portabilitatea programului.

Pachetele care oferă suport pentru lucrul cu baze de date sunt java.sql ce reprezintă nucleul tehnologiei JDBC.

În linii mari, API-ul JDBC oferă următoarele facilități:

1. Stabilirea unei conexiuni cu o bază de date.

2. Efectuarea de secvențe SQL.

3. Prelucrarea rezultatelor obținute.

1.3.1 Conectarea la o bază de date

Procesul de conectare la o baza de date implică efectuarea a două operații:

1. Inregistrarea unui driver corespunzator.

2. Realizarea unei conexiuni propriu-zise.

Clasele și interfețele responsabile cu realizarea unei conexiuni sunt:

• DriverManager – este clasa ce se ocupă cu înregistrarea driverelor ce vor fi folosite în aplicație;

• Driver – interfața pe care trebuie să o implementeze orice clasă ce descrie un driver;

• DriverPropertyInfo – prin intermediul acestei clase pot fi specificate diverse proprietăți ce vor fi folosite la realizarea conexiunilor;

• Connection – descrie obiectele ce modeleaza o conexiune propriu-zisa cu baza de date.

Înregistrarea unui driver

Primul lucru pe care trebuie sa îl facă o aplicație în procesul de conectare la o bază de date este să înregistreze la mașina virtuală ce rulează aplicația, driverul JDBC responsabil cu comunicarea cu respectiva bază de date. Acest lucru presupune încărcarea în memorie a clasei ce implementează driver-ul și poate fi realizată în mai multe modalități.

a. Folosirea clasei DriverManager:

DriverManager.registerDriver(new TipDriver());

b. Folosirea metodei Class.forName ce apeleaza ClassLoader-ul mașinii virtuale:

Class.forName("TipDriver");

Class.forName("TipDriver").newInstance();

c. Setarea proprietatii sistem jdbc.drivers, care poate fi realizata în două feluri:

– De la linia de comandă:

java -Djdbc.drivers=TipDriver Aplicatie

– Din program:

System.setProperty("jdbc.drivers", "TipDriver");

Folosind această metodă, specificarea mai multor drivere se face separând numele claselor cu punct și virgulă.

Specificarea unei baze de date

O dată ce un driver JDBC a fost înregistrat, acesta poate fi folosit la stabilirea unei conexiuni cu o bază de date. Având în vedere faptul că pot exista mai multe drivere încărcate în memorie, trebuie să avem posibilitea de a specifica pe lângă un identificator al bazei de date și driverul ce trebuie folosit. Aceasta se realizează prin intermediul uni adrese specifice, numită JDBC URL ce are următorul format:

jdbc:sub-protocol:identificator

Câmpul sub-protocol denumește tipul de driver ce trebuie folosit pentru realizarea conexiunii și poate fi odbc, oracle, sybase, db2 și așa mai departe.

Identificatorul bazei de date este un indicator specific fiecărui driver corespunzător bazei de date cu care aplicația dorește să interacționeze. În funcție de tipul driver-ului, acest identificator poate include numele unei mașini gazdă, un număr de port, numele unui fișier sau al unui director, etc.

Subprotocolul odbc este un caz special, în sensul că permite specificarea în cadrul URL-ului a unor atribute ce vor fi folosite la crearea unei conexiuni.

La primirea unui JDBC URL, DriverManager-ul va parcurge lista driverelor inregistrate în memorie, până când unul dintre ele va recunoaște URL-ul respectiv. Dacă nu există nici unul potrivit, atunci va fi lansată o excepție de tipul SQLException, cu mesajul "No suitable driver".

Tipuri de drivere

Tipurile de drivere existente ce pot fi folosite pentru realizarea unei conexiuni prin intermediul JDBC se impart în urmatoarele categorii:

Tip 1.

Acest tip de driver permite conectarea la o bază de date care a fost înregistrată în prealabil în ODBC. ODBC (Open Database Conectivity) reprezintă o modalitate de a uniformiza accesul la baze de date, asociind acestora un identificator DSN (Data Source Name) și driver și parametrii necesari conectării. Conectarea efectivă la baza de date se va face prin intermediul acestui identificator, driver-ul ODBC efectuând comunicarea cu driverul nativ al bazei de date.

Driverul va converti apelurile de metode JDBC în apeluri de funcții ODBC.

Deși simplu de utilizat, soluția JDBC-ODBC nu este portabilă și comunicarea cu baza de date suferă la nivelul vitezei de execuție datorită multiplelor redirectări între drivere. De asemenea, atât ODBC-ul cât și driver-ul nativ sunt dependente de mașina pe care rulează aplicația. Astfel, această variantă ar trebui evitată dacă există la dispoziție un driver pur Java.

Clasa Java care descrie acest tip de driver JDBC este sun.jdbc.odbc.JdbcOdbcDriver și este inclusa în distribuția standard J2SDK.

Specificarea bazei de date se face printr-un URL de forma:

jdbc:odbc:identificator

unde identificator este profilul (DSN) creat bazei de date în ODBC.

Tip 2. Driver JDBC – Driver nativ

Acest tip de driver transformă cererile JDBC direct în apeluri către driverul nativ al bazei de date, care trebuie instalat în prealabil. Driverul va converti apelurile de metode JDBC în apeluri native ale API-ului bazei de date. Aceasta este o variantă mai bună decât prima, nemaiavând de-a face și cu ODBC-ul, însă nu este scris în întregime în Java, deci nici acesta nu oferă independența de platformă și nu este foarte potrivit pentru appleturi. În schimb, faptul că folosește API-uri native îl face foarte rapid.

Clase Java care implementează astfel de drivere pot fi procurate de la producătorii de SGBD-uri, distribuția standard J2SDK neincluzând niciunul.

Tip 3. Driver JDBC – Server

Acest tip de driver este cunoscut și sub denumirea de driver pur Java, folosindu-se de middleware-ul specific unui tip de baze de date și transformă cererile JDBC folosind un protocol de rețea independent, acestea fiind apoi transformate folosind o aplicație server într-un protocol specific bazei de date. Introducerea serverului ca nivel intermediar aduce flexibilitate maximă în sensul că vor putea fi realizate conexiuni cu diferite tipuri de baze, fără nici o modificare la nivelul clientului și al independenței de platformă. Folosindu-se de un middleware, oferă avantaje suplimentare de securitate.

Librăriile specifice nu mai trebuie să existe pe mașina client, ceea ce face acest protocol potrivit și pentru appleturi.

Tip 4. Driver JDBC nativ

Acest tip de driver este cunoscut ca fiind un driver pur Java de acces direct la o bază de date. El transformă cererile JDBC direct în cereri către baza de date folosind protocolul de rețea al acesteia, comunicarea făcându-se deobicei prin socket-uri.

Această soluție este cea mai rapidă, fiind preferată la dezvoltarea aplicațiilor care manevrează volume mari de date și viteza de execuție este critică.

Driverul este independent de platformă și trebuie să fie instalat în JMV a mașinii client. Drivere de acest tip pot fi procurate de la diverși producători de SGBD-uri.

Exemplu de driver: oracle.jdbc.driver.OracleDriver

Realizarea unei conexiuni la o bază de date

Metoda folosită pentru realizarea unei conexiuni este getConnection() din clasa DriverManager și poate avea mai multe forme:

Connection c = DriverManager.getConnection(url);

Connection c = DriverManager.getConnection(url, username, password);

Connection c = DriverManager.getConnection(url, dbproperties);

Folosirea diferitelor tipuri de drivere implică doar schimbarea numelui clasei ce reprezinta driverul și a modalitatii de specificare a bazei de date.

O conexiune va fi folosită pentru:

• Crearea de secvențe SQL utilizate pentru interogarea sau actualizarea bazei.

• Aflarea unor informatii legate de baza de date (meta-date).

De asemenea, clasa Connection asigură facilități pentru controlul tranzacțiilor din memorie către baza de date prin metodele commit, rollback, setAutoCommit.

Închiderea unei conexiuni se realizează prin metoda close().

1.3.2 Efectuarea de secvențe SQL

Odată făcută conectarea la baza de date cu metoda DriverManager.getConection(), se poate folosi obiectul Connection rezultat pentru a se crea obiecte de tip Statement, PreparedStatement sau CallableStatement cu ajutorul cărora putem trimite secvențe SQL către baza de date. Cele mai uzuale comenzi SQL sunt cele folosite pentru:

• Interogarea bazei de date: SELECT

• Actualizarea datelor: INSERT, UPDATE, DELETE

• Actualizarea structurii: CREATE, ALTER, DROP – acestea mai sunt numite instrucțiuni DDL (Data Definition Language)

• Apelarea unei proceduri stocate: CALL

După cum vom vedea, obținerea și prelucrarea rezultatelor unei interogări este realizată prin intermediul obiectelor de tip ResultSet.

Interfața Statement

Interfața Statement oferă metodele de bază pentru trimiterea de secvențe SQL către baza de date și obtinerea rezultatelor, celelalte doua interfete: PreparedStatement și CallableStatement fiind derivate din aceasta. Crearea unui obiect Statement se realizează prin intermediul metodei createStatement() a clasei Connection, fără nici un argument:

Connection con = DriverManager.getConnection(url);

Statement stmt = con.createStatement();

Executia unei secvențe SQL poate fi realizată prin intermediul a trei metode:

1. executeQuery

Este folosită pentru realizarea de interogari de tip SELECT.Metoda returneaza un obiect de tip ResultSet ce va conține sub o formă tabelară rezultatul interogării.

String sql = "SELECT * FROM persoane";

ResultSet rs = stmt.executeQuery(sql);

2. executeUpdate

Este folosită pentru actualizarea datelor (INSERT, UPDATE, DELETE) sau a structurii bazei de date (CREATE, ALTER, DROP). Metoda va returna un întreg ce semnifică numărul de linii afectate de operațiunea de actualizare a datelor, sau 0 în cazul unei instrucțiuni DDL.

3. execute

Această metodă va fi folosită doar dacă este posibil ca rezultatul unei interogări să fie format din doua sau mai multe obiecte de tip ResultSet sau rezultatul unei actualizari să fie format din mai mule valori, sau o combinatie intre aceste cazuri. Aceasta situatie, desi mai rară, este posibila atunci cand sunt executate proceduri stocate sau secvențe SQL cunoscute abia la momentul execuției, programatorul neștiind deci dacă va fi vorba de o actualizare a datelor sau a structurii. Metoda întoarce true dacă rezultatul obtinut este format din obiecte de tip ResultSet și false dacă e format din întregi.

În funcție de aceasta, pot fi apelate metodele: getResultSet() sau getUpdateCount() pentru a afla efectiv rezultatul comenzii SQL. Pentru a prelua toate rezultatele va fi apelata metoda getMoreResults(), dupa care vor fi apelate din nou metodele amintite, până la obținerea valorii null, respectiv −1.

Folosind clasa Statement, în cazul în care dorim să introducem valorile unor variabile într-o secvență SQL, nu avem altă soluție decât să creăm un șir de caractere compus din instructiuni SQL și valorile variabilelor:

int cod = 100;

String nume = "Popescu";

String sql = "SELECT * FROM persoane WHERE cod=" + cod +" OR nume=’" + nume + "’";

ResultSet rs = stmt.executeQuery(sql);

Interfața PreparedStatement

Interfața PreparedStatement este derivată din Statement, fiind diferită de aceasta în următoarele privințe:

• Instanțele de tip PreparedStatement conțin secvențe SQL care au fost deja compilate (sunt ”pregătite”).

• O secvență SQL specificată unui obiect PreparedStatement poate să aiba unul sau mai mulți parametri de intrare, care vor fi specificați prin intermediul unui semn de întrebare (”?”) în locul fiecăruia dintre ei. Înainte ca secvența SQL să poată fi executată, fiecarui parametru de intrare trebuie să i se atribuie o valoare, folosind metode specifice acestei clase.

Execuția repetată a aceleiați secvențe SQL, dar cu parametri diferiți, va fi în general mai rapidă dacă folosim PreparedStatement, deoarece nu mai trebuie sa creăm câte un obiect de tip Statement pentru fiecare apel SQL, ci refolosim o singură instanță precompilată, furnizându-i doar alte argumente.

Crearea unui obiect de tip PreparedStatement se realizează prin intermediul metodei prepareStatement() a clasei Connection, specificând ca argument o secvență SQL ce conține câte un semn de întrebare pentru fiecare parametru de intrare:

Connection con = DriverManager.getConnection(url);

String sql = "UPDATE persoane SET nume=? WHERE cod=?";

Statement pstmt = con.prepareStatement(sql);

Obiectul va pstmt conține o comandă SQL precompilată care este trimisă imediat către baza de date, unde va aștepta parametri de intrare pentru a putea fi executată.

Trimiterea parametrilor se realizează prin metode de tip setXXX, unde XXX este tipul corespunzător parametrului, iar argumentele metodei sunt numărul de ordine al parametrului de intrare (al semnului de intrebare) și valoarea pe care dorim să o atribuim.

pstmt.setString(1, "Ionescu");

pstmt.setInt(2, 100);

După stabilirea parametrilor de intrare, secvența SQL poate fi executata. Putem apoi stabili alte valori de intrare și refolosi obiectul PreparedStatement pentru execuții repetate ale comenzii SQL. Este însă posibil ca SGBD-ul folosit să nu suporte acest tip de operatiune și să nu rețină obiectul precompilat pentru execuții ulterioare. În această situație, folosirea interfeței PreparedStatement în loc de Statement nu va îmbunătăți în nici un fel performanța codului, din punctul de vedere al vitezei de execuție a acestuia.

Execuția unei secvențe SQL folosind un obiect PreparedStatement se realizează printr-una din metodele executeQuery, executeUpdate sau execute, semnificațiile lor fiind aceleași ca și în cazul obiectelor de tip Statement, cu singura deosebire că în cazul de față, ele nu au nici un argument.

String sql = "UPDATE persoane SET nume=? WHERE cod=?";

Statement pstmt = con.prepareStatement(sql);

pstmt.setString(1, "Ionescu");

pstmt.setInt(2, 100);

pstmt.executeUpdate();

pstmt.setString(1, "Popescu");

pstmt.setInt(2, 200);

pstmt.executeUpdate();

sql = "SELECT * from persoane WHERE cod >= ?";

pstmt = con.prepareStatement(sql);

pstmt.setInt(1, 100);

ResultSet rs = pstmt.executeQuery();

Fiecărui tip Java îi corespunde un tip generic SQL. Este responsabilitatea programatorului să se asigure că foloseste metoda adecvată de tip setXXX la stabilirea valorii unui parametru de intrare. Lista tuturor tipurilor generice disponibile, numite și tipuri JDBC, este definită de clasa java.sql.Types, prin constantelor declarate de aceasta. Metoda setObject() permite specificarea unor valori pentru parametrii de intrare, atunci când dorim să folosim maparea implicită între tipurile Java și cele JDBC sau atunci când dorim să precizăm explicit un tip JDBC.

pstmt.setObject(1, "Ionescu", Types.CHAR);

pstmt.setObject(2, 100, Types.INTEGER); // sau doar

pstmt.setObject(2, 100);

Folosind metoda setNull() putem să atribuim unui parametru de intrare valoare SQL NULL, trebuind însă să specificăm și tipul de date al coloanei în care vom scrie această valoare. Același lucru poate fi realizat cu metode de tipul setXXX dacă argumentul folosit are valoarea null.

pstmt.setNull(1, Types.CHAR);

pstmt.setInt(2, null);

Interfața CallableStatement

Interfața CallableStatement este derivată din PreparedStatement, instanțele de acest tip oferind o modalitate de a apela o procedura stocata intr-o baza de date, intr-o maniera standar pentru toate SGBD-urile.

Crearea unui obiect CallableStatement se realizeaza prin metoda prepareCall a clasei Connection:

Connection con = DriverManager.getConnection(url);

CallableStatement cstmt = con.prepareCall("{call proceduraStocata(?, ?)}");

Trimiterea parametrilor de intrare se realizeaza intocmai ca la PreparedStatement, cu metode de tip setXXX. Dacă procedura are și parametri de iesire (valori returnate), acestia vor trebui inregistrati cu metoda registerOutParameter inainte de executia procedurii. Obținerea valorilor rezultate în parametrii de iesie se va face cu metode de tip getXXX.

CallableStatement cstmt = con.prepareCall("{call calculMedie(?)}");

cstmt.registerOutParameter(1, java.sql.Types.FLOAT);

cstmt.executeQuery();

float medie = cstmt.getDouble(1);

Este posibil ca un parametru de intrare sa fie și parametru de iesire. În acest caz el trebuie să primească o valoare cu setXXX și, de asemenea, va fi înregistrat cu registerOutParameter, tipurile de date specificate trebuind să coincidă.

1.3.3 Obținerea și prelucrarea rezultatelor

Interfața ResultSet

În urma executiei unei interogari SQL, rezultatul va fi reprezentat printr-un obiect de tip ResultSet, ce va conține toate liniile ce satisfac conditiile impuse de comanda SQL. Forma generală a unui ResultSet este tabelară, având un număr de coloane și de linii, în funcție de secvența executată. De asemenea, obiectul va conține și meta-datele interogării cum ar fi denumirele coloanelor selectate, numărul lor, etc.

Pentru a extrage informațiile din această structură va trebui să parcurgem tabelul linie cu linie și din fiecare să extragem valorile de pe coloane. Pentru acest lucru vom folosi metode de tip getXXX, unde XXX este tipul de data al unei coloane iar argumentul primit indică fie numărul de ordine din cadrul tabelului, fie numele acestuia. Coloanele sunt numerotate de la stânga la dreapta, începând cu 1. În general, folosirea indexului coloanei în loc de numele său va fi mai eficientă. De asemenea, pentru maxima portabilitate se recomandă citirea coloanelor în ordine de la stânga la dreapta și fiecare citire să se facă o singură dată.

Un obiect ResultSet folosește un cursor pentru a parcurge articolele rezultate în urma unei interogări. Inițial acest cursor este poziționat înaintea primei linii, fiecare apel al metodei next() determinând trecerea la următoarea linie. Deoarece next() returnează false când nu mai sunt linii de adus, uzual va fi folosită o buclă while petru a itera prin articolele tabelului:

String sql = "SELECT cod, nume FROM persoane";

ResultSet rs = stmt.executeQuery(sql);

while (rs.next()) {

int cod = r.getInt("cod");

String nume = r.getString("nume");

/* echivalent cu:

int cod = r.getInt(1);

String nume = r.getString(2);

*/

System.out.println(cod + ", " + nume);

}

Implicit, un tabel de tip ResultSet nu poate fi modificat, iar cursorul asociat nu se deplaseaza decât înainte, linie cu linie. Așadar, putem itera prin rezultatul unei interogări o singură dată și numai de la prima la ultima linie. Este însă posibil să creăm ResultSet-uri care să permită modificarea sau deplasarea în ambele sensuri. Exemplul următor va folosi un cursor care este modificabil și nu va reflecta schimbarile produse de alți utilizatori după crearea sa:

Statement stmt = con.createStatement(

ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_UPDATABLE);

String sql = "SELECT cod, nume FROM persoane";

ResultSet rs = stmt.executeQuery(sql);

Dacă un ResultSet foloseste un cursor modificabil și care poate naviga în ambele sensuri, atunci are la dispoziție o serie de metode ce se bazeaza pe acest suport:

• absolute – deplasează cursorul la o anumită linie specificată absolut;

• updateXXX – actualizeaza valoarea unei coloane din linia curenta,unde XXX este un tip de date.

• updateRow – transferă actualizările făcute liniei în baza de date.

• moveToInsertRow – deplasează cursorul la o linie specială, numită linie nouă, utilizată pentru a introduce noi articole în baza de date. Linia curentă anterioară a cursorului va fi memorată pentru a se putea reveni la ea.

• insertRow – inserează articolul din zona linie noua în baza de date; cursorul trebuie să fie poziționat la linia nouă la execuția acestei operatiuni.

• moveToCurrentRow – revine la linia curentă din tabel.

• deleteRow – sterge linia curenta din tabel și din baza de date; nu poate fi apelată când cursorul este în modul linie nouă.

Nu toate sistemele de gestiune a bazelor de date oferă suport pentru folosirea cursoarelor care pot fi modificate. Pentru a determina dacă baza de date permite acest lucru pot fi utilizate metodele supportsPositionedUpdate() și supportsPositionedDelete() ale clasei DatabaseMetaData. În cazul în care acest lucru este permis, este responsabilitatea driver-ului bazei de date sa asigure rezolvarea problemelor legate de actualizarea concurenta a unui cursor, astfel incat sa nu apara anomalii.

1.3.4 Lucrul cu meta-date

Interfața DatabaseMetaData

După realizarea unui conexiuni la o bază de date, putem apela metoda getMetaData() pentru a afla diverse informatii legate de baza respectiva, asa numitele meta-date (”date despre date”); Ca rezultat al apelului metodei, vom obtine un obiect de tip DatabaseMetaData ce oferă un număr mare de metode pentru determinarea tabelelor, procedurilor stocate, capabilitatilor conexiunii, gramaticii SQL suportate, etc. ale bazei de date.

În aplicația prezentată în această lucrare am folosit metodele getColumns() și getTables().

Metoda getColumns() permite obținerea de informații despre coloanele unui tabel dintr-o bază de date. Informațiile returnate despre coloane sunt destul de variate, fiind 22 la număr. Dintre cele mai de interes sunt: COLUMN_NAME – numele coloanei, DATA_TYPE – tipul de date SQL așa cum este definit în java.sql.Types, TYPE_NAME – denumirea tipului de date care este dependent de tipul sursei de date, COLUMN_SIZE – dacă coloana este de tip caracter returnează dimensiunea maximă, dacă este de tip numeric returnează precizia, NULLABLE și IS_NULLABLE – precizează dacă coloana permite NULL sau nu, COLUMN_DEF – valoarea implicită, ORDINAL_POSITION – numărul de ordine al coloanei în tabel.

Metoda getTables() permite obținerea de informații despre tabelele din baza de date precum ar fi: TABLE_NAME – numele tabelului, TABLE_TYPE – tipul tabelului (poate fi "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM").

Interfața ResultSetMetaData

Meta-datele unui ResultSet reprezintă informațiile despre rezultatul conținut în acel obiect cum ar fi numărul coloanelor, tipul și denumirile lor, etc. Acestea sunt obținute apelând metoda getMetaData() pentru ResultSet-ul respectiv, care va returna un obiect de tip ResultSetMetaData ce poate fi apoi folosit pentru extragerea informațiilor dorite cum ar fi: getColumnCount() pentru a afla câte coloane sunt în ResultSet, getColumnName(int n) pentru a afla numele celei de-a n coloană, getColumnType(int n) pentru a afla tipul de date al celei de-a n coloane (așa cum este definit în java.sql.Types), getColumnTypeName(int n) pentru a afla tipul de date al celei de-a n coloane (cu denumirea dependentă de tipul sursei de date).

Exemplu: Obținerea numărului de coloane dintr-o tabelă și a numelui coloanelor.

ResultSet rs = stmt.executeQuery("SELECT * FROM tabel");

ResultSetMetaData rsmd = rs.getMetaData();

// Aflam numarul de coloane

int n = rsmd.getColumnCount();

// Aflam numele coloanelor

Sring nume[] = new String[n+1];

for(int i=1; i<=n; i++)

nume[i] = rsmd.getColumnName(i);

CAPITOLUL II – MODUL DE REALIZARE A APLICAȚIEI

2.1 Proiectarea aplicației pe baza cerințelor

Primul pas în realizarea acestei aplicații a fost consultarea clinicii care avea sa o folosească. Aceasta și-a definit în mod cât mai exact necesitățile, funcționalitățile care trebuiau implementate, cât și unele specificații legate de aspectul interfeței și modul de operare al aplicației, dorința de bază fiind aceea a unei utilizări cât mai facile și a necesității minime de instruire în folosirea aplicației.

În urma discuțiilor purtate s-au conturat câteva elemente de bază și anume cele ce țin de programarea pacienților, de încasări, diverse tipuri de raporte (nu foarte multe la număr totuși) și câteva elemente ce țin de medici. Conform acestor elemente s-a conturat interfața aplicației și structura bazei de date care urma să conțină datele necesare operării aplicației.

Limbajul de programare ales a fost Java, din multiple considerente, deși din punct de vedere al performanțelor, dacă se mergea pe ideea ca va fi folosit doar pe sisteme Windows, ar fi putut ales un alt limbaj dedicat sistemelor Windows (Microsoft Access, Visual FoxPro, etc).

Aplicația a fost inițial gândită să fie folosită pe un singur calculator, însă în timp a apărut necesitatea operării de pe cel puțin două calculatoare, astfel ca trecerea bazei de date pe un server devine tot mai necesară.

2.2 Baza de date

După cum am menționat deja, baza de date este de tip MySQL. Ea conține 6 tabele care vor fi prezentate pe scurt în cele ce urmează.

Tabelul Blocaje

Acest tabel conține datele despre orele sau zilele blocate ale medicilor.

Fig. 2.1

Tabelul Medici

Acest tabel conține numele și specialitatea medicilor din clinică.

Fig. 2.2

Tabelul Orar

Acest tabel conține orarele de lucru ale medicilor. Există câte o coloană pentru fiecare zi a săptămânii, iar orarul este reprezentat ca un șir de caractere de forma: 10:00 – 14:00.

Fig. 2.3

În cazul în care într-o zi, un medic are program în mai mult decât un singur interval orar, vor exista mai multe intrări în tabel, egal cu numărul de intervale orare.

De exemplu:

Fig. 2.4

Tabelul Ore:

Acest tabel conține orele la care se pot face programări pentru fiecare medic, pentru fiecare zi și interval orar.

Fig. 2.5

Orele sunt reprezentate ca și șiruri de caractere de forma: 10:15.

Exemplu:

Fig. 2.6

Tabelul Programări

Acesta este cel mai consistent tabel și conține date despre programări după cum urmează:

p_id – este un identificator unic al fiecărei programări, este de tip numeric lung și reprezintă ora în milisecunde la care a fost făcută programarea.

m_id – reprezintă codul unic de identificare a medicului la care este făcută programarea

pacient – reprezintă numele pacientului

telefon – reprezintă telefonul pacientului

data_prg – reprezintă data programării

ora_prg – reprezintă ora programării

interventie – reprezintă intervenția pnetru care se face programarea

ora_op_prg – reprezintă ora la care a fost adăugată din aplicație programarea

ora_op_inc – reprezintă ora la care a fost adăugată din aplicație încasarea aferentă respectivei programări

data_op_prg – reprezintă data la care a fost adăugată din aplicație programarea

data_op_inc – reprezintă data la care a fost adăugată din aplicație încasarea aferentă respectivei programări

valoare – reprezintă suma încasată pentru acea programare

salt – reprezintă numărul care denotă dacă programarea va ocupa mai multe intervale orare

valuta – reprezintă moneda în care se face încasarea

Fig. 2.7

Tabelul Tip_consult

Acest tabel conține toate tipurile de intervenții pe care le poate presta fiecare medic, împreună cu tariful aferent.

Fig. 2.8

2.3 Ferestrele aplicației

Aplicația conține o fereastră principală care găzduiește meniul acesteia. Pe suprafața ferestrei a fost plasată o imagine, deși aceasta putea fi lăsată să conțină doar culoarea de fundal.

Ferestrele sunt clase JFrame, majoritatea având un titlu care le sugerează funcționalitatea. Titlul ferestrelor se setează folosind metoda setTitle(“…”) pentru obiectul de tip JFrame.

Deoarece ferestrele nu au o dimensiune predefinită, pentru fiecare dintre acestea a fost folosită metoda setSize(lungime, lățime) pentru a stabili dimensiunile în pixeli, pe orizontală și pe verticală.

Ferestrele în mod implicit sunt afișate începând cu colțul stâng al ecranului, astfel că pentru a obține afișarea centrală pe ecran s-a folosit pentru acestea metoda setLocationRelativeTo(null).

Deși se recomandă utilizarea gestionarilor de poziționare predefiniți, care vin cu o serie de avantaje, în cadrul acestei aplicații s-a optat pentru a nu se folosi nici un gestionar si astfel să se permită poziționarea absolută a oricărei componente în orice locație dorită. Astfel pentru fiecare fereastră s-a apelat metoda setLayout(null). Dezavantajul care vine cu această variantă constă în faptul că la redimensionarea unei ferestre, componentele rămân în poziția lor inițială ceea ce poate duce uneori la un aspect nepotrivit al ferestrei.

Înafară de fereastra principală care are pe fundal o imagine, toate celelalte ferestre ale aplicației au doar culoare de fundal albastru deschis, setată cu metoda:

getContentPane().setBackground (new Color(236,233,216));

Fundalul ferestrei principale a fost obținut prin plasarea unui JPanel pe aceasta. Pentru acel panel a fost suprascrisă metoda paintComponent(Graphics g), setându-se imaginea care se va desena pe acesta astfel:

try {

image = javax.imageio.ImageIO.read

(new java.net.URL(getClass().getResource("hospital.jpg"), "hospital.jpg"));

} catch (Exception e) {}

Ca și componente grafice, ferestrele în general conțin: JComboBox, JLabel, JTextField, JButton, JTable.

2.4 Calendarul

Un element mai deosebit care nu era oferit de Java, deși se găsea gata implementat de către alți programatori, însă deobicei nu în limba română sau sub forme care nu se potriveau aplicației, este calendarul. Astfel am facut propriul calendar concretizat în clasa MyDatePickerPanel. După cum îi spune și numele este vorba de un JPanel care conține: două butoane pentru trecerea de la o lună la alta, un label care conține luna și anul afișat curent de către calendar și un tabel cu 6 linii și 7 coloane pentru reprezentarea zilelor lunii.

Data curent selectată în calendar este reprezentată pe fundal roșu pentru a fi identificată mai ușor. Deoarece în mod normal toate celulele cu conținut de același tip sunt reprezentate la fel, iar datele de tip numeric se afișează aliniate la dreapta, a fost necesară crearea unei clase personalizate care să extindă clasa DefaultTableCellRenderer. În cadrul acesteia a fost setată alinierea centrată a textului din celule, iar celula din data curent selectată să aibă culoarea de fundal roșie.

Codul acestei clase este următorul:

class CenterCellRenderer extends DefaultTableCellRenderer {

public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

JLabel renderedLabel = (JLabel) super.getTableCellRendererComponent(

table, value, isSelected, hasFocus, row, column);

renderedLabel.setHorizontalAlignment(SwingConstants.CENTER);

if (row == liniaAzi && column == colAzi && lunaCur == lunaAzi) {

renderedLabel.setBackground(new Color(255, 140, 140));

} else {

renderedLabel.setBackground(Color.white);

}

return renderedLabel;

}

}

Fig. 2.11

Calendarul va porni întotdeauna din luna curentă, urmând ca folosind butoanele < și > să se schimbe luna.

Una din problemele inițiale în realizarea acestui calendar a fost afișarea corectă a zilelor lunii în tabel. Pentru aceasta s-a folosit un obiect din clasa Calendar pentru care s-a apelat metoda get(temp_cal.DAY_OF_WEEK) pentru a afla a câta zi din săptămână este prima zi din lună. Deasemenea a fost necesar să se știe câte zile are luna curentă pentru a ști câte elemente să fie plasate în tabel. Știind aceste lucruri se completează tabelul.

Denumirile lunilor au fost setate din cod, pentru a putea fi în limba romană.

Butoanele < și > au atașați ascultători, iar când sa face click pe unul dintre ei, se va schimba luna curentă și se va repopula tabelul.

Deoarece multe din ferestre conțin elemente asemănătoare, vom explica modul de realizare al unei ferestre mai complexe cum este cea de creare a unei programari noi, deoarece multe din elementele acesteia se regăsesc și în alte ferestre.

Ca și componente grafice, ferestra Programare nouă conține tot ce am enumerat mai sus (JComboBox, JLabel, JTextField, JButton, JTable).

Fig. 2.12

La deschiderea ferestrei se va autocompleta caseta pentru dată cu data curentă și combobox-ul care conține numele medicilor din clinică. Acest lucru este realizat prin interogarea tabelei medici din baza de date. Conform teoriei din capitolul anterior, pentru a realiza acest lucru am înregistrat prima dată driverul corespunzător, am referit tabela dorită în variabila url, am realizat conectarea propriu-zisă la baza de date într-un obiect de tip Connection, am setat instrucțiunea SQL într-o variabilă de tip String pe care am pasat-o ca și parametru unui obiect de tip Statement. Rezultatele interogării au fost plasate într-un obiect de tip ResultSet care a fost apoi parcurs cu ajutorul instrucțiunii while și din care s-a extras din fiecare rând numele medicului.

try {

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

} catch (ClassNotFoundException e) {

System.out.println("Eroare incarcare driver !\n" + e);

return;

}

url = "jdbc:odbc:medici";

try {

Connection con = DriverManager.getConnection(url);

sql = "SELECT nume FROM medici ORDER BY nume";

stmt = con.createStatement();

rs = stmt.executeQuery(sql);

String ss;

while (rs.next()) {

ss = rs.getString("nume");

jComboDoctor.addItem(ss);

}

con.close();

} catch (SQLException e) {

e.printStackTrace();

}

Acest obiect combobox are atașat un listener, astfel că în momentul în care se va selecta o anumită linie, se va executa o anumită secvență de program și anume se va autocompleta specialitatea medicului selectat (tot ca și rezultat al interogării tabelului medici) și se va completa tabelul cu orarul medicului selectat, ca și rezultat al interogării tabelului orar în cadrul metodei citiredb(). Tabelul se completează setând matricea care conține datele acestuia și vectorul de tip String care conține denumirile coloanelor.

String col[] = {"Luni", "Marti", "Miercuri", "Joi", "Vineri", "Sambata"};

Object[][] data = citiredb();

jTable1.setModel(new DefaultTableModel(data, col));

Următorul pas este selectarea datei în care se dorește să se facă programarea. Aceasta poate fi data curentă sau o dată viitoare și se va selecta cu ajutorul calendarului apăsând butonul Alege. După ce se alege o dată în care medicul are program, se va autocompleta combobox-ul Ora cu orele la care se poate face programare în respectiva zi. Acesta va fi rezultatul interogării tabelului Ore care conține toate orele la care se poate face programare pentru un anumit medic într-o anumită zi a săptămânii. De menționat faptul că în practică fiecare medic poate avea programări la diverse intervale orare cum ar fi odată la 15 minute, 20, 30, 50 de minute, în funcție de specialitatea sa și de durata medie a unei intervenții a sa.

Se va mai autocompleta și tabelul Programări efectuate, care va conține pacienții deja programați în ziua aleasă la respectivul medic. Acesta va fi rezultatul interogării tabelului programări pentru medicul și data setate anterior.

Datorită eventualelor programări existente, la anumite ore nu se va mai putea face programare, astfel că în lista Ora vor mai apărea doar orele încă disponibile. Practic se va face o interogare a tabelului Programări pentru medicul și data setate anterior și se vor elimina din combobox-ul ora, orele la care se găsesc programări deja efectuate.

O opțiune mai deosebită care poate apărea la nivelul orelor este faptul că la o anumită programare se poate permite ocuparea mai multor intervale orare, nu doar a unui singur cum este în mod implicit. Într-un astfel de caz se va completa cu un număr mai mare sau egal decât 1 caseta de text care se află lângă combobox-ul Ora.

Exemplu: Un anumit medic are programări o dată la 15 minute. Un pacient este programat la ora 10:00 + 1. În acest caz, acesta va ocupa atât programarea de la ora 10:00, cât și pe cea de la ora 10:15, astfel că ora 10:15 nu va mai fi disponibilă pentru programarea altui pacient.

După setarea tuturor acestor elemente se pot trece datele pacientului care constau doar în numele acestuia și opțional un număr de telefon pentru a putea fi contactat. Acesta poate fi considerat un mod relativ atipic de lucru, deoarece deobicei se rețin mai multe date despre pacienți, însă în cazul acestei clinici nu se rețin nici un fel de dare personale al pacienților sau vreun istoric al intervențiilor lor în cadrul clinicii.

Un ultim pas care poate fi realizat în cadrul acestei ferestre este acela de încasare a pacientului, însă această operație nu este foarte uzuală, deoarece pacientul este deobicei încasat dupa intervenție. Totuși dacă se dorește încasarea anticipată a sa, se va apăsa butonul Încasare, după care vor apărea două componente care erau ascunse: o casetă de text în care se va introduce suma încasată și un combobox din care se va alege moneda în care se face încasarea. De menționat aici faptul că, clinica permite încasări și în alte monede, nu doar în lei.

Ultimul pas este apăsarea butonului OK care va avea ca și efect preluarea datelor setate în cadrul ferestrei și materializarea lor într-o secvență SQL de tip INSERT pentru a adăuga noua programare în baza de date:

sql = "INSERT INTO programari VALUES (" + p_id + "," + mid + ",'" + pacient + "','" + telefon + "',{^" + datatest1 + "},'" + ora_prg + "','" + interventie + "','" + ora_op_prg + "','', {^" + dataAzi + "}, {^0/0/0}," + valoare + "," + salt + ",'')";

Fereastra va dispărea și va apărea o fereastră de tip JFrame care conține rezumatul programării efectuate, care poate fi listată la imprimantă și oferită pacientului. Practic se tipărește conținutul ferestrei cu tot ce este amplasat pe ea.

PrinterJob job = PrinterJob.getPrinterJob();

job.setPrintable(PrintProgramare.this);

try {

job.print();

} catch (PrinterException ex) {}

2.5 Rapoarte

Rapoarte de tip tabel

Deoarece modul de introducere a datelor într-un JTable a fost deja prezentat vom afișa doar secvența SQL care va avea ca și rezultat popularea tabelului.

Exemplul 1: În fereastra Programați, pentru a vizualiza toți pacienții programați la un anumit medic într-o anumită zi s-a folosit secvența SQL:

sql = "SELECT pacient, telefon, interventie, ora_prg, valoare, valuta FROM programari ORDER BY ora_prg WHERE m_id=" + mid + " AND day(data_prg)=" + dataCurenta.getDate() + " AND month(data_prg)=" + (dataCurenta.getMonth() + 1) + " AND year(data_prg)=" + (dataCurenta.getYear() + 1900);

Exemplul 2: În fereastra Încasați, pentru a vizualiza toate încasările la un anumit medic într-o anumită zi s-a folosit secvența SQL:

sql = "SELECT pacient, interventie, ora_op_inc, valoare, valuta FROM programari ORDER BY ora_op_inc WHERE m_id=" + mid + " AND day(data_op_inc)=" + dataCurenta.getDate() + " and month(data_op_inc)=" + (dataCurenta.getMonth() + 1) + " AND year(data_op_inc)=" + (dataCurenta.getYear() + 1900);

Exemplul 3: În fereastra Încasări pe schimb, pentru a vizualiza toate încasările dintr-un anumit schimb (1 sau 2) într-o anumită perioadă de tip, grupate pe medici, s-a folosit secvența de cod:

if (schimb == 1)

sql = "SELECT medici.nume, SUM(programari.valoare) FROM medici, programari WHERE medici.m_id=programari.m_id " + "AND (programari.valuta='LEU' OR programari.valuta='LEI') AND data_op_inc>={^" + datatest1 + "} AND data_op_inc<={^" + datatest2 + "} " + "AND (SUBSTR(ora_op_inc,1,2)<'14' OR SUBSTR(ora_op_inc,1,2)='8:' or SUBSTR(ora_op_inc,1,2)='9:') GROUP BY medici.nume";

Deoarece în tabelul Programări nu există decât codul medicului, pentru a putea afișa numele medicilor s-a făcut un JOIN intre tabelul Programări și tabelul Medici pe baza câmpului m_id.

Exemplul 4: În fereastra Programați azi în schimbul 1 (sau 2), spre deosebire de cazurile anteriorare, este vorba de mai multe tabele care trebuiesc populate, câte unul pentru fiecare medic. Acest lucru a fost realizat astfel:

În primă fază au fost selectați din tabelul Programări medici care au programări în data curentă și introduși într-o matrice:

sql = "SELECT DISTINCT programari.m_id, medici.nume, medici.specialitate FROM programari,medici WHERE programari.m_id=medici.m_id AND day(programari.data_prg)=" + dataCurenta.getDate() + " AND month(programari.data_prg)=" + (dataCurenta.getMonth() + 1) + " AND year(programari.data_prg)=" + (dataCurenta.getYear() + 1900);

După aceasta s-a parcurs matricea pentru a selecta programările pentru fiecare medic în parte din tabelul Programări:

sql = "SELECT programari.pacient, programari.interventie, programari.ora_prg, programari.valoare FROM programari ORDER BY programari.ora_prg WHERE m_id=" + medici[nrcrt] + " AND day(programari.data_prg)=" + dataCurenta.getDate() + " AND month(programari.data_prg)=" + (dataCurenta.getMonth() + 1) + " AND year(programari.data_prg)=" + (dataCurenta.getYear() + 1900);

Fiecare astfel de tabel este apoi tipărit la imprimantă.

Rapoarte de tip valoare

În această clasă se află totalurile de diverse tipuri cum ar fi: total programări într-o perioadă de timp, total încasări într-o perioadă de timp.

Exemplul 1: În fereastra Încasări pe medici se pot vizualiza totalul încasărilor dintr-o perioadă de tip, grupate pe medici, cât și sub formă de totaluri.

Pentru a obține totalul încasărilor într-o anumită monedă s-a folosit următoarea secvență SQL:

sql = "SELECT SUM(valoare) FROM programari WHERE (valuta='LEU' OR valuta='LEI') AND data_op_inc>={^" + datatest1 + "} AND data_op_inc<={^" + datatest2 + "}";

2.6 Blocarea de ore sau zile

O operație mai deosebită este aceea de a bloca anumite ore sau zile pentru un anumit medic, când nu se vor putea face programări. Deși are program, un medic poate să lipsească din motive obiective sau subiective un anumit număr de ore într-o zi, sau chiar o zi întreagă sau mai multe. Acest lucru trebuie să se reflecte în aplicație pentru a nu se face programări în acele intervale. Deasemenea trebuie să se poată anula eventuale blocaje care nu mai sunt valabile la un momentdat.

Aceste operațiuni sunt efectuate în meniul Ore blocate.

Adăugarea unui nou blocaj presupune selectarea tipului acestuia: un interval orar dintr-o anumită zi sau o zi întreagă (sau mai multe).

Dacă medicul lipsește un interval de zile, vor trebui completate datele De la și Până la. Dacă medicul lipsește un interval orar dintr-o anumită zi, vor trebui completate orele De la și Până la. După ce au fost setate datele blocajului se apasă OK, iar rezultatul va fi adăugarea unei noi linii în tabelul Blocaje.

Aceste blocaje vor fi apoi vizibile sub forma unui label de culoare roșie în fereastra Programări, în cazul în care la o dată selectată există blocaj pentru medicul selectat. În label se va menționa că medicul lipsește întreaga și sau doar intervalul (intervalele) orar din respectiva zi.

Pentru a anula un blocaj existent se va alege din meniu opțiunea Șterge blocaj. În fereastra care apare se selectează prima dată un medic. După aceasta este interogat tabelul Blocaje pentru a vedea dacă există blocaje pentru respectivul medic. Dacă da, acestea vor fi afișate într-un tabel care are prima coloană sub formă de checkbox. Blocajele care se doresc a fi anulate se vor bifa in prima coloană după care se va apăsa butonul OK. Aceasta va avea ca si efect ștergerea blocajelor selectate din tabelul Blocaje și posibilitatea de a face din nou programări în acele zile sau ore care fuseseră blocate.

CAPITOLUL III – MODUL DE UTILIZARE A APLICAȚIEI

Fig 3.1 – Fereastra principală

Meniurile

3.1. Meniul Programări

În cadrul acestui meniu se pot face programari noi, se pot anula programări deja existente sau se pot vizualiza pacienții programați într-o anumită zi la un anumit medic.

Operațiunea de reprogramare a unui pacient nu există de sine stătătoare ci constă în anularea programării deja existente și realizarea unei programări noi.

Fig 3.2 Meniu Programări

Opțiunea Programare nouă

În cadrul acestei ferestre se poate realiza o programare nouă.

Primul lucru care trebuie făcut este să se selecteze medicul la care se face programarea. Această selecție se poate face manual din lista ascunsă sau se poate scrie începutul numelui medicului în caseta de text și se va autocompleta numele medicului.

După ce este selectat un medic, se vor autocompleta mai multe componente cum sunt: caseta de text cu specialitatea acestuia, lista cu tipurile de intervenții prestate de respectivul medic, tabelul cu orarul doctorului.

Implicit, caseta Data conține data curentă, care dacă se dorește a fi modificată se va apăsa butonul Alege, care are ca și rezultat deschiderea unui calendar lunar din care se poate selecta o dată (data curentă sau o dată viitoare).

În momentul în care este selectată data dorită, în tabelul Programări efectuate apar pacienții deja programați la respectivul medic în data aleasă, iar în lista ascunsă Ora sunt afișate orele care mai sunt disponibile pentru respectivul medic în data aleasă. După ce se alege ora dorită se va completa numele pacientului (obligatoriu) și opțional numărul de telefon al acestuia.

Dacă se dorește încasarea pacientului în momentul realizării programării, se va apăsa butonul Încasare și în dreptul acestuia vor apărea o casetă de text în care se va completa suma încasată și o listă ascunsă din care se va selecta moneda în care se face încasarea.

După realizarea tuturor acestor operații, se va apăsa butonul OK, care va avea ca și efect salvarea în baza de date a programării nou făcute și va oferi posibilitatea de a lista la imprimantă confirmarea programării, care poate fi oferită pacientului. În cazul în care programarea se face telefonic, confirmarea programării deobicei nu se mai listează la imprimantă.

Fig. 3.3

Fig. 3.4

Opțiunea Anulare programare

În cadrul acestei ferestre se poate anula o programare deja existentă.

Primul lucru care trebuie făcut este să se selecteze medicul la care este făcută programarea care urmează să fie anulată. Această selecție se poate face manual din lista ascunsă sau se poate scrie începutul numelui medicului în caseta de text și se va autocompleta numele medicului.

Implicit, caseta Data conține data curentă, care dacă se dorește a fi modificată se va apăsa butonul Alege, care are ca și rezultat deschiderea unui calendar lunar din care se poate selecta o dată (data curentă sau o dată viitoare).

În momentul în care este selectată data dorită, în lista ascunsă Ora sunt afișate orele la care există programări făcute pentru respectivul medic în data aleasă. După ce se alege ora la care era făcută programarea care urmează să fie anulată, se va autocompleta numele pacientului, intervenția pentru care a fost programat și eventual suma plătită de acesta, în cazul în care va trebui făcută și o returnare de bani.

După realizarea tuturor acestor operații, se va apăsa butonul Anulare, iar programarea aleasă va fi ștearsă din baza de date, ora eliberată putând fi apoi alocată unei alte programări.

Fig. 3.5

Opțiunea Programați

În cadrul acestei ferestre se pot vizualiza pacienții programați la un anumit medic, la o anumită dată.

Primul lucru care trebuie făcut este să se selecteze medicul pentru care se dorește vizualizarea programărilor. Această selecție se poate face manual din lista ascunsă sau se poate scrie începutul numelui medicului în caseta de text și se va autocompleta numele medicului.

Implicit, caseta Data conține data curentă, care dacă se dorește a fi modificată se va apăsa butonul Alege, care are ca și rezultat deschiderea unui calendar lunar din care se poate selecta o dată (data curentă, anterioară sau viitoare).

După realizarea tuturor acestor operații se va completa tabelul din fereastră cu pacienții găsiți în baza de date care corespund celor două criterii alese. Acest tabel poate fi tipărit la imprimantă apăsând butonul Tipărire.

Acestă opțiune mai este utilă pentru medicii al căror ora se întinde atât în schimbul 1 (orele 8-14) cât și în schimbul 2 (14-20), deoarece cu ajutorul acestei opțiuni se pot lista programările din ambele schimburi. Despre acest lucru vom discuta și în unele opțiuni de meniu ce vor urma mai jos.

Fig. 3.6

3.2. Meniul Încasări

În cadrul acestui meniu se pot face încasări, se pot corecta sau anula încasări deja existente sau se pot vizualiza încasările dintr-o anumită zi la un anumit medic.

Fig. 3.7

Opțiunea Încasare programare

În cadrul acestei ferestre se poate încasa un pacient pe baza medicului la care a fost programat, a datei și orei la care a avut programarea.

Fig. 3.8

Primul lucru care trebuie făcut este să se selecteze medicul la care este făcută programarea. Această selecție se poate face manual din lista ascunsă sau se poate scrie începutul numelui medicului în caseta de text și se va autocompleta numele medicului.

Implicit, caseta Data conține data curentă, care dacă se dorește a fi modificată se va apăsa butonul Alege, care are ca și rezultat deschiderea unui calendar lunar din care se poate selecta o dată (data curentă, anterioară sau viitoare).

În momentul în care este selectată data dorită, în lista ascunsă Ora sunt afișate orele la care există programări făcute pentru respectivul medic în data aleasă. După ce se alege ora la care era făcută programarea, se va autocompleta numele pacientului, intervenția pentru care a fost programat și eventual suma plătită de acesta.

La final se va completa suma care se încasează și din lista ascunsă alăturată se va alege moneda în care se face încasarea.

După realizarea tuturor acestor operații se va apăsa butonul OK pentru a salva încasarea în baza de date sau Renunță pentru a ieși din această fereastră fără a realiza încasarea.

Opțiunea Încasare simplă

Această opțiune este similară opțiunii Încasare programare, însă este mult mai simplă, deoarece nu necesită decât selectarea medicului pentru care se face încasarea din lista ascunsă, a numelui pacientului, a sumei încasate și a monedei în care se face încasarea.

După realizarea acestor operații se va apăsa butonul OK pentru a salva încasarea în baza de date sau Renunță pentru a ieși din această fereastră fără a realiza încasarea.

Acestă opțiune a fost creată cu scopul de a permite un volum mai mare de încasări simplu și rapid.

Fig. 3.9

Opțiunea Corecție încasare (Anulare)

În cadrul acestei ferestre se pot corecta sau anula încasări deja existente.

Primul lucru care trebuie făcut este să se selecteze medicul la care este făcută programarea. Această selecție se poate face manual din lista ascunsă sau se poate scrie începutul numelui medicului în caseta de text și se va autocompleta numele medicului.

Implicit, caseta Data conține data curentă, care dacă se dorește a fi modificată se va apăsa butonul Alege, care are ca și rezultat deschiderea unui calendar lunar din care se poate selecta o dată (data curentă, anterioară sau viitoare).

În momentul în care este selectată data dorită, în lista ascunsă Pacient sunt afișați pacienții pentru care au fost făcute încasări la respectivul medic, în data aleasă. După ce se alege numele pacientului, se va autocompleta suma plătită de acesta.

Pentru a corecta suma încasată se va scrie noua valoare în caseta de text Suma și eventual se va selecta moneda, după care se va apăsa butonul Corectare.

Pentru a anula o încasare se va apăsa butonul Anulare.

Dacă se dorește părăsirea acestei ferestre se va apăsa butonul Renunță.

Fig. 3.10

Opțiunea Încasați

În cadrul acestei ferestre pot fi vizualizate toate încasările efectute la o anumită dată pentru un anumit medic.

Primul lucru care trebuie făcut este să se selecteze medicul. Această selecție se poate face manual din lista ascunsă sau se poate scrie începutul numelui medicului în caseta de text și se va autocompleta numele medicului.

Implicit, caseta Data conține data curentă, care dacă se dorește a fi modificată se va apăsa butonul Alege, care are ca și rezultat deschiderea unui calendar lunar din care se poate selecta o dată (data curentă sau anterioară).

În momentul în care este selectată data dorită, se va autocompleta tabelul care conține informațiile: nume pacient, intervenția realizată, ora încasării, suma încasată și moneda. Sub tabel va apărea numărul total de încasări.

Dacă se dorește părăsirea acestei ferestre se va apăsa butonul Renunță.

Fig. 3.11

3.3. Meniul Evidențe

În cadrul acestui meniu se pot vizualiza sub diverse forme, pentru o anumită zi sau pentru o perioadă, informații despre programări și încasări, cât și informații despre medici.

Fig 3.12 Meniu Evidențe

Opțiunile Programați azi în schimbul 1, Programați azi în schimbul 2

Aceste două opțiuni sunt similare și permit tipărirea la imprimantă a pacienților programați în ziua curentă, în schimbul 1 (8-14) sau în schimbul 2 (14-20) grupați pe medici. Acestea informații sunt necesare pentru a le oferi medicilor, care astfel vor avea astfel informații despre programările pe care le au într-o anumită zi (nume pacient, intervenție, ora programării).

De menționat faptul că aceste opțiuni funcționează doar pentru data curentă. Dacă se dorește vizualizarea programărilor dintr-o altă zi (anterioară sau viitoare) se va folosi opțiunea Programați din meniul Programări.

Pentru a tipări toate programările, trebuie apăsate în mod repetat butoanele Tipărire și >> până la ultimul medic.

Fig. 3.13

Dacă se dorește părăsirea acestei ferestre se va apăsa butonul Închidere.

Ca și observație, în cazul în care există medici care au program atât în schimbul 1 cât și în schimbul 2, aceștia vor primi două hârtii. Deasemenea, există la îndemână și opțiunea alternativă de a alege opțiunea Programați din meniul Programări pentru data curentă, care va conține toate programările medicului din respectiva zi, fără a ține cont de schimburi.

Opțiunea Număr programări/Perioadă

În cadrul acestei ferestre, pe baza datelor selectate De la și Până la, se poate vizualiza numărul total de programări într-o perioadă de timp, defalcate pe schimbul 1 și schimbul 2.

Implicit, casetele de date conțin data curentă, care dacă se dorește a fi modificată se va apăsa butonul Alege, care are ca și rezultat deschiderea unui calendar lunar din care se poate selecta o dată (anterioară sau viitoare).

Fig. 3.14

3.4. Meniul Ore blocate

Fig 3.15 Meniu Ore blocate

Acest meniu are două opțiuni: Adăugare bocaj și Ștergere blocaj.

Un blocaj poate fi de două feluri: blocaj intervale de ore într-o zi sau blocaj pe zile întregi. Acestea sunt necesare a fi ținute în evidență pentru situațiile în care unii medici lipsesc în timpul programului de lucru.

Opțiunea Adăugare blocaj

Prima dată trebuie selectat medicul pentru care se introduce un blocaj, apoi trebuie ales tipul de blocaj. În funcție de aceasta se va introduce un interval orar dintr-o zi aleasă sau un interval de zile.

Opțiunea Ștergere blocaj

Această opțiune se alege când un blocaj existent nu mai este valabil, pentru a fi anulat. Prima dată trebuie selectat medicul pentru care șterge un blocaj, după care din tabelul care apare se bifează liniile care se vor șterge, iar la final se apasă OK.

Fig 3.16 Adăugare blocaj

Fig 3.17 Anulare blocaj

BIBLIOGRAFIE

[1] Eckel Bruce, Thinking in Java, Third Edition, Ed. Prentice Hall, 2002

[2] DuBois Paul, MySQL Cookbook, Ed. O’Reilly, 2007

[3] Tanasă S., Olaru C., Andrei Ș., Java de la 0 la expert, Ed.Polirom, 2007

[4] http://thor.info.uaic.ro/~acf/java/Cristian_Frasinaru-Curs_practic_de_Java.pdf

[5] http://www.aps.ro/dezvoltare_software/medxline

[6] http://www.dec-solutions.eu/hospital/?part=descriere

[7] http://www.med-soft.ro/

[8] http://www.softeh.ro/site/produse.html

BIBLIOGRAFIE

[1] Eckel Bruce, Thinking in Java, Third Edition, Ed. Prentice Hall, 2002

[2] DuBois Paul, MySQL Cookbook, Ed. O’Reilly, 2007

[3] Tanasă S., Olaru C., Andrei Ș., Java de la 0 la expert, Ed.Polirom, 2007

[4] http://thor.info.uaic.ro/~acf/java/Cristian_Frasinaru-Curs_practic_de_Java.pdf

[5] http://www.aps.ro/dezvoltare_software/medxline

[6] http://www.dec-solutions.eu/hospital/?part=descriere

[7] http://www.med-soft.ro/

[8] http://www.softeh.ro/site/produse.html

Similar Posts