Sunteți pe pagina 1din 15

Programare Java

Curs – 10

MANAGEMENTUL UNEI INTERFETE GRAFICE

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 .

DISPUNEREA COMPONENTELOR UNEI INTERFETE

Un administrator de dispunere determina modul in care vor fi aranjate componentele


unui contatiner . Administratorul implicit al Java este clasa FlowLayout . Ea permite
dispunerea secventiala a obiectelor , de la stanga la dreapta si de sus in jos .
Pachetul AWT poate folosi inca patru administratori : GridLayout , BorderLayout ,
CardLayout si GridBagLayout .
Pentru a crea un administrator pentru un container se creaza o instanta a clasei
container folosind o instructiune de tipul :

FlowLayout administrator=new FlowLayout();

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 :

public class Inceput extends java.applet.Applet {


FlowLayout ad=new FlowLayout();
public void init() {
setLayout(ad);
}
}

ADMINISTRATORUL DE DISPUNERE SECVENTIALA ( FlowLayout )

Daca foloism constructorul FlowLayout() fara argumente toate componentele de pe


fiecare rand vor fi automat centrate . Daca vrem ca alinierea sa se faca explicit trebuie
sa utilizam ca argument pentru constructor una dintre variabilele de clasa
FlowLayout.LEFT sau FlowLayout.RIGHT sau chiar FlowLayout.CENTER .
In mod automat administratorul de dispunere secventiala lasa un spatiu de trei pixeli
intre componente pe un rand si tot cate trei pixeli intre randuri . Daca vrem sa
modificam aceste caracteristici putem folosi un constructor de genul :

FlowLayout(int, int, int)

Acesta primeste ca argumente :

- alinierea ( o variabila de clasa )


- spatiul in pixeli dintre componente pe orizontala
- spatiul in pixeli pe verticala intre linii

ADMINISTRATORUL DE DISPUNERE TABELARA ( GridLayout )

Acesta aranjeaza componentele intr-un tabel de randuri si coloane . Componentele


sunt adaugate incepand cu celula aflata cel mai in stanga pe primul rand si continuand
spre dreapta . In continuare se va trece la urmatoarea linie si tot asa mai departe .
Clasa care implementeaza acest administrator este GridLayout . Un constructor al
acestei clase primeste doua argumente : numarul de linii si numarul de coloane al
tabelului in care se va imparti containerul .
Exista si posibilitatea de a utiliza inca doua argumente care sa exprime spatiul pe
orizontala si pe verticala intre componente . Spatiul implicit intre componentele
administrate in acest mod este 0 pixeli pe ambele directii .
Trebuie facuta neaparat o observatie legata de acest administrator de dispunere :
componentele vor ocupa totdeauna intregul spatiu al celulei in care trebuie sa se
integreze .

In exemplul de mai jos avem un applet ce creaza un tabel cu 9 celule spatiate la 10


pixeli atat pe verticala cat si pe orizontala :

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("Dinamo");
Button b3=new Button("Rapid");
Button b4=new Button("National");
Button b5=new Button("Bacau");
Button b6=new Button("Astra");
Button b7=new Button("Otelul");
Button b8=new Button("Sportul");
Button b9=new Button("Petrolul");

public void init() {


setLayout(tabelul);
add(b1);
add(b2);
add(b3);
add(b4);
add(b5);
add(b6);
add(b7);
add(b8);
add(b9);
}
}

ADMINISTRATORUL DE DISPUNERE MARGINALA ( BorderLayout )

Administratorul BorderLayout imparte un container in 5 zone : nord , sud , est , vest si


centru . In cadrul acestei dispuneri componentele din cele patru directi de baza vor
ocupa spatiul pe care il necesita iar centrul va primi restul de spatiu .
Exista doua versiuni ale constructorului clasei BorderLayout : fara nici un parametru
sau cu doi parametri . Prima varianta creaza o dispunere fara spatiere intre
componente in timp ce a doua varianta permite specificarea distantei in pixeli pe
orizontala si pe verticala dintre componente .
Dupa crearea si aplicarea administratorului de acest tip adaugarea componentelor in
container se face cu o metoda de genul :

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");

public void init() {


setLayout(b);
add("North",nord);
add("South",sud);
add("East",est);
add("West",vest);
add("Center",centru);
}
}

COMBINAREA ADMINISTRATORILOR DE DISPUNERE


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 :

- panoul se umple cu componente inainte de a fi introdus in containerul mai


mare
- panoul are propriul administrator de dispunere

Un panou este creat simplu :

Panel panou=new Panel();

Panoului i se atribuie o metoda de dispunere cu ajutorul lui setLayout() . Acesta


functioneaza identic cu setLayout() pentru containere normale . Componentele sunt
adaugate intr-un panou cu metoda add() a acestuia .

ADMINISTRATORUL DE DISPUNERE IN STIVA ( CardLayout )

Dipsunerea in stiva difera de celelalte deoarece ascunde practic unele componente . O


astfel de dispunere inseamna de fapt un grup de containere sau componente afisate
cate unul pe rand - fiecare container din grup fiind numit un card .
In mod normal acest administrator foloseste un panou pentru fiecare card . Mai intai
se introduc componentele in panouri si apoi acestea se introduc in containerul de baza
pentru care s-a stabilit o dispunere in stiva .
Clasa care implementeaza acest administrator este CardLayout .
Dupa ce am stabilit un container cu administrare a dispunerii in stiva trebuie sa
adaugam cardurile sale cu ajutorul unei metode add() de forma :

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 :

- primul este containerul in care au fost adaugate cardurile ; daca respectivul


container este chiar fereastra principala a appletului putem folosi cuvantul
cheie this ca argument
- numele cardului

In cele ce urmeaza se va prezenta o modalitate bazata pe fire de executie pentru a


trece de la un card la altul :
import java.awt.*;

public class Carduri extends java.applet.Applet implements Runnable {

CardLayout cartela=new CardLayout();


Label[] etichete=new Label[6];
int crt=0;
Thread executabil;

public void start() {


if (executabil==null) {
executabil=new Thread(this);
executabil.start();
}
}

public void stop() {


executabil=null;
}

public void init() {


etichete[0]=new Label("Textul 1");
etichete[1]=new Label("Urmeaza textul 2");
etichete[2]=new Label("Apoi textul 3");
etichete[3]=new Label("Dupa care vine textul 4");
etichete[4]=new Label("Urmat de textul 5");
etichete[5]=new Label("Si in final apare textul 6");
setLayout(cartela);
for (int i=0;i<6;i++)
add("Cartela "+i,etichete[i]);
}

public void run() {


Thread firExecutie=Thread.currentThread();
while (executabil==firExecutie) {
cartela.show(this,"Cartela "+crt);
crt++;
if (crt>5)
crt=0;
repaint();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
}
}
}
ADMINISTRATORUL DE DISPUNERE TABELARA NEPROPORTIONALA
(GridBagLayout )

Acesta administrator reprezinta de fapt o extensie a dispunerii tabelare . Exista cateva


diferente intre aceasta dispunere si cea tabelara standard :

- o componenta poate ocupa mai multe celule ale tabelului


- proportiile intre diferitele randuri sau coloane nu trebuie sa fie aceeasi
- componentele dispuse in cadrul celulelor pot fi aranjate in diferite moduri

Pentru a crea o astfel de dispunere se folosesc clasa GridBagLayout si clasa


GridBagConstraints . Prima clasa este chiar administratorul de dispunere iar cea de a
doua este folosita pentru a defini constrngerile fiecarei componente ce va fi plasata
intr-o celula - pozitia , dimensiunile , alinierea , etc .
In forma generala crearea unei dispuneri tabelare neproportionale presupune cativa
pasi :

- crearea unui obiect GridBagLayout si stabilirea sa ca administrator de


dispunere curent
- crearea unei noi instante a clasei GridBagConstraints
- definirea restrictiilor pentru o componenta
- anuntarea componentei si a restrictiilor sale in administratorul de dispunere
- introducerea componentei in container

Pentru realizarea in practica a unei astfel de dispuneri sa luam un exemplu direct :

- prima etapa : proiectarea tabelului

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 .

Schita noastra sa presupunem ca este ceva de genul :

Nume
Parola

OK

La pasul urmator ar trebui sa tabelam deja interfata noastra etichetand celulele cu


coordonatele lor x , y :

0,0 1,0
Nume
0,1 Parola 1,1

0,2 OK 1,2
- etapa a doua : crearea tabelului

In aceasta etapa ne vom axa pe dispunere doar asa ca vom folosi doar niste butoane
care sa tina locul elementelor reale ce vor apare pe panou .
Pentru usurinta specificarii restrictiilor vom defini o metoda care preia mai multe
valori si stabileste restrictiile pentru aceastea . Metoda definireRestrictii() preia sapte
argumente : un obiect GridBagConstraints si sase intregi care reprezinta variabilele
gridx, gridy, gridwidth, gridheight, weightx si weighty .
Primele doua argumente reprezinta valorile coordonatelor celulei respective - in cazul
in care o componenta ocupa mai multe celule coordonatele date sunt cele ale celului
aflate cea mai in stanga-sus ca pozitie .
Urmatoarele doua argumente reprezinta numarul de celule pe care le ocupa
componenta : gridwidth pentru coloane si gridheight pentru linii .
Ultimele doua argumente sunt date pentru latimea si inaltimea celulei - ca proportii
din totalul pe orizontala respectiv verticala .
Pentru atribuirea restrictiilor unui obiect se foloseste metoda setConstraints() ; aceasta
preia doua argumente : componente si restrictiile acesteia . Dupa ce toate acestea s-au
realizat componenta poate fi adaugata in panou .
Crearea de fapt a dispunerii se face in metoda init() . Aici vom defini un administrator
de dispunere GridBagLayout si se creaza un obiect pentru restrictii .
La finalul acestei etape trebuie sa verificam aspectul functional al tabelului , daca are
numarul corect de linii si coloane , daca unele componente care ocupa mai multe
celule sunt prezentate corect si daca nu apar alte anomalii vizibile .

- etapa a treia : determinarea proportiilor

Acum se vor determina proportiile liniilor si coloanelor in relatiile cu alte linii si


coloane . Cel mai usor este sa luam valorile weightx si weighty ca procente din
latimea si inaltimea totale ale panoului . In acest caz valorile insumate pentru toate
variabilele weightx si weighty trebuie sa fie 100 .
Celulele care ocupa mai multe linii sau coloane trebuie sa aiba totdeauna valoarea o in
directia in care se extind . In afara de acest lucru trebuie sa ne hotaram doar asupra
celulei care va primi o valoare ; toate celelalte de pe rand sau de pe coloana trebuie sa
aiba valoarea 0 .
Scopul acestei etape este de a incerca sa stabilim proportiile de baza ale liniilor si
celulelor care vor apare pe ecran . In general in aceasta etapa vor apare mai multe
incercari pana la obtinerea rezultatului dorit .

- etapa a patra : adaugarea si aranjarea componentelor

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 :

- GridBagConstraints.BOTH - determina extinderea pentru a umple celula in


ambele directii
- GridBagConstraints.NONE - determina afisarea la dimensiunea mimina
necesara componentei
- GridBagConstraints.HORIZONTAL - determina extinderea pe orizontala
- GridBagConstraints.VERTICAL - determina extinderea pe verticala

Implicit restrictia fill are valoarea NONE pentru toate componentele .

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

Valoarea prestabilita pentru ancorare este GridBagConstraints.CENTER .

- etapa a cincea : ajustari

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.*;

public class NumeParola extends java.applet.Applet {

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;
}

public void init() {


GridBagLayout tabelnp=new GridBagLayout();
GridBagConstraints restrictii=new GridBagConstraints();
setLayout(tabelnp);

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 comonentele 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 :

public Insets getInsets() {


return new Insets(10,30,10,30);
}

INTERACTIUNEA UTILIZATORULUI CU UN APPLET

Pana acum am vazut cum se poate crea o interfata grafica utilizator - problema este ca
aceasta interfata nu poate face deocamdata nimic ! In cele ce urmeaza vom vedea
modul in care putem determina un applet sa trateze diferite evenimente folosind
tehnici din Java 1.02 - limbajul cel mai raspandit inca pentru crearea appleturilor .
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 .

Un eveniment este generat ca raspuns la aproape orice actiune pe care o poate


intreprinde un utilizator . In programele noastre nu trebuie tratate toate evenimentele -
ne vom ocupa de fapt doar de cele la care vrem sa reactioneze programul nostru
ignorand restul . Intre evenimentele care pot fi tratate amintim : clicuri demouse ,
miscari ale mouseului , apasari de taste sau evenimente ale interfetei grafice
utilizatoru ( clicuri pe diferite componente , derulari de liste , etc ) .

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 hendleEvent() 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 .

TRATAREA CLICURILOR DE MOUSE

1. Evenimentele mouse down si mouse up


La executarea unui clid de mouse apar de fapt doua evenimente : mouse down , la
apasarea butonului si mouse up la eliberarea butonului mouseului .
Semnatura metodei pentru evenimentul mouse down este :

public boolean mouseDown(Event evt, int x, int y) {


...
}

Metoda - ca si mouseUp() de altfel - primeste trei argumente : evenimentul si


coordonatele x si y unde a aparut evenimentul .
Argumentul evt este o instanta a clasei Event . Toate evenimentele genereaza o
instanta a clasei Event care contine informatii privind locul si perioada cand a avut loc
evenimentul , tipul sau si alte informatii .
De exemplu putem crea o metoda care sa afiseze coordonatele punctului unde s-a
executat un clic de mouse :

public boolean mouseDown(Event evt, int x, int y) {


System.out.println("Mouse apasat la coordonatele "+x+" , "+y);
return true;
}

Trebuie metionat ca aceasta metoda returneaza o valoare booleana , spre deosebire de


majoritatea metodelor folosite pana acum . Valoarea de retur true sau false a unei
metode de tratare de evenimente determina daca o anumita componenta poate
intercepta evenimentul sau daca trebuie sa il transmita mai departe altor componente .
Regula este ca daca metoda intercepteaza si trateaza evenimentul ea trebuie sa
returneze true ; daca metoda ignora evenimentul ea trebuie sa returneze false pentru ca
celelalte componente ale interfetei sa aiba sansa de a trata ele evenimentul .

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.*;

public class Pete extends java.applet.Applet {


final int MAXPETE=15;
int xpete[]=new int[MAXPETE];
int ypete[]=new int[MAXPETE];
int pataCrt=0;

public void init() {


setBackground(Color.yellow);
}

public boolean mouseDown(Event evt, int x, int y) {


if (pataCrt<MAXPETE) {
adaugaPata(x,y);
return true;
}
else {
System.out.println("Prea multe pete");
return false;
}
}

void adaugaPata(int x, int y) {


xpete[pataCrt]=x;
ypete[pataCrt]=y;
pataCrt++;
repaint();
}

public void paint(Graphics ecran) {


ecran.setColor(Color.blue);
for (int i=0;i<pataCrt;i++) {
ecran.fillOval(xpete[i]-10,ypete[i]-10,20,20);
}
}
}

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 :

public boolean mouseDown(Event evt, int x, int y) {


switch (evt.clickCount) {
case 1: // clic simplu
case 2: // clic dublu
case 3: // clic triplu
}
}

Metoda mouseDown() este de fapt apelata pentru fiecare clic in parte .


Ca sa fie mai clar sa luam exemplul :

public boolean mouseDown(Event evt, int x, int y) {


System.out.println("Numar de clicuri : "+evt.clickCount);
return false;
}

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 :

public boolean mouseMove(Event evt, int x, int y) {


...
}

Meotda mouseDrag() are o semnatura similara si mai trebuie sa mentionam ca in


ambele metode argumentele pentru coordonatele x si y reprezinta noua pozitie a
mouseului si nu cea initiala .

Metodele mouseEnter() si mouseExit() sunt apelate cand mouseul patrunde sau


paraseste un applet sau o portiune a acestuia . Ambele metode au semnaturi similare
cu cele intalnite mai inainte , coordonatele x si y referindu-se aici la puctul unde
mouseul a patruns sau respectiv a parasit appletul :

public boolean mouseEnter(Event evt, int x, int y) {


...
}

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;

public class Linii extends java.applet.Applet {


final int MAXLINII=20;
Point inceput[]=new Point[MAXLINII];
Point finalul[]=new Point[MAXLINII];
Point pctInitial;
Point pctCurent;
int linieCrt=0;

public void init() {


setBackground(Color.white);
}
public boolean mouseDown(Event evt , int x , int y) {
if (linieCrt<MAXLINII) {
pctInitial=new Point(x,y);
return true;
}
else {
System.out.println("Prea multe linii.");
return false;
}
}

public boolean mouseUp (Event evt , int x , int y) {


if (linieCrt<MAXLINII) {
adaugareLinie(x,y);
return true;
}
else return false;
}

public boolean mouseDrag (Event evt , int x , int y) {


if (linieCrt<MAXLINII) {
pctCurent=new Point(x,y);
repaint();
return true;
}
else return false;
}

void adaugareLinie(int x,int y) {


inceput[linieCrt]=pctInitial;
finalul[linieCrt]=new Point(x,y);
linieCrt++;
pctCurent=null;
pctInitial=null;
repaint();
}

public void paint(Graphics g) {


g.setColor(Color.blue);
for (int i=0;i<linieCrt;i++) {
g.drawLine(inceput[i].x, inceput[i].y, finalul[i].x, finalul[i].y);
}
g.setColor(Color.red);
if (pctCurent!=null)
g.drawLine(pctInitial.x , pctInitial.y , pctCurent.x , pctCurent.y);
}
}
Pentru a ajuta la intelegerea programului vom schita pe scurt si un comentariu al
diferitelor elemente ce apar in cadrul sursei de mai sus .
Programul nostru memoreaz nu valori individuale ale coordonatelor ci obiecte Point .
Tabloul inceput memoreaza punctele care reprezinta punctele de inceput ale liniilor
deja desenate . Tabloul final memoreaza punctele de final ale liniilor deja desenate .
Variabila pctInitial memoreaza punctul de start al liniei pe care o desenam la
momentul curent iar pctCurent retine punctul final al liniei desenate curent . Variabila
linieCrt memoreaza numarul de linii desenate pentru a nu se depasi valoare
MAXLINII si pentru a se cunoaste linia din tablou care se va accesa in continuare .
Evenimentele tratate in applet sunt trei : mouseDown() pentru a stabili punctul de start
al liniei curente , mouseDrag() pentru a desena linia curenta pe masura ce este
desenata si mouseUp() pentru a se stabili punctul final al liniei desenate .
Pe masura ce mouseul este miscat pentru a trasa o noua linie appletul o deseneaza pe
aceasta astfel incat noua linie se va deplasa de la punctul de pornire si pana la punctul
mobil reprezentat de mouse ; evenimentul mouseDrag() memoreaza punctul curent ori
de cate ori mouseul se deplaseaza asa ca aceasta metoda poate fi folosita pentru a
reimprospata afisarea liniei curente dand astfel senzatia de animatie a acestei liniii .
Noua linie desenata se va adauga in tabloul de liniii doar dupa eliberarea mouseului -
la interventia metodei mouseUp() care apeleaza metoda adaugareLinie() .
Aceasta metoda adaugareLinie() actualizeaza tabloul de linii - de fapt tablourile de
puncte de inceput si de sfarsit ale liniilor dupa care appletul este redesenat pentru a
tine cont de aparitia ultimei linii desenate . Tot in cadrul acestei metode se seteaza
variabilele pctCurent si pctInitial la null deoarece linia desenata curent a fost
finalizata in momentul apelarii acestei metode . Prin setarea aceasta putem apoi testa
aceasta valoare null in metoda paint() pentru a vedea daca trebuie trasata o nou linie .
Desenarea appletului presupune desenarea tuturor liniilor stocate in tablourile
programului precum si desenarea liniei curente ale carei capete sunt in pozitiile
pctInitial si respectiv pctCurent .
Dupa cum am metionat putin mai sus in cadrul metodei paint() intai testam daca
valoarea lui pctCurent este null . Daca da , atunci appletul nu se afla in timpul
desenarii unei linii deci nu va avea nici un motiv sa traseze o linie care nu exista . Prin
testarea variabilei pctCurent - si prin posibilitatea setarii ei la null in metoda
adaugareLinie() - putem desena doar ceea ce este necesar .