Crearea interfetelor grafice. Pachetul java.awt

  1. Introducere
  2. Componente grafice
  3. Ierarhia claselor pentru componente
  4. Obiecte peer
  5. Conceptul Model/View/Controller (MVC)
  6. Afisarea componentelor
  7. Organizarea componentelor

Introducere

    Acest pachet ne ofera o coletie de clase pentru crearea interfetelor grafice. Aceste clase permit lucrul cu ferestre, desenari, lucrul cu imagini si utilizarea componentelor ca butoane, liste, meniuri intr-un mod independent de platforma. Pachetul java.awt contine clasele AWT (Abstract Window Toolkit) GUI iar java.awt.image ne ofera niste facilitati in plus pentru lucrul cu imagini. Dupa cum numele sugereaza AWT este o abstractie. Clasele si functionalitatile oferite sunt aceleasi pentru orice implementare Java. Pentru a obtine independenta de platforma AWT utilizeaza toolkituri interschimbabile care actioneaza cu sistemul de ferestre pe care se ruleaza aplicatia. De exemplu sa presupunem ca aplicatia noastra creaza un buton. Cand se ruleaza aplicatia, toolkitul specific platformei afiseaza butonul conform platformei. Daca aplicatia se ruleaza sub Windows vom obtine un buton de tip Windows, iar daca  se ruleaza sub Unix se va afisa un buton de tip X Windows.
    Utilizarea componentelor din acest pachet este relativ usoara, pe cand toolkiturile GUI sunt foarte complexe, dar aceasta este treaba celor care vor sa implementeze AWT-ul pe o noua platforma.
Realitatea este ca cele mai multe probleme despre Java se ridica la folosirea acestui pachet. Implementarea toolkiturilor pentru acest pachet contin cele mai multe buguri Java. Tocmai din aceasta cauza JavaSoft a introdus Swing care reprezinta noua generatie de componentele grafice si fac parte din JFC (Java Foundation Classes).

Componente grafice

Componentele sunt elementele care se utilizeaza la crearea unei interfete grafice. Componentele sunt incluse in containere, care la randul lor sunt componente speciale. Anumite componente pot fi containere pentru alte componente: de exemplu o fereastra cu doua panouri. In acest caz fereastra este containerul, iar panelele sunt componentele continute. Daca adaugam elemente ca butoane, liste, etichete, casete text etc. in cele doua panouri atunci panoul va fi containerul iar elementele adaugate vor fi componentele.

Ierarhia claselor pentru componente

    Pentru simplitate impartim functionalitatea clasei Component in doua categorii: modul de afisare si comportament. Aceasta  clasa contine metode si variabile care controleaza modul de afisare general al componentei. Aici sunt incluse atributele pentru vizibilitate, marime, pozitie si atribute ca culoarea si fontul. Clasa contine metode abstracte, care sunt implementate de subclasele pentru diferite tipuri de componente, si care determina imaginea grafica a componentei. Prin comportamentul componentei intelegem actiunile componentei la evenimentele primite de la  utilizator. In momentul cand utilizatorul actiuneaza asupra unei componente (de exemplu apsa butonul mouse-ului) un fir de executie AWT informeaza toti receptorii (componentele care vor sa primeasca acest eveniment) despre evenimentul produs. De exemplu la apasarea unui buton se genereaza evenimentul ActionEvent. Cei care vor sa primeasca acest eveniment trebuie sa fie inregistrati, aceasta insemnand ca trebuie sa fie obiecte care respecta interfata ActionListener.
    Evenimentele sunt receptionate de catre obiecte de tip Listener, care la primirea evenimentului apeleaza o metoda de tratare a evenimetului. Obiectele care doresc sa primeasca evenimente trebuie sa implementeze interfetele pentru tipurile de evenimente pe care doresc sa le primeasca. De exemplu evenimentele de tip MouseEvents sunt primite de catre obiectele care respecta interfata MouseListener. Evenimentele reprezinta un mecanism de comunicare intre obiecte (nu numai obiecte grafice). Evenimentele sunt importante mai alesin cazul beanurilor Java.
    Containerele rezolva tratarea evenimentelor pentru toate componentele continute. De obicei containerul se inregistreaza la sursa de evenimente pentru a primi evenimentele necesare pentru o anumita componenta.
 

Peer

In sectiunea precedenta tocmai am descris functionarea acestor componente si evenimentele cu ajutorul carora aceste componente comunica intre ele. Asa sunt privite componentele de Java, dar nu si in lumea reala, adica pe platforma pe care vor fi efectiv afisate componentele. Lumea reala este caracterizata de o anumita arhitectura si de dispozitive fizice. La un anumit nivel obiectele noastre vor comunica cu obiecte care contin metode native pentru mediul  in caare componentele trebuie sa interactioneze. Pentru a tine aceasta interactiune sub control Java utilizeaza interfetele peer.  Aceasta interfata peer face posibila ca o componenta AWT Java  sa utilizeze componenta corespunzatoare din lumea reala - obiectul peer  din mediul nativ. Programele noastre vor lucra cu obiectele AWT Java, restul, partea grea este rezolvata de clasa Component.

    Este important sa intelegem aceasta arhitectura deoarece astfel putem intelege cam ce putem realiza cu componentele. In figura preceedenta se poate vedea ce se intampla la crearea unui buton. Toolkitul este de fapt o "fabrica de componente" native. Java utilizeaza aceasta fabrica pentru a separa funtionalitatea componentelor de modalitatea de implementare pe un sistem de afisare nativ. Obiectul Toolkit contine metode pentru crearea tuturor tipurilor de componente grafice. Daca nu ne place acest Toolkit oferit de mediul Java, putem sa scriem toolkitul nostru propriu.
    Pachetul java.awt.peer contine o interfata pentru fiecare tip de componenta grafica. In acest pachet clasa de baza este ComponentPeer de la care se deriva aproape toate celelalte clase. De exemplu clasei Button ii corespunde clasa ButtonPeer. Apelul metodei setLabel() determina apelul metodei corespunzatoare al obiectului nativ.

Conceptul Model/View/Controller (MVC)

    MVC este o metoda pentru producerea componentelor reutilizabile care sunt caracterizate prin structura, reprezentare si comportament. MVC a fost introdus ca standard in primul rand pentru componentele grafice, dar ideile de baza pot fi aplicate si la alte tipuri de componente. Ideea fundamentala este separarea modelului de reprezentare. Pentru un singur model de date exista mai multe reprezentari diferite. De exemplu datelor dintr-un spreadsheet putem atasa diferite tipuri de grafice. In cazul unei componente de tip Button modelul de date ar fi o valoare logica pentru a reprezenta starea butonului, reprezentarea este modul de afisare, aspectul grafic al butonului, iar evenimentele reprezinta partea de control.
    Comunicarea intre componentele grafice AWT respecta MVC. Receptorii evenimentelor sunt Observatori  iar sursele evenimentelor Observabili. In momentul cand un obiect Observabil isi modifica starea informeaza toti observatorii despre aceasta modificare.
    Conceptul "fabrica de componente" utilizat de catre obiectul Toolkit respecta tot MVC. Aceste "fabrici" utilizeaza  interfetele Java pentru a separa implementarea obiectelor grafice de comportamentul acestora. Componetele native trebuie sa respecte doar anumite interfete, nu trebuie sa se incadreze intr-o ierarhie de clase. Singurul lucru pe care trebuie sa-l faca este implementarea metodelor din interfata.
 

Afisarea componentelor

Componetele pot fi rugate sa se autoafiseze. De exemplu daca fereastra care contine componentele este acoperita de o alta fereastra, in momentul revenirii la fereastra initiala aceasta trebuie reafisata cel putin partial. Cand AWT roaga componenta sa se autoafiseze, aceasta apeleaza metoda paint(). Metoda update() are aceasi functionalitae, dar aceasta prima data sterge suprafata componentei si dupa aceea apeleaz metoda paint(). Componentele nu vor apela direct update(), aceasta metoda fiind apelata de catre repaint(). Aceasta metoda roaga AWT sa programeze componenta in cauza pentru improspatare. Atat paint() cat si update() au un parametru de tip Graphics care reprezinta contextul grafic a componentei in cauza. Corespunde suprafetei ecran pe care componenta poate desena. Acesta este mecanismul utilizat de componente pentru autoafisare. Noi vom utiliza aceste metode doar in cazul containerelor speciale, adica in cazul obiectelor de tip Panel, Canvas si Applet.
 

Organizarea componentelor

Un organizator al componentelor este un obiect care stabileste marimea si pozitia componentelor in cadrul unui container. Fiecare container are un organizator implicit care in caz de necesitate poate fi modificat. Containerele principale sunt diferitele tipuri de ferestre, apleturi, panele etc. In cazul ferestrelor organizatorul implicit este un obiect de tip BorderLayout, iar in cazul apleturilor si ale panourilor unul de tip FlowLayout. Clasele principale organizatori de componente sunt: FlowLayot, GridLayout,CardLayout, BorderLayout si GridBagLayout.

FlowLayout organizeaza componentele de la stanga la dreapta si daca se umple randul curent atunci componetul urmator va fi plasat in randul urmator. Inaltimea randului este data de componenta de cea mai mare inaltime pe randul respectiv.
 

FlowLayout fLayout = new FlowLayout();
setLayout( fLayout );
Button butonOk = new Button("Ok");
add(butonOk);
Button butonCancel = new Button("Cancel");
add(butonCancel);


sau scris mai compact:

setLayout( new FlowLayout());
add( new Button("Ok"));
add( new Button("Cancel"));


Organizatorul centreaza componentele adaugate, dar acest tip de aliniere poate fi schimbata prin metoda setAlignment(). Metoda primeste ca parametru tipul alinierii. Tipurile de aliniere posibile sunt definite ca constante in clasa FlowLayout (LEFT, RIGHT, CENTER)  si se utilizeaza in modul urmator:

FlowLayout fLayout = new FlowLayout();
fLayout.setAlignment(FlowLayout.LEFT)
setLayout( fLayout );


BorderLayout aranjeaza componentele in cinci regiuni: Nord, Sud, Vest, Est si Centru. La adaugarea componentelor utilizand acest organizator trebuie specificat pe langa componenta adaugata si regiunea la care se adauga. Atat BorderLayout cat si CardLayout permite specificarea spatiului intre componente indicand numarul de pixeli pe orizontala respectiv pe verticala.

setLayout( new BorderLayout(), 10,6);
add( new Button("Unu"),"North");
add( new Button("Doi"),"East");
add( new Button("Trei"),"South");
add( new Button("Patru"),"West");


CardLayout (teanc de carti) se utilizeaza la organizarea componentelor care nu incap pe o anumita suprafata. Componentele sunt organizate pe aceste carti dintre care unul singurul se va vedea pe ecran. Visual Caffe introduce ferestrele cu mai multe pagini care pot inlocui acest organizator.

GridLayout imparte suprafata in randuri si coloane permitand aranjarea componentelor in aceste celule de dimensiuni egale. Componentele sunt plasate in celule incepand cu primul rand dupa aceea urmatorul rand si asa mai departe.

GridBagLayout este organizatorul cel mai avansat. Lucreaza asemanator ca GridLayout. Principala diferenta fata de acesta este ca in caul acestui organizator o componenta poate ocupa mai mult decat o singura celula.

Un container poate sa contina la randul lui alte containere si fiecare dinntre aceste containere avand propriul organizator. De exemplu o fereastra continand mai multe panele.