Documente Academic
Documente Profesional
Documente Cultură
Curs – 8
Aspectul de pana acum al unei interfete grafice AWT era oarecum relativ -
redimensionarea ferestrei putand modifica intreaga dispunere in fereastra. Aceasta
maleabilitate a interfetei grafice apare in Java datorita posibilitatii sale de a rula pe
diferite platforme care trateaza diferit elementele componente ale unei interfete
grafice.
Pentru a introduce un control mai strict asupra aspectului interfetei noastre Java ne
pune la dispozitie pentru pachetul AWT un numar de 5 administratori de dispunere.
Acest administrator nou creat trebuie apoi declarat ca administrator pentru container
cu ajutorul metodei setLayout(). Administratorul de dispunere trebuie stabilit inainte
de a adauga componente containerului. Daca nu este stabilit un administrator explicit
atunci apare automat cel de dispunere secventiala (FlowLayout).
In exemplul de mai jos avem inceputul unui applet care foloseste un administrator de
dispunere:
import java.awt.*;
public class Tabelare extends java.applet.Applet {
GridLayout tabelul=new GridLayout(3,3,10,10);
Button b1=new Button("Steaua");
Button b2=new Button("Astra");
Button b3=new Button("Petrolul");
Button b4=new Button("Vaslui");
Button b5=new Button("CFR");
Button b6=new Button("Pandurii");
Button b7=new Button("U Cluj");
Button b8=new Button("Chiajna");
Button b9=new Button("FC Brasov");
add(string, componenta);
Primul argument are valori intre: "North", "South", "East", "West" si "Center". Al
doilea argument este chiar componenta care trebuie adaugata.
Programul de mai jos implementeaza un administrator de dispunere marginala:
import java.awt.*;
public class Margini extends java.applet.Applet {
BorderLayout b=new BorderLayout(10,15);
Button nord=new Button("Nord");
Button sud=new Button("Sud");
Button est=new Button("Est");
Button vest=new Button("Vest");
Button centru=new Button("Centru");
Pentru a realiza o interfata grafica practica si utila trebuie de fapt sa folosim mai multi
administratori pentru aceeasi interfata. Acest lucru se poate face adaugand mai multe
containere intr-un container principal, ca fereastra applet, fiecare avand un alt
administrator de dispunere.
Aceste containere mai mici se numesc panouri si sunt derivate din clasa Panel.
Panourile sunt folosite pentru a grupa diferite componente. Atunci cand lucram cu ele
trebuie sa retinem cateva lucruri:
add(string, container);
Primul argument al metodei este un sir care reprezinta numele cardului. Al doilea
argument specifica containerul sau componenta care reprezinta cardul. Daca este
vorba de un container acesta trebuie sa contina deja toate componentele necesare lui.
Dupa ce am adaugat cardul in containerul principal al programului putem folosi
metoda show() a administratorului de dispunere in stiva pentru a afisa o anumita
cartela. Metoda show() primeste doua argumente:
import java.awt.*;
public class Carduri extends java.applet.Applet implements Runnable {
Aceasta parte se realizeaza pe hartie, unde vom schita interfata grafica. Fiecare
componenta a interfetei trebuie plasata intr-o celula separata - desi o componenta
poate ocupa mai multe celule.
Nume
Parola
OK
0,0 1,0
Nume
0,1 Parola 1,1
0,2 OK 1,2
Aici mai apar restrictiile care sa aranjeze componentele in cadrul celulelor. Avem
doua astfel de restrictii: fill si anchor.
Restrictia fill determina - pentru componentele care se pot extinde in orice directie - in
ce directie se face aceasta extindere (cum ar fi casetele de text sau butoanele).
Restrictia fill poate avea una dintre urmatoarele patru valori, definite drept variabile
de clasa in GridBagConstrints:
A doua restrictie care afecteaza aparitia unei componente intr-o celula este anchor.
Aceasta se aplica doar componentelor care nu umplu intreaga celula si indica
functiilor AWT unde sa plaseze componenta in cadrul celulei. Valorile posibile pentru
aceasta restrictie sunt:
- GridBagConstraints.NORTH
- GridBagConstraints.NORTHEAST
- GridBagConstraints.SOUTH
- GridBagConstraints.SOUTHWEST
- GridBagConstraints.EAST
- GridBagConstraints.SOUTHEAST
- GridBagConstraints.WEST
- GridBagConstraints.NORTHWEST
- GridBagConstraints.CENTER
In realitate aceasta etapa apare aproape totdeauna; pentru ca totul sa arate perfect va
trebui sa mai facem anumite modificari ale unor restrictii de obicei.
In listingul de mai jos avem un exemplu complet de creare a unui applet care
implementeaza o interfata grafica similara celei prezentate in etapa intai a constructiei
teoretice a unei interfete ce foloseste un administrator de dispunere tabelara
neproportionala:
import java.awt.*;
void definireRestrictii(GridBagConstraints gbc, int gx, int gy, int gw, int gh, int wx,
int wy) {
gbc.gridx=gx;
gbc.gridy=gy;
gbc.gridwidth=gw;
gbc.gridheight=gh;
gbc.weightx=wx;
gbc.weighty=wy;
}
definireRestrictii(restrictii,0,0,1,1,10,40);
restrictii.fill=GridBagConstraints.NONE;
restrictii.anchor=GridBagConstraints.EAST;
Label eticheta1=new Label("Nume:",Label.LEFT);
tabelnp.setConstraints(eticheta1,restrictii);
add(eticheta1);
definireRestrictii(restrictii,1,0,1,1,90,0);
restrictii.fill=GridBagConstraints.HORIZONTAL;
TextField tfnume=new TextField();
tabelnp.setConstraints(tfnume,restrictii);
add(tfnume);
definireRestrictii(restrictii,0,1,1,1,0,40);
restrictii.fill=GridBagConstraints.NONE;
restrictii.anchor=GridBagConstraints.EAST;
Label eticheta2=new Label("Parola:",Label.LEFT);
tabelnp.setConstraints(eticheta2,restrictii);
add(eticheta2);
definireRestrictii(restrictii,1,1,1,1,0,0);
restrictii.fill=GridBagConstraints.HORIZONTAL;
TextField tfparola=new TextField();
tfparola.setEchoCharacter('*');
tabelnp.setConstraints(tfparola,restrictii);
add(tfparola);
definireRestrictii(restrictii,0,2,2,1,0,20);
restrictii.fill=GridBagConstraints.NONE;
restrictii.anchor=GridBagConstraints.CENTER;
Button butonok=new Button("OK");
tabelnp.setConstraints(butonok,restrictii);
add(butonok);
}
}
In afara restrictiilor discutate anterior mai trebuie amintite inca doua restrictii ipadx si
ipady. Acestea doua controleaza bordurile - spatiul care inconjoara o componenta
dintr-un panou. In mod prestabilit componentele nu au nici un spatiu liber in jurul lor.
Restrictia ipadx adauga un spatiu in stanga si in dreapta componentei iar ipady adauga
deasupra si dedesubtul componentei.
Pentru a determina spatiul lasat in jurul unui panou putem folosi insertiile (insets).
Clasa Insets contine valori pentru insertiile din partea de sus, de jos, din stanga si din
dreapta, valori folosite la desenarea panoului.
Insertiile determina spatiul dintre marginile panoului si componentele acestuia.
Pentru a modifica insertiile trebuie sa suprascriem metoda insets() - in Java 1.02, sau
metoda getInsets() din Java2 - ambele metode realizand acelasi lucru.
In cadrul metodei getInsets() (sau insets()) se creaza un nou obiect Insets unde
constructorul clasei primeste ca argumente patru valori intregi reprezentand insertiile
pentru partea de sus, din stanga, de jos si din dreapta panoului. Metoda va returna apoi
obiectul Insets. In continuare avem o prezentare a codului necesar pentru adaugarea
insertiilor intr-o dispunere tabelara: 10 pentru partea de sus si de jos si 30 pentru
laterale:
Pana acum am vazut cum se poate crea o interfata grafica utilizator - problema este ca
aceasta interfata nu poate face deocamdata mai nimic ☺. In cele ce urmeaza vom
vedea modul in care putem determina un applet sa trateze diferite evenimente folosind
tehnici Java 1.02.
O interfata functionala trebuie sa fie capabila sa raspunda la evenimente - acestea
reprezentand apeluri de metode pe care sistemul de ferestre Java le face ori de cate ori
se interactioneaza cu un element al interfetei grafice create de utilizator.
METODA handleEvent()
Tratarea evenimentelor in Java 1.02 se face prin metoda handleEvent(). Aceasta este
definita in clasa Component care este mostenita de java.applet.Applet - devenind
astfel disponibila appleturilor.
Cand un eveniment este transmis metodei handleEvent() aceasta apeleaza o metoda
specifica de tratare a evenimentului respectiv. Pentru a trata un anumit eveniment va
trebui sa suprascriem aceste metode specifice. Apoi, la aparitia evenimentului
respectiv metoda noua va fi apelata si executata.
In listingul de mai jos vom vedea un applet care va trata apasarea mouseului - la
fiecare clic de mouse in fereastra este desenata o pata, pana la totalul de maxim 15
pete:
import java.awt.*;
2. Dublu clicuri
Clasa Event din Java poseda o variabila denumita clickCount care pastreaza aceasta
informatie. clickCount este o variabila intreaga care contine numarul de clicuri
consecutive aparute - consecutivitatea este determinata de sistemul de operare sau de
hardwareul mouseului. In cazul in care vrem sa tratam ca evenimente clicuri multiple
trebuie sa testam valoarea variabilei sus amintite in corpul metodei noastre:
Daca rulam un program care implementeaza aceasta metoda si executam un triplu clic
rezultatul obtinut va fi:
Numar de clicuri: 1
Numar de clicuri: 2
Numar de clicuri: 3
3. Miscarile mouseului
AWT defineste doua tipuri distincte de miscari ale mouseului: tragerea sa - miscarea
se face cu butonul semnificativ apasat, si miscarea simpla - cu butonul neapasat.
Evenimentele de mai sus sunt interceptate si tratate cu ajutorul metodelor
mouseDrag() si mouseMove().
Metoda mouseMove() seamana mult cu metodele care tratau clicurile de mouse:
Pentru a utiliza aceste evenimente si a le trata vom prezenta un exemplu de applet care
traseaza linii drepte pe ecran prin tragerea mouseului dintr-un punct in altul. Numarul
de linii va fi restrictionat la 20:
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.awt.Point;
Un astfel de eveniment apare ori de cate ori este apasata o tasta. Pentru ca un
eveniment de tastatura sa fie receptionat de catre o componenta trebuie ca aceasta sa
fie selectata, sau focalizata - focused. Pentru a indica explicit selectarea unei
componente pentru a primi date de intrare putem apela metoda requestFocus() a
componentei respective, ca in exemplul de mai jos care presupune ca avem un buton
denumit "buton1":
buton1.requestFocus();
Putem selecta chiar intreaga fereastra Applet prin apelarea metodei sale
requestFocus().
EVENIMENTELE keyDown si keyUp
Metodele care asigura tratarea unui eveniment de tastatura sunt de urmatoarea factura:
caracter=(char)tasta;
In exemplul de mai jos avem o metoda care afiseaza exact tasta pe care am apasat, ca
si caracter si ca valoare Unicode:
TASTE PRESTABILITE
Clasa Event are un set de variabile de clasa care reprezinta unele taste nealfanumerice
ca tastele functionale sau cele directionale. Daca interfata appletului nostru foloseste
aceste taste putem testa folosirea lor in cadrul metodei keyDown(). Valorile acestor
variabile de clasa sunt intregi, acest lucru fiind important mai ales pentru folosirea
instructiunii switch in cadrul testarii acestor variabile. Mai jos este prezentat un tabel
care arata variabilele de clasa amintite mai sus:
import java.awt.*;
public class Taste extends java.applet.Applet {
char tastaCrt;
int xCrt;
int yCrt;
Aceste taste nu genereaza evenimente proprii insa atunci cand tratam un eveniment
obisnuit - de tastatura sau mouse - putem testa daca vreuna dintre aceste trei taste a
fost apasata pe durata evenimentului.
Clasa Event ofera trei metode pentru a testa apasarea uneia dintre tastele amintite mai
sus: shiftDown(), metaDown() si controlDown(). Toate aceste metode returneaza
valori booleene in functie de starea de apasare a tastelor respective.
Tasta Meta este echivalentul tastei ALT pe PC si al tastei Command pe MacIntosh.
Putem apela la aceste metode in oricare dintre metodele de tratare a evenimentelor
prin apelarea lor pentru obiectul eveniment transmis metodei:
Aceste metode mai pot fi folosite si pentru a testa care dintre butoanele mouseului au
generat un anumit eveniment de mouse in cazul sistemelor cu doua sau trei butoane
ale mouseului. In mod prestabilit evenimentele de mouse sunt generate indiferent de
butonul apasat. Totusi Java asociaza apasarile pe butonul din drepta sau din mijloc cu
apasarile tastelor de modificare Meta si Control asa ca prin testarea acestor taste se
poate afla butonul de mouse care a fost apasat. Prin testarea tastelor de modificare
putem afla care buton de mouse a fost folosit executand alte actiuni diferite decat cele
pe care le-am fi folosit in mod normal pentru butonul din stanga. Se poate folosi
instructiunea if pentru a testa fiecare caz, ca in exemplul de mai jos:
Metodele prestabilite prezentate mai sus sunt apelate de o metoda generica de tratare a
evenimentelor - handleEvent(). La folosirea ei, AWT trateaza in mod generic
evenimentele care apar intre componentele aplicatiei sau evenimentele datorate
actiunilor utilizatorului.
In metoda handleEvent() se proceseaza evenimentele de baza si se apeleaza metodele
despre care am vorbit mai devreme. Pentru a trata si alte evenimente decat cele
mentionate deja, pentru a modifica comportamentul implicit de tratare a
evenimentelor sau pentru a crea si a transmite propriile evenimente va trebui sa
suprascriem metoda handleEvent(). Ea are o semnatura de forma:
In ceea ce priveste evenimentele de mouse putem testa si in cazul lor mai multe
evenimente:
Aceste evenimente au loc pe componente de genul butoane, zone de text sau alte
elemente ale interfetelor grafice utilizator. Spre exemplu butoanele folosesc
evenimente declansate la apasarea lor; nu mai conteaza evenimentele mouse down sau
mouse up sau locul unde a aparut un clic - componenta se va ocupa de tratarea tuturor
acestor evenimente.
Exista trei tipuri de evenimente ce pot fi generate prin interactiunea cu componentele
interfetei:
In metoda action() primul lucru facut este testarea componentei care a generat
actiunea. Obiectul Event pe care il primim ca argument in apelul action() contine o
variabila de instanta numita target, care contine o referinta catre obiectul ce a generat
evenimentul. Putem folosi operatorul instanceof pentru a afla ce componenta a
generat evenimentul, ca in exemplul de mai jos:
Aceste liste genereaza trei tipuri de evenimente; selectarea sau deselectarea unui
element din lista are ca efect un eveniment de selectare/deselectare din lista iar dublul
clic executat pe un element al listei are ca efect un eveniment de actiune.
Putem suprascrie metoda action() pentru a trata elementul din lista pe care s-a efectuat
dublu clic. Pentru selectiile si deselectiile din lista putem suprascrie metoda
handleEvent() si apoi sa testam identificatorii de evenimente LIST_SELECT si
LIST_DESELECT.
Toate detaliile teoretice de pana acum s-ar putea sa para greu de inteles fara o
exemplificare practica. Tocmai pentru a arata utilizarea diferitelor evenimente si
tratarea lor vom prezenta un applet care va avea cinci butoane cu denumirea a cinci
culori; la executarea unui clic pe oricare buton fondul appletului se va modifica la
culoarea inscrisa pe buton si va apare un text care ne va anunta culoarea pe care am
selectat-o.
Intr-o prima etapa a construirii appletului nostru vom crea componentele si se va
stabili modul lor de dispunere in fereastra. In exemplul nostru vom folosi un
administrator de dispunere de tip FlowLayout pe care il vom aplica apoi containerului
nostru.
Odata cu apasarea butoanelor noastre se vor genera evenimente de actiune. Pentru
tratarea lor vom folosi metoda action() care in practica va realiza mai multe lucruri:
Pentru a modulariza cat mai corect codul sursa vom crea o metoda action() care va
apela in fapt o alta metoda schimbaCuloare(); aceasta metoda primeste ca argument
chiar obiectul buton care a initiat evenimentul.
Folosind faptul ca argumentul suplimentar al metodei action() este eticheta (in cazul
butoanelor) putem afla care dintre butoane a fost apasat. In cazul de fata nu vom mai
folosi solutia comparatiei etichetei butonului cu un anumit text. Obiectul transmis ca
argument metodei schimbaCuloare() este o instanta a clasei Button iar una dintre
variabilele de instanta este o referinta la acelasi obiect. In metoda noastra vom
compara cele doua variabile pentru a testa daca este vorba de acelasi obiect, dupa care
vom stabili culoarea de fond si apelam metoda repaint().
In continuare avem si listingul complet al aplicatiei comentate in randurile anterioare:
import java.awt.*;
butonRosu=new Button("Rosu");
add(butonRosu);
butonAlbastru=new Button("Albastru");
add(butonAlbastru);
butonVerde=new Button("Verde");
add(butonVerde);
butonAlb=new Button("Alb");
add(butonAlb);
butonNegru=new Button("Negru");
add(butonNegru);
}
void schimbaCuloare(Button b) {
if (b==butonRosu) { setForeground(Color.white);sir="Fond
rosu";setBackground(Color.red);}
else if (b==butonAlbastru) { setForeground(Color.white);sir="Fond
albastru";setBackground(Color.blue);}
else if (b==butonVerde) { setForeground(Color.red);sir="Fond
verde";setBackground(Color.green);}
else if (b==butonAlb) { setForeground(Color.red);sir="Fond
alb";setBackground(Color.white);}
else { setForeground(Color.white);sir="Fond
negru";setBackground(Color.black);}
repaint();
}