Sunteți pe pagina 1din 49

3.

Tehnica programării în Java

3.1. Appleturi Java

Considerăm utilă vizualizarea appleturilor cu Netscape, deşi nu se recomandă utilizarea -o


(optimization) ca opţiune din javac, deoarece acesta face verificarea codul binar înaintea trecerii
spre interpreter. Netscape permite tratarea erorilor depistate înainte a pune appletul pe
server.Appletviewer nu realizează acest lucru nici măcar pentru appleturile încărcate local, dar
ocupă mai puţin spaţiu de memorie. Rulând cu flag -debug permite depanarea appletului dar nu
oferă posibilitatea vizualizării întregii pagini Web, doar a appleturilor, însă oferă posibilitatea
implementării relaxate şi sigure, în special la nivelul appleturilor încărcate pe sistemul local de
fişiere. Pentru a crea un applet se extinde clasa java.applet.Applet prin moştenire simplă. Această
clasă la rândul ei este descendent al altor clase moştenind un mare bagaj de funcţionalitate la orice
nivel.

3.1.1. Ciclul de viaţă al appletului

Spre deosebire de aplicaţiile monouser, unde programatorul scrie metoda principală care
direcţionează activitatea programului de la început la sfârşit, appleturile nu au în general o metodă
main() fiind manipulate de appletviewer sau Web browser care decide asupra iniţializării, rulării,
întreruperii şi distrugerii appletului.[Ramb_96]

start() stop()
Iniţializarea Execuţia Oprirea
appletului appletuluiu appletului

init() start()
destroy()

Distrugerea
appletului

Figura 3.1. Ciclul de viaţă al appletului

Conform figurii 3.1., programul principal aşteaptă ca appletul să fiec în măsură să execute metode
clare ca: init(), start(0, stop(), destroy() ce constituie ciclul de viaţă al unui applet şi sunt definite în
clasa java.applet.Applet. Deşi sunt metode cu corp void se aşteaptă ca programatorul să le
defineasă astfel încât ele să poată fi utilizate în scopul solicitat de appletul proiectat.
Metoda init() este apelată la prima încărcare a appletului, practic odată în tot ciclul de viaţă al
appletului şi se foloseşte pentru a iniţializa variabilele de instanţă, pentru setarea dimensiunii
appletului final, fundalul şi primplanul acestuia sau pentru stabilirea unor condiţii iniţiale de
execuţie propriu-zisă.
Metoda start() este similară cu main() method a appletului şi este apelată imediat după init()
declanşând execuţia appletului. Dacă appletul este oprit, metoda poate fi apelată din nou, pentru a

1
re-rula appletul, apărând ori de câte ori se doreşte instanţierea firelor sau pentru execuţia unui task
principal din applet.
Metoda stop() este apelată când appletul rulează şi utilizatorul minimizează fereastra browserului
sau reîncarcă pagina. Dacă se doreşte oprirea appletulului sau a firelor, metoda poate fi apelată şi
succedată de start() pentru a re-rula appletul..
Metoda destroy() este apelată când appletul poate fi eliminat din memorie (purge) deşi garbage
collector face acest lucru şi fără metoda în sine. In mod normal extinderea metodei se impune doar
în situaţii limită când appletul foloseşte resurse ale altor clase externe care trebuie gestionate de
către utilizator.
Exemplu:Structura generală a unui applet
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class StructuraApplet extends Applet {
public void init() {
}
public void start() {
}
public void stop() {
}
public void destroy() {
}

public void paint(Graphics g) {


}
}
In Windows 98 sau Windows NT minimizarea appletului nu invocă stop() şi de accea nu se va
invoca start la maximizarea ferestrei şi appletul se execută lăsând procesorului posibilitatea de a
rula alt fir în acest timp.
Legarea cu altă pagină ce nu conţine appleturi determină automat apelul lui stop() şi este
recomandată când se doreşte minimizarea ferestrei browserului.
Metodele anterior descrise nu trebuie explicitate decât dacă se doreşte executarea unor acţiuni
specifice.

3.1.2. Elemente esenţiale în dezvoltarea unui applet

Pentru a construi un applet este nevoie să creăm o clasă care este derivată din clasa de bază Applet
aflată în pachetul java.applet. Clasa Applet este clasa ce oferă cadrul absolut necesar comunicării
cu browserul WWW, practice o interfaţă de comunicare a unui program Java cu browserul. Orice
applet este implementat prin crearea unei subclase a clasei Applet. Ierarhia claselor din care deriva
Applet este prezentată în figura 3.2. Fiind derivata din clasa Container, clasa Applet descrie de fapt
suprafete de afisare, asemenea claselor Frame sau Panel.

2
Figura 3.2. Ierarhia de clasă a appletului

Tagul html de conexiune cu fişierul class este tagul APPLET şi are varianta minimală de forma:

<APPLET CODE=”numeApplet.class”
WIDTH=300
HEIGHT=200>
</APPLET>

Exemplu:
import java.applet.Applet;
import java.awt.*;
public class AppletExemplu extends Applet {
public void paint(Graphics g) {
g.setFont(new Font("Arial", Font.BOLD, 16));
g.drawString("Java", 0, 30);
}
}

Figura 3.3.Procesul dezvoltării şi execuţiei unui applet Java


Browser Web cu
fişier html (WebPage.html) suport Java
Editor text -conţine eticheta de legătură (appletviewer,
cu fişierul .class Netscape, etc.)
MyApplet.class

fişier executabil JVM execuţie program


Bytecodes Java în JVM
(MyApplet.class)

fişier sursă Java


(MyApplet.java) Compilator Java
(javac)
Clasa principala va fi salvata într-un fisier cu acelasi nume şi extensia .java. Spre exemplu:
fişierul AppletExemplu.java.
Compilarea se face la fel ca şi la aplicatiile independente, apelând compilatorul javac pentru clasa
principala a appletului (cea care extinde Applet).
javac AppletExemplu.java

3
In cazul în care compilarea a reusit va fi generat fisierul AppletExemplu.class.
Pentru a vizualiza un applet trebuie creat un document HTML (ex: exemplu.html), în care se
specifică cel putin următoarele informaţii:
 clasa ce contine codul appletului
 latimea si înaltimea suprafetei alocate pe pagina Web

<HTML>
<HEAD>
<TITLE> Exemplu de applet </TITLE>
</HEAD>
<APPLET CODE="AppletExemplu.class" WIDTH=100 HEIGHT=50></APPLET>
</HTML>

Vizualizarea acestui document se poate face cu orice browser (Internet Explorer, Netscape, etc),
sau cu utilitarul appletviewer ce vine în pachetul JDK.
appletviewer exemplu.html

3.1.3. Prelucrarea parametrilor din fişiere HTML


Sintaxa tagului applet
In fişierul HTML apar o serie de tag-uri utilizate la transferul parametrilor între appleturi şi aceste
fişiere.
Fără a insista prea mult asupra semnificaţiei tagului applet, amintim câteva aspecte referitoare la
tagurile de imagine şi sunet.[Rado-96],[Murh_98]
Tag-ul <APPLET>
[CODEBASE = directorApplet]
CODE = clasaApplet
[ALT = textAlternativ]
[NAME = numeInstantaApplet]
WIDTH = latimeInPixeli
HEIGHT = înaltimeInPixeli
[ALIGN = aliniere]
[VSPACE = spatiuVertical]
[HSPACE = spatiuOrizontal]
< APPLET
[< PARAM NAME = numeParametru1 VALUE = valoare1 >]
[< PARAM NAME = numeParametru2 VALUE = valoare2 >]
...
[text HTML alternativ]
</APPLET>
Atributele dintre paranteze patrate sunt optionale.
Semnificaţia parametrilor este:
 CODEBASE = directorApplet - Specifica URL-ul în care se gaseste clasa appletului;
uzual se exprima relativ la directorul documentului HTML iar în cazul în care lipseste, se
considera implicit URL-ul documentului.
 CODE = clasaApplet - este numele fisierului ce contine clasa principala a appletului.
Acesta va fi cautat în directorul specificat de CODEBASE şi nu poate fi absolut.

4
 ALT = textAlternativ specifică textul ce trebuie afisat daca browserul întelege tagul
APPLET dar nu poate rula appleturi Java.
 NAME = numeInstantaApplet oferă posibilitatea de a da un nume respectivei instanţe
a appletului, astfel încât mai multe appleturi aflate pe aceeasi pagina să comunice între ele
folosindu-se de numele lor.
 WIDTH = latimeInPixeli respective HEIGHT = înaltimeInPixeli - specifică laţimea şi
înalţimea suprafeţei în care va fi afişat appletul.
 ALIGN = aliniere - semnifică modalitatea de aliniere a appletului în pagina Web şi
poate primi una din urmatoarele valori: left, right, top, texttop, middle, absmiddle,
baseline, bottom, absbottom similare cu si la tagul IMG.
 VSPACE = spatiuVertical şi HSPACE = spatiuOrizontal - specifică numărul de
pixeli dintre applet şi marginile suprafeţei de afişare.
 < PARAM NAME = numeParametru1 VALUE = valoare1 >
Tag-urile <PARAM> sunt folosite pentru specificarea parametrilor unui applet.
text HTML alternativ - textul ce va fi afisat în cazul în care browserul nu poate interpreta tagul
APPLET iar browserele care înteleg Java vor ignora acest text.

Manipularea şi definirea parametrilor


Parametrii appleturilor sunt similari cu argumentele de la linia de comanda pentru aplicaţiile
independente şi permit utilizatorului personalizarea aspectul sau comportarea unui applet fără a-i
schimba codul şi a recompila clasele ce-l compun.
Definirea parametrilor se face în cadrul tagului APPLET din documentul HTML ce conţine
appletul şi sunt identificati prin atributul PARAM. Fiecare parametru are un nume, specificat prin
NAME şi o valoare, specificată prin VALUE, ca în exemplul de mai jos:
<APPLET CODE="AppletSimplu.class" WIDTH=100 HEIGHT=50
<PARAM NAME=textAfisat VALUE="Java">
<PARAM NAME=numeFont VALUE="Times New Roman">
<PARAM NAME=dimFont VALUE=20>
</APPLET>

Tipul parametrilor este şir de caractere, indiferent dacă valoarea este între ghilimele sau nu şi
fiecare applet are în plus un set de parametri prestabiliţi ale caror nume nu vor putea fi folosite
pentru definirea de noi parametri (folosind metoda de mai sus). Aceştia apar direct în corpul
tagului APPLET şi definesc informaţii generale despre applet (spre exemplu parametri CODE,
WIDTH sau HEIGHT). Folosirea parametrilor primiţi de către un applet se face prin intermediul
metodei getParameter() care primeşte ca argument numele unui parametru şi returnează valoarea
acestuia. In cazul în care nu exista nici un parametru cu numele specificat, metoda întoarce null,
caz în care programul trebuie să atribuie o valoare implicită variabilei associate respectivului
parametru.

Exemplu:rescrierea appletului considerat initial (AppletExemplu) astfel încât acesta sa afiseze


textul primit ca parametru, folosind un font cu numele si dimensiunea specificate de asemenea ca
parametri.

import java.applet.Applet;
import java.awt.*;

5
public class AppletExemplu extends Applet {
String text, numeFont;
int dimFont;
public void init() {
text = getParameter("textAfisat");
if (text==null)
text="Java"; // valoare implicita
numeFont = getParameter("numeFont");
if (numeFont==null)
numeFont="Arial";
try {
dimFont = Integer.parseInt(getParameter("dimFont"));
}
catch(NumberFormatException e) {
dimFont = 16;
}
}
public void paint(Graphics g) {
g.setFont(new Font(numeFont, Font.BOLD, dimFont));
g.drawString(text, 20, 20);
}
}
In general se evită definirea şi utilizarea unui număr mare de parametri în appleturi deoarece le
face practic neutilizabile, datorită dificultăţii de memorare a acestora. Soluţia recomandată este
utilizarea şi extinderea metodei getParameterInfo() definită în clasa java.applet.Applet pentru
appleturile proiectate, ceea ce oferă posibilitatea vizualizării tuturor parametrilor appletului
precum şi a altor informaţii ofetite de appletviwer.
Exemplu:
public String[ ][ ] getParrameterInfo() {
String [ ] [ ] Info={
{"MESSAGE", "String", "mesaj afisat"},
{"PAUSE", "int", "durata pauzei"},
{"STEPSIZE", "int", "dimensiunea pasului"},
{"FONTNAME", "String", "nume font"},
{"FONTSTYLE", "int", "stil font 0-PLAIN, 1-BOLD"+
"2-ITALIC"+"combinatii"},
{"FONTSIZE", "int", "dimensiunea fontului"},
{"MSG_COLOR", "int", "nume culoare"}
};
return Info;
}

In exemplul de mai sus, metoda întoarce un tablou de tablou de şiruri. Variabila locală Info se
iniţializează în timpul declaraţiei iar tabloul este iniţializat unidimensional, fiecare element fiind
la rândul lui un tablou. Dacă şirul este prea lung, pentu o linie, el se întrerupe cu " şi se continuă cu
operatorul de concatenare + deşi se poate folosi simplu return pentru continuarea textului pe o
nouă linie deoarece compilatorul recunoaşte faptul că nu s-a terminat şirul.

6
Observaţie: Java nu are operator de supraîncărcare (overloading) şi nu permite programatorilor
atribuirea unui alt inţeles operatorilor. Singura excepţie de la regulă este + (concatenarea şirurilor),
deşi operatorii aritmetici (+,-,*,/) care pot fi utilizaţi în int, flat, long, double sunt ei însuşi
supraîncărcaţi prin moştenirile acestora.

Clasa java.applet.Applet defineşte metoda getParameter(String Nume1) prin care întoarce valoarea
pereche a şirului Nume1 din interiorul fişierului HTML (tag-ul parameter). In caz contrar,
înroarce şirul null. Prin wrapper classes (clasele acoperitoare) se pot utiliza şi valori int, boolean,
float dacă sunt apelate metodele de conversie între şiruri şi tipurile primitive.
Orice applet poate pune la dispozitie o "documentatie" referitoare la parametrii pe care îi suporta,
pentru a veni în ajutorul utilizatorilor care doresc sa includa appletul într-o pagina Web. Aceasta se
realizeaza prin supradefinirea metodei getParameterInfo, care returneaza un vector format din
triplete de siruri. Fiecare element al vectorului este de fapt un vector cu trei elemente de tip
String, cele trei siruri reprezentând numele parametrului, tipul sau si o descriere a sa.

public String[][] getParameterInfo() {


String[][] info = {
//Nume Tip Descriere
{"textAfisat", "String", "Sirul ce va fi afisat"},
{"numeFont", "String", "Numele fontului"},
{"dimFont", "int", "Dimensiunea fontului"}
};
return info;
}

Informatiile furnizate de un applet pot fi citite din browserul folosit pentru vizualizare prin metode
specifice acestuia. De exemplu, în Netscape se foloseste optiunea Page info din meniul View.

Manipularea informaţiilor despre applet Similară cu metoda getParameterInfo există


metoda getAppletInfo ce permite specificarea unor informatii legate de applet cum ar fi
numele, autorul, versiunea, etc. Metoda returneaza un şir de caractere continând informatii
despre applet.

Exemplu:
public String getAppletInfo() {
return "Exemplu de applet, autor Delia Corches, ver 1.0";
}

3.1.4. Facilităţi de lucru cu imagini şi fişiere audio

Pentru un applet animat tagul este:


<APPLET CLASS="Animator"
IMAGESOURCE="unDirector"--directorul care are cadrele animate (o serie de desene în
format GIF, namite fisier1.gif, fisier2.gif, ...)
STARTUP="Fisier1" -- imagine ce se afişează la momentul încărcării
BACKGROUND="Fişier2"-- imagine ce se desenează pe fundalul cadrului

7
STARTIMAGE="Numar1" -- numărul cadrului de început (1..n)
ENDIMAGE="Numar2" -- numărul cadrului de sfârşit (1..n)
PAUSE="100" -- millisecunde de pauză între imagini, implicit poate fi suprascris prin
PAUSES)
PAUSES="300|200||400|200||100" -- millisecond întârziere pe cadru
Blank utilizează valoarea implicită a lui PAUSE
REPEAT="true" -- repetă secvenţa?
POSITIONS="100@200||200@100||200@200|100@100|105@105"
 posiţiia (X@Y) pentru fiecare cadru
 Blank - permite utilizarea poziţia cadrului anterior
IMAGES="3|3|2|1|2|3|17" -- ordine explicită de cadre
SOUNDSOURCE="Director2" -- directorul ce are fişiere audio
SOUNDTRACK="Fişier3" -- fişier audio ce este redat
SOUNDS="aFisier4.au|||||bFisier5.au" -- fişiere audio asociate cadrelor individuale

Parametri IMAGES, STARTIMAGE şi ENDIMAGE permit specificarea fie a unei liste de


imagini (IMAGES) sau interval de imagini (STARTIMAGE/ENDIMAGE) dar nu ambele
simultan. Lista din IMAGES este un şir de numere de cadre în ordinea în care se afişează,
separate prin bare verticale. STARTIMAGE and ENDIMAGE permit specificarea ordinii
imaginilor. Specificând ENDIMAGE număr mai mic decât STARTIMAGE, se afişează imaginile
în ordine inversă. Ambii parametrii au valoare implicită 1, aşa încât specificând numai
STARTIMAGE="12" înseamnă că se deseneză cadrele de la 12 la 1. Nu se pot specifica în acelaşi
timp STARTIMAGE şi ENDIMAGE.

Cum clasa Applet este o extensie a superclasei Container, înseamnă ca appleturile sunt,
înainte de toate, suprafeţe de afisare. Plasarea componentelor, gestionarea pozitionarii lor şi
tratarea evenimentelor generate se realizează la fel ca şi în cazul aplicaţiilor. Adăugarea
componentelor pe suprafata appletului şi stabilirea obiectelor responsabile cu tratarea
evenimentelor generate sunt operaţiuni ce vor fi realizate în metoda init. Gestionarul de
pozitionare implicit este FlowLayout, care poate fi schimbat prin metoda setLayout.
Exista o categorie întreagă de appleturi ce nu comunica cu utilizatorul prin intermediul
componentelor, ci executia lor se rezuma la diverse operatiuni de desenare executate în metoda
paint. Metoda paint permite definirea aspectului grafic al oricărei componente şi trebuie
supradefinită. In acest caz evenimentele tratate uzual vor fi cele generate de mouse sau tastatură.

Pentru manipularea imaginilor clasa Applet pune la dispoziţia programatorului două metode de
creare obiect de tip imagine:
 public Image getImage(URL url)- metodă care crează un obiect imagine (de tipul
Image) având ca şi parametru locaţia absolută WWW (URL-ul) unde se găseşte fişierul
imagine. Fişierul trebuie să fie unul din tipurile suportate de Java (gif, jpg).
 public Image getImage(URL url, String name)- returnează un obiect imagine. Are ca
parametrii locaţia relativă WWW şi numele fişierului imagine.
Afisarea imaginilor într-un applet se face fie prin intermediul unei componente ce permite acest
lucru - o suprafaţă de desenare de tip Canvas, fie direct în metoda paint a applet-ului, folosind
metoda drawImage a clasei Graphics. In ambele cazuri, încarcarea imaginii în memorie se va
face cu ajutorul metodei getImage din clasa Applet. Aceasta poate primi ca argument fie adresa
URL absoluta a fisierului ce contine imaginea, fie calea sa relativa la o anumita adresa URL, cum

8
ar fi cea a directorului în care se gaseste documentul HTML ce contine appletul
(getDocumentBase) sau a directorului în care se gaseste clasa appletului (getCodeBase).

Ex: import java.applet.Applet;


import java.awt.*;
public class AppletImagine extends Applet {
Image img = null;
public void init() {
img = getImage(getCodeBase(), "taz.gif");
}
public void paint(Graphics g) {
g.drawImage(img, 0, 0, this);
}
}

Pentru eliminarea problemelor de flashing se poate folosi tehnica double-buffering. Prin această
tehnică se desenează appletul într-o imagine ascunsă după care se afişează această imagine în zona
vizibilă.
Pentru a lucra cu fişiere audio, există în clasa Applet două metode care returnează un obiect Java
de tip AudioClip. Acest obiect poate fi folosit mai apoi pentru execuţia sunetului:

public AudioClip getAudioClip(URL url)


public AudioClip getAudioClip(URL url, String name).
Parametrii acestor metode sunt asemănători parametrilor de la metodele legate de imagine cu
deosebirea că fişierul care conţine sunetul trebuie să fie unul de tipul celor suportate de Java (au).

Folosirea firelor de executie în appleturi

Fiecare applet aflat pe o pagina Web se executa într-un fir de executie propriu. Acesta este creat de
catre browser si este responsabil cu desenarea appletului (apelul metodelor update si paint)
precum si cu transmiterea mesajelor generate de catre componentele appletului. In cazul în care
dorim sa realizam si alte operatiuni consumatoare de timp este recomandat sa le realizam într-un
alt fir de executie, pentru a nu bloca interactiunea utilizatorului cu appletul sau redesenarea
acestuia.

Structura unui applet care doreste sa lanseze un fir de executie poate avea doua forme. In prima
situatie appletul porneste un fir de executie la initialzarea sa, iar acesta va rula indiferent daca
appletul mai este sau nu vizibil, pâna la oprirea sa naturala (terminarea metodei run).

Ex: import java.applet.Applet;


class AppletThread1 extends Applet implements Runnable {
Thread appletThread = null;
public void init() {
if (appletThread == null) {
appletThread = new Thread(this);
appletThread.start();
}

9
}
public void run() {
//codul firului de executie
}
}

In cazul în care firul de executie pornit de applet efectueaza operatii ce au sens doar daca appletul
este vizibil, cum ar fi animatie, ar fi de dorit ca acesta sa se opreasca atunci când appletul nu mai
este vizibil (la apelul metodei stop) si sa reporneasca atunci când appletul redevine vizibil (la
apelul metodei start).
Ex: import java.applet.Applet;
public class StructuraApplet extends Applet implements Runnable {
Thread appletThread = null;
boolean running = false;
public void start() {
//reporneste firul de executie
if (appletThread == null) {
appletThread = new Thread(this);
running = true;
appletThread.start();
}
}
public void stop() {
//opreste firul de executie
running = false;
appletThread = null;
}
public void run() {
while (running) {
//codul firului de executie
}
}
}

Un applet este considerat activ imediat dupa apelul metodei start si devine inactiv la apelul
metodei stop. Pentru a afla daca un applet este activ se foloseste metoda isActive.

Comunicarea dintre browser şi applet


a. Transmiterea de parametrii prin pagina html
Parametrii unui applet sunt utili atunci când dorim să lăsăm la latitudinea utilizatorului appletului
(a celui care crează pagina html) setările unor valori de lucru.

Ex: applet care afişează un şir setat în pagina html


import java.applet.*;
import java.awt.*;
public class FirstApplet extends Applet {

10
public void paint(Graphics g) {
String sir=getParameter(“DISPLAYED_STRING”);
if(sir==null)sir=” Sirul afisat in interiorul appletului!”;
g.draw.String(sir,30,30);
}
}

Fişierul html corespunzător appletului dezvoltat conţine:

<APPLET CODE=”FirstApplet.class”
WIDTH=300
HEIGHT=200>
<PARAM NAME=”DISPLAYED_STRING”VALUE=”Bine ati venit pe site-ul meu”>
</APPLET>

Pentru a putea face cunoscută în exterior lista parametrilor, numele, tipul şi scopul acestora,
programatorul poate suprascrie metoda
public String[][] getParameterInfo()
În cazul exemplului de mai sus avem:

public String[][] getParameterInfo() {


String pinfo[][]=
{{“DISPLAYED_STRING”,”String”,”Sirul afisat in interiorul appletului”}}
return pinfo;
}

b.Obţinerea unor informaţii de la browser


Există o serie de metode care pot fi utilizate în interiorul appletului pentru a obţine anumite
informaţii de la browser, cu metodele:
public URL getDocumentBase()-returnează locaţia (adresa www) la care se găseşte pagina în care
se află appletul
public URL getCodeBase()-returnează locaţia la care se găseşte appletul.
Pentru a transmite anumite mesaje browserului din interiorul unui applet se pot folosi metodele
definite în interfaţa AppletContext. Un obiect de tipul AppletContext se poate obţine prin metoda
clasei Applet, getAppletContext(). Pentru comunicarea cu browserul avem următoarele metode
definite în interfaţa AppletContext:
public void showDocument(URL url)- cere browserului încărcărea unei noi pagini în fereastra de
afişaj curentă, pagină aflată la adresa specificată prin parametrul url.
public void showDocument(URL url, String target)-cere browserului încărcarea unei noi pagini
specificând în plus faţă de metoda anterioară cadrul în care se va afişa pagina. Un browser poate
avea mai multe cadre (frame) de afişaj în interiorul ferestrei sale, deschizând şi afişând astfel mai
multe pagini html în aceeaşi fereastră de browser. Parametrul target poate avea următoarele valori:
"_self" –pagina se afişează în cadrul curent
"_parent" –pagina se afişează în cadrul părinte
"_top" –pagina se afişează în cadrul superior al ferestrei browserului
"_blank" –pagina se afişează într-o nouă fereastră de browser fără nume

11
"name" –pagina se afişează într-o nouă fereastră de browser cu numele
name.
public void showStatus(String status)-prin această metodă appletul poate cere browserului afişarea
unui şir în interiroul “status window” a browserului. Acest “status window” reprezintă o
componentă grafică în care browserul afişează diferite informaţii legate de încărcarea paginilor, de
stabilirea conexiunii, etc. Această metodă este disponibilă şi în clasa Applet.
public Enumeration getApplets()-returnează toate appleturile disponibile în pagina în care se află
appletul curent (într-o pagină pot exista mai multe appleturi Java). Ca urmare, appletul curent
poate accesa diferite metode publice ale altor appleturi aflate în aceeaşi pagină html.
public Applet getApplet(String name)-prin această metodă appletul poate cere browserului
referinţa la appletul cu numele name.

c. Afisarea unor mesaje în bara de stare a browserului se realizeaza cu metoda showStatus


public void init() {
showStatus("Initializare applet...");
}

d. Afisarea unor documente în browser se face cu metoda showDocument ce primeste adresa


URL a fisierului ce contine documentul dorit (text, html, imagine, etc). Aceasta metoda se gaseste
în interfata AppletContext.
try {
URL doc = new URL("http://www.master.ro");
getAppletContext().showDocument(doc);
} catch(MalformedURLException e) {}

e. Comunicarea cu alte applet-uri aflate pe aceeaşi pagină implică de fapt identificarea unui
applet aflat pe aceeasi pagina si apelarea unei metode sau setare unei variabile publice a acestuia.
Identificarea se face prin intermediu numelui pe care orice instanta a unui applet îl poate specifica
prin atributul NAME. Obtinerea unei instante a unui applet al carui nume îl cunoastem sau
obtinerea unei enumerari a tuturor applet-urilor din pagina se fac cu metodele definite de interfata
AppletContext getApplet si getApplets.

f. Contextul de execuţie al unui applet se refera la pagina în care acesta rulează şi este descris de
interfata AppletContext. Crearea unui obiect ce implementează aceasta interfaţă se realizeaza de
catre browser, la apelul metodei getAppletContext a clasei Applet. Prin intermediul acestei
interfete un applet poate "vedea" în jurul sau, putând comunica cu alte applet-uri aflate pe aceeasi
pagina sau cere browser-ului sa deschida diverse documente.
AppletContext env = getAppletContext();

Probleme de securitate
Ferestrele folosite de un applet, altele decât cea a browserului, vor arata altfel decât într-o aplicatie
obişnuită. Sunt evidente o serie de probleme de securitate care se pun în cazul execuţiei
appleturilor în cadrul unui browser. Fiecare browser implementează o serie de politici de securitate
pentru a împiedica compromiterea sistemului. Aceste politici pot însă să difere de la un browser la
altul. În majoritatea cazurilor însă se impun unui applet următoarele restricţii:

12
• nu poate citi sau scrie fişiere de pe maşina pe care se execută
• nu poate şterge sau modifica fişiere de pe maşina pe care se execută
• nu poate citi anumite proprietăţi de sistem
• nu poate porni un program pe maşina pe care se execută
• nu poate deschide o conexiune de reţea decât cu maşina de pe care a fost adus
• nu poate încărca librării sau metode native.

Pentru a împiedica accesul unor appleturi maliţioase la resursele maşinii locale, browserul
implementează o serie de politici de securitate. Astfel unui applet îi sunt interzise o serie de
operaţii (unele descrise mai sus) care pot fi executate în cazul aplicaţiilor Java stand-alone. Politica
de securitate este implementată prin clasa SecurityManager.

Fiecare browser are un SecurityManager care implemntează politica de securitate. Când se


încearcă o violare a drepturilor acest SecurityManager aruncă o excepţie de tipul
SecurityException.
JDK oferă o soluţie prin care se pot acorda unor categorii speciale de appleturi anumite drepturi
de acces (altfel interzise) la resursele maşinii client. Pentru aceasta se foloseşte semnătura digitală
a appleturilor.

4.2. Documentarea parametrilor appleturilor


Spre exemplu, dacă utilizăm întârzierea ca parametru furnizat de fişierul HTML, vom avea:
Exemplu:
pause=100; care se va regăsi în codul Java:
String pause_str=getParameter("pause");
pause= Integer.parseInt (pause_str); //
//sau combinând cele 2 linii
pause=Integer.parseInt(getparameter("pause"));

In general se testează valabilitatea corespondenţei parametrilor în fişierele HTML astfel:


Exemplu:
String msg=getParameter("mesaj");
String pause_str=getParameter("pause");
if (msg = null){
msg="Paramatreu lipsa in fisier HTML";
}
if (pause_str != null){
pause Integer.parseInt(pause_str);
} else {
pause=200; //implicit
}

In fişierul HTML apare:

Observaţii:
 Toate numele parametrilor se trec între ghilimele şi sunt necesare când există
spaţii sau caracere de separaţie a căilor.

13
 Nu toate clasele acoperite construite furnizează convesrie facilă în clasa Integer,
când se solicită parametri numerici în appleturi. Astfel, pentru conversie float:
Exemplu:
float f;
String f_string=getParameter("f_par");
float f_acop=Float.valueOf(f_string);//conversie
f=f_acop.floatValue();
//valoarea conţinută

4.4. Animaţie în Java

Orice animaţie are ca obiective specifice în realizarea acestor "filme" sau secvenţe animate,
care pot constitui parametri utilizator în funcţie de care se realizează diferite variante de "film" 1.
Acestea presupun:[java_7]
• specificarea ordinii cadrelor în scopul reutilizării lor;
• specificarea punctului de unde se repetă animaţia;
• specificarea soundtrack-ului;
• specificarea sunetelor ce pot fi dispuse în cadre individuale;
• specificarea cuantei de timp pentru pauza dintre cadre (atât pentru întreaga animaţie cât şi
pentru cadrele individuale);
• specificarea unei imagini de început afişată la momentul încărcării;
• specificarea background-ului de imagine peste care se afişează animaţia propriu-zisă;
• specificarea poziţiei de la care se afişează fiecare cadru2.

Animaţia simplă presupune afişarea unei imagini statice (cadru) la un moment dat, într-o buclă
şi ideea centrală este de a afişa un cadru de secvenţe, făcând transfer de la cadru la cadru, atât de
repede încât percepţia naturală este realizată ca întreg, simulând o imagine în mişcare3
Respectând principiile de proiectare a directoarelor anterior expuse, cadrele se înmagazinează
într-un director de imagini iar appleturile şi fişierele HTMl au în general direcor comun sau două
subdirectoare de acelaşi nivel.

In documentaţia API, java.applet.Applet defineşte metoda paint() moştenită de la unul din


ascendenţi java.awt.Component. Moştenirea este cumulativă, clasa moştenind tot ce are superclasa
inclusiv moştenirile superclasei în sine. Browserul apelează paint() ori de câte ori este necesară
afişarea unei porţiuni de ecran ce conţine appletul propriu. In general gând se glisează o fereastră
peste appletul propriu (parţial sau integral) browserul redesenează porţiunea appletului ascunsă de
fereastră, apelând metoda paint(). [java_4]
Exemplu:
import java.awt.Graphics;
import java.awt.Color;
import java.applet.Applet;
public class Desen extends Applet {
1
Pentru detalii consultaţi site-ul java@java.sun.com
2
Conform Herb Jellinek | jellinek@eng.sun.com
3
durata cu care se schimbă cadrele este egală cu durata persistenţei imaginii pe retina ochiului

14
// coordonatele desenului
int x_coord[ ]={120,250,50,230,70,170};
int y_coord[ ]={20,250,150,130,170,20};
public void init(){
// definim metoda init
System.out.println ('initializarea appletului");
SetBackground(Color.blue);
SetForeground(Color.green);
resize(400,400);
}
public void start(){
// definim metoda start
System.out.println ('rularea appletului");
}

//desenul
public void paint(Graphics g){
System.out.println ('desenarea ");
g.drawPolygon(x_coord, y_coord,5);
}
public void stop(){
// definim metoda stop
System.out.println ('oprirea appletului");
}
public void destroy(){
// definim metoda destroy
System.out.println ('distrugerea appletului");
}

}
Codul fişierului HTML conţine:
<applet code=Desen.class width=450, height=450>
</applet>

Observaţie: Dacă se rulează cu Netscape, se setează Show Java Console care permite afişarea
mesajelor.

Rularea appletului:
Este deja cunoscut faptul că utilizarea opţiunii Reload din Netscape reîncarcă pagina ce conţine
appletul, dar browserul nu încarcă appletul în sine. Dacă se doreşte cel mai recent vizitat applet, cu
comportamentele noi ale acestuia, se selectează Network Preferences din meniul Options ştergând
disk cache astfel încât sistemul utilizează memoria cache. Când appletul se încarcă se va afişa cea
mai recentă versiune a lui.
Pentru a exemplifica acţiunile specifice ciclului de viaţă se recomandă următoarele experimente:
 Se lasă pagina şi apoi se reîntoarce la ea;
 Se încearcă minimizarea ferestrei browser;
 Se readuce fereastra la dimensiune normală;

15
 Se mută fereastra consolei in faţa appletului pentru a-l umbri;
 Se readuce fereastra appletului în primplan şi se defilează prin applet.
Cele trei instrucţiuni importă clasele Graphics, Color şi Applet care nu devin parte integrată a
codului appletului şi nu afectează dimensiunea programului.După import ele se referă conform
convenţiei sintactice:
public class Desen extends Applet {
Fiecare applet este o nouă clasă ce extinde clasa Applet şi moşteneşte variabilele şi metodele din
java.applet.Applet. Desen este clasă declarată public pentru că se utilizează de o aplicaţie din
exterior iar în caz contrar browserul nu poate avea acces la Desen şi nu il poate rula.
Cele două declaraţii de tablou:
int x_coord[ ]={120,250,50,230,70,170};
int y_coord[ ]={20,250,150,130,170,20};
permit alocarea spaţiului automat.
In momentul apelului Desen.init() se afişează un mesaj şi apoi se apelează cele două metode
moştenite din java.awt.Component (Color.blue şi Color.green) care sunt variabile statice.In final
redimensionează appletul la (400,400). La Netscape se remarcă un scurt flash de la dimensiunea
din HTML (450,450) la cea a appletului. Toate metodele sunt publice pentru a avea acelaşi tip de
acces cu clasa din care fac parte. Dacă se doreşte în jurul appletului se poate completa cu text.

Spre deosebire de appletviewer, în Netscape pagina rămâne statică iar resize() nu are efect. La
apelul resize() (redesenare) se specifică aria pe care appletul o recunoaşte ca proprie iar la
redesenare se actualizează doar aria respectivă. Acest lucru este des utilizat în animaţie pentru a
optimiza zona efectiv actualizată.[java_5]
Browserul trece metoda paint() unui obiect din clasa Graphics. Obiectul însuşi este referit în
context grafic, creat, menţinut şi posedat de sistem. După ce anunţă consola că paint() este apelat,
metoda trimite mesaj către obiectul Graphics, cerându-I să execute drawPolygon(), metodă din
java.awt.Graphics care ia 3 parametri: (x,y) din zonă şi numărul de laturi-n. Poligonul poate fi
închis (când n=numărul de laturi, sau deschis n> numărul de laturi). In Java, originea sistemului de
coordonate este stânga-sus şi coordonatele cresc în jos pe ecran (figura 3.2.).

(0,0) y

x (120,150)

Figura 3.2. Coordonatele grafice în Java

Metodele stop() şi destroy() au rolul de a demonstra ciclul de viaţă al appletului.

16
Folosirea appleturilor Java în paginile web
Când NU trebuie folosite Applet-urile Java:
pentru simple animaţii, acestea pot fi făcute cu gif-uri animate care se încarcă mai repede şi sunt
compatibile cu mult mai multe browsere;
pentru butoane: nu toata lumea are browsere care rulează Applet-uri sau în unele cazuri această
opţiune poate fi dezactivată. Dacă totuşi un programator foloseşte Applet-uri pentru butoane,
trebuie să fie sigur că aceasta este numai o alternativă şi că aduce ceva în plus faţă de un link
obişnuit ;
nu se umple pagina web cu multe applet-uri, aceasta va face ca pagina să se încarce foarte greu;
în general nu trebuie lăsat numai pe seama Applet-urilor Java lucrurile esentiale din pagina web!
(pe site-urile marilor companii, applet-urile Java sunt aproape inexistente).
Când trebuie folosite Applet-urile Java:
Când pagina web trebuie să prezinte lucruri care nu sunt posibil de realizat numai cu HTML (ex:
mici programe interactive, jocuri, animaţii cu sunet etc )
Când se doreşte ca pagina să ofere un înalt grad de interactivitate.
Java este sinonim cu Internetul. Applet-urile Java nu sunt indispensabile pentru Web. Ele sunt ca
sarea si piperul unei pagini web si nu trebuie abuzat de ele.

3.3. Realizarea animaţiei

Prezentăm un exemplu imperfect dat de o buclă infinită ce redă controlul CPU. Appletul are rolul
de a demonstra ce se întâmplă când un applet animat nu-şi crează un fir propriu independent
pentru a rula animaţia. Executat pe sistem multitasking la sfârşit se poate forţa terminarea
appletului.[java_6]
Exemplu:
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.applet.Applet;

public class BandaDefilanta extends Applet {


String msg; // mesaj defilant
int x, y // coordonatele desenului
int orizPas;//dimensiune pas în pixeli
int pause;// numar de iteratii in bucla pauza
int msgWidth; dimesiunea mesajului în font curent

public void init(){


msg="Monopolizarea CPU";
pause=100000;
orizPas=2;
FontMetrics fm=get FontMetrics(get Font());
MsgWidth=fm.stringWidth(msg);
// incepe x din dreapta
x=size().width;
// incepe y mai sus de capăt
y=size().height-(int)(fm.getHeight()/3);
}

17
public void paint(Graphics g) {
while (true) {
//redesenarea appletului in fundal
g.setColor(getBackground());
g.fillRect(0,0,size().width, size().height);
//desenarea mesajului în poziţia curentă
g.setColor(getForeground());
g.drawString (msg,x,y);
//avans stânga
if(x>0-msgWidth){
x=x-orizPas;
}else{
//incepe din dreapta
x=size().width;
}
pauza(pause)
}
}
void pauza(int contor){
// definim metoda de pierdere de timp
for(int i=0,i<contor,i++) {
}
}
Codul fişierului HTML conţine:
<applet code=BandaDefinlanta.class width=250, height=150>
</applet>

Rularea appletului
Metoda g.setColor() trimite un mesaj către obiectul grafic g, contextul grafic îl trece ca parametru
lui paint(), comunicând şi setul de culori al "peniţei" pentru a umple sau desena figuri geometrice
sau şiruri. Prin apelul lui g.setColor(getBackground()) se ia fundalul curent. Dacă se utilizează un
dreptunghi pentru fundal, acesta umple zona appletului, ştregând aria pe ecran. Se setează culoarea
de primplan a appletului pentru a putea desena mesajul pe ecran. Metoda size() moştenită din
java.awt.Components dă înălţimea şi lăţimea appletului şi întoarce un obiect de tip
java.awt.Dimension (clasă care conţie 2 variabile width şi height). Aceşti 2 membri ai obiectului
pot fi accesaţi direct, fără a declara un obiect din clasa Dimension. Dacă se intenţionează
utilizarea succesivă a variabilelor width şi height, este de preferat memorarea lor într-un obiect,
pentru a nu permite apelurile redundante ale lui size(). Datorită faptului că dimensiunea appletului
se schimbă, cel mai simplu mod de a garanta valoarea recentă este de a apela size() direct. In
exemplu se foloseşte o metodă atipică de a plasa bucla de animaţie loop în interiorul metodei
paint(). In plus, fundalul se redesenează de fiecare dată când se redesenează şirul dar utilizând
update() se poate desena numai fundalul. Obiectul FontMetrics este util pentru a calcula lingimea
şirului din mesaj, dat fiind faptul că multe fonturi sunt proporţionale, înafară de monospaţii şi este
de dorit ca fonturile să fie cât mai aspectuase deşi sunt dependente de sistemele pe care se rulează
appletul.[java_7]

18
3.4.Firele

3.4.1. Interfeţe şi fire de execuţie

Apelăm la clasicul exemplu din literatura de specialitate - modul în care Java implementează
erorile şi firele (threads). Frecvent un applet rulează cu un fir în timp ce alte fire sunt abilitate să se
execute simultan, utilizând sistemul eficient.

Dacă appletul extinde java.applet.Applet, nu poate extinde java.lang.Thread pentru că violează


restricţiile moştenirilor multiple. Soluţia o oferă java.lang.Runnable, caz în care appletul propriu
implementează metoda run() plasată în corpul principal al appletului. Apoi se construieşte un fir
thread() în interiorul appletului, transmiţând this ca parametru al constructorului Thread (). Acest
constructor poate lua ca parametru orice obiect ce implementează o interfaţă Runnable astfel:
public Thread(Runnable tinta);

Metoda constructorului lansează un fir a căriu corp, când este rulat ia metoda run() furnizată de
propriul applet- cheia înţelegerii interfeţelor. Dacă appletul este declarat Runnable, appletul este
tratat ca obiect Runnable şi orice metodă ( ca şi constructorul anterior) care ia Runnable ca
parametru, poate accepta appletul. Când se apelează metodele ce fac parte din interfaţa Runnable -
în cazul de faţă run()- appletul propriu a furnizat metoda consistentă cu cererea, ceea ce este ca şi
cum ar fi clasă obişnuită numită Runnalbe şi appletul propriu este derivat din clasă. Interfaţa
Runnable este cel mai intuitiv exemplu care ilustrează în acelaşi timp un important concept de
proiectare: keep it simple.

Există doar o metodă implementată în interfaţa Runnalbe şi de aceea este foarte uşor de
implementat în orice clasă proiectată. Dacă se definesc n metode, este greu de imaginat că cineva
consideră convenabilă implementarea tuturor acestor interfeţe iar dacă aceste metode sunt
disparate în câteva interfeţe este facilă implementarea acelor interfeţe care asigură funcţionalitate
absolut necesară.[Ramb_96]. Modificatorii de interfaţă sunt public şi abstract iar în lipsa lor
interfaţa este accesibilă doar în interiorul pachetului. O interfaţă spre deosebire de clasă, poate
extinde mai multe interfeţe.

2.4.3. Modul de utilizare a interfeţelor

Apelăm la clasicul exemplu din literatura de specialitate - modul în care Java implementează
erorile şi firele (threads). Frecvent un applet rulează cu un fir în timp ce alte fire sunt abilitate să se
execute simultan, utilizând sistemul eficient.
Dacă appletul extinde java.applet.Applet, nu poate extinde java.lang.Thread pentru că violează
restricţiile moştenirilor multiple.Soluţia o oferă java.lang.Runnable, caz în care appletul propriu
implementează metoda run() plasată în corpul principal al appletului. Apoi se construieşte un fir
thread() în interiorul appletului, transmiţând this ca parametru al constructorului Thread (). Acest
constructor poate lua ca parametru orice obiect ce implementează o interfaţă Runnable astfel:
public Thread(Runnable tinta);

Metoda constructorului lansează un fir a căriu corp, când este rulat ia metoda run() furnizată de
propriul applet- cheia înţelegerii interfeţelor. Dacă appletul este declarat Runnable, appletul este

19
tratat ca obiect Runnable şi orice metodă ( ca şi constructorul anterior) care ia Runnable ca
parametru, poate accepta appletul. Când se apelează metodele ce fac parte din interfaţa Runnable -
în cazul de faţă run()- appletul propriu a furnizat metoda consistentă cu cererea, ceea ce este ca şi
cum ar fi clasă obişnuită numită Runnalbe şi appletul propriu este derivat din clasă. Interfaţa
Runnable este cel mai intuitiv exemplu care ilustrează în acelaşi timp un important concept de
proiectare: keep it simple.

Există doar o metodă implementată în interfaţa Runnalbe şi de aceea este foarte uşor de
implementat în orice clasă proiectată. Dacă se definesc n metode, este greu de imaginat că cineva
consideră convenabilă implementarea tuturor acestor interfeţe iar dacă aceste metode sunt
disparate în câteva interfeţe este facilă implementarea acelor interfeţe care asigură funcţionalitate
absolut necesară.[Ramb_96]. Modificatorii de interfaţă sunt public şi abstract iar în lipsa lor
interfaţa este accesibilă doar în interiorul pachetului. O interfaţă spre deosebire de clasă, poate
extinde mai multe interfeţe.

In problema anterioară este necesară existenţa unui applet care execută animaţia în fir separat şi un
altul ce rulează concurent, evitând monopolizarea CPU. Problema centrală este de a crea un fir
responsabil d emanipularea evenimentelor, scopul fiind de a rula animaţia, în timp ce redă
controlul CPU.
Faţă de conceptul tradiţional în are programul execută o serie de instrucţiuni în ordine, firele sunt
în fapt o localizare independentă a controlului unui program. Manipulând mai multe fire de
execuţie, se poate executa o parte a instrucţiunilor din lista unui fir, după care să se execute o altă
succesiune de instrucţiuni din alt fir, dar la momentul revenirii la firul anterior, să se localizeze
exact porţiunea de instrucţiuni din listă (locus of control - localizarea controlului). Programele
multithread au simultan mai multe loc of control deşi unele sisteme utilizează un singur procesor,
simulând în fapt execuţia paralelă sau multifir, în realitate oferind o cuantă de timp în care
utilizează microprocesporul (de ordinul câtorva microsecunde), algoritmii de planificare, ajungând
la un sistem dependent.[Zaha_00]
Implementarea interfeţei Runnable este un mod convenabil de creare a appletului multithread.Cum
java.lang.Thread este subclasă a lui java.lang.Applet, creând un applet ca subclasă a
java.lang.Thread, contrazicem principiul moştenirii simple. De aceea la implementarea interfeţei
Runnable se cer implementate toate metodele acesteia - adică run() - metoda definită de Runnable
astfel încât appletul presupune:
 Includerea clauzei implements Runnable în declaraţia de clasă a appletului;
 Estinderea metodei run() a interfeţei Runnable, cu codul principal în appletul propriu;
 Metoda start() a appletului propriu crează un fir trecând appletul ca parametru al
constructorului, prin cuvântul cheie this
 Metoda stop() a appletului propriu, cu codul acestuia, opreşte execuţia firului.
Exemplu:
public Class Simple implements Runnable{
protected String message;
protected TextArea text;
//constructorul clasei
public Simple(String m, TextArea t)
message m;
text=t;
}

20
public void run(){
text.appendText(message);
}
}
Clasa Simple implementeazã o interfaţã de tinp Runnable, care are doar o metodã run()
public interface Runnable{
public void run();
}

Clasele care implementeazã o interfaţã de tin Runnable nu au nimic în comun decât metoda run().
public Class Sapplet extends Applet{
protected TextArea text;
protected Simple hello;
protected Simple bye;
public Sapplet(){
text= new TextArea(4,20);
hello= new Simple hello;
bye= new Simple bye;
}

public void init(){


add(text);
}
public void start(){
hello.run();
bye.run();
}
Dupã invocarea metodei start() se continuã cu primul obect hello() iar dupã ce revine din execuţie
cu return din metoda run() ruleazã bye. Nu este multithreading ci doar Runnable, obiectele fiind
secvenţiale.
Versiunea multithread:
public Class Tapplet extends Applet {
protected TextArea text;
protected Simple hello;
protected Simple bye;
public Tapplet(){
text= new TextArea(4,20);
hello= new Simple (“hello\n”, text);
bye= new Simple (“bye\n”,text);
}

public void init(){


add(text);
}
public void start(){
new Thread(hello).start();
new Thread (bye).start();

21
}
}
3.4.1. Firele şi prioritatea lor

Priorităţile firelor sunt valori întregi (1-10) utilizate la schimbarea (switch) a firului executat.CPU
execută un singur fir la un moment dat deşi un fir poate renunţa voluntar la control prin
determinări explicite, dormind sau blocând prin agăţare I/O sau poate fi pre-empted. In primul caz
sunt examinate firele în funcţie de priorităţi şi cel cu prioritate maximă şi care este gata de rulare
are controlul CPU. In al doilea caz, cumun fir renunţă voluntar, firul cu prioritate maximă care
vrea să ruleze o va face dar situaţia limită apare când 2 fire cu aceeaşi prioritate cer control CPU.
C.A.R.Hoare defineşte conceptul de monitorizare. De vreme ce firele introduc comportament
asincron al programului, trebuie să existe o metodă de a forţa sincronizarea necesară. Monitoarele
sunt prescrise pentru a proteja resursele partajabile sa în vederea manipulării acestora de mai multe
ori la un moment dat. In Java monitorul este dat de metoda syncronized. Mesajele schimbate între
2 fire sunt focalizate cu metodele wait şi notify. Un fir poate introduce metoda syncronized pe un
obiect şi să aştepte până când un alt fir notifică explicit ieşirea. Analog, mai multe fire pot
introduce metoda syncronized pe un obiect şi să aştepte până când apare aceeaşi notificare. Firul
curent ce se execută poate fi terminat cu Thread.currentThread.[java_4]

3.4.2. Utilizarea firelor în programare

Metodele clasei sunt statice, apelate din clasa Thread direct:


 currentThread - indică firul curent;
 yield - determină execuţia în contextul switch de la firul curent către alt fir runnable
disponibil.
 sleep(int n) - sleep n milisecunde.

Metodele de instanţă sunt:


start(), run(), stop() - cu semnificaţii binecunoscute;
suspend() - diferit de stop cauzează oprirea fără distrugerea stării şi se poate relua prin
resume();
resume() - reia execuţia firului, făcându-l disponibil.
set priority(int p) - setarea priorităţii firelor. Majoritatea folosesc NORM_PRIORITY -1 iar
taskurile background operaţii I/O sau retipărire) au MIN_PRIORITY
MIN_PRIORITY=1, NORM_PRIORITY=5, MAX_PRIORITY=10
GetPriority() - întoarce prioritatea;
SetName( String nume) dă numele firului;
GetName() întoarce valoarea precizată de setName.

In continuare vom exemplifica utilizarea acestor metode.


Exemplu:
class FirCurentEx {
public static void main(String args[]){
Thread t=Thread.currentThread();
t.setName=("firul meu");
System.out.println ("firul curent"+t);
try {

22
for (int n=5; n>0; n_-){
System.out.println (" "+n);
}
catch(InterruptedException e){
System.out.println ("intrerupt");
}
}
}
Rezultatul execuţiei:
Firul curent Thread[firul meu,5,main]
5
4
3
2
1
unde main este numele unui grup de fire cu care se leagă.
Runnable este în fapt o simplă interfaţă ce abstractizează noţiunea de aştepare înaintea execuţiei
asincrone, cum putem observa în exemplul următor.
Exemplu:
class FirCurent implements Runnable {
Thread ct=Thread.currentThread();
System.out.println ("firul curent"+ct);
Thread t=new Thread (this, "Noul Thread");
System.out.println ("firul nou"+t);
t.start();
try {
Thread.sleep();
}catch(InterruptedException e){
System.out.println ("intrerupt");
}
System.out.println ("Iesire din firul principal");
}
}
public void run(){
try{
for (int n=5; n>0; n_-){
System.out.println (" "+n);
Thread.sleep(1000};
} catch(InterruptedException e){
System.out.println ("Fir intrerupt");
}
System.out.println ("Iesire din firul fiu");
}
public static void main(String args[]){
new FirCurent();
}
}

23
Rezultatul execuţiei:
Firul curent Thread[main,5,main]
Firul nou Thread[Noul Thread,5,main]
5
4
3
Iesire din firul principal
2
1
Iesire din firul fiu
Setarea priorităţii de realizaeză cu metoda setPriority cu 2 nivele faţă de cea normală
reprezentată de Thread.NORM_PRIORITY(HIGH,LOW)
Exemplu:
class ClasaFir implements Runnable {
int click=0;
private Thread t;
private boolean ruleaza=true;
public ClasaFir (int p) {
t= new Thread(this);
t.setPriority(p);
}
public void run(){
while(ruleaza) {
click++;
}
}
public void stop(){
ruleaza=false;
}

public void start(){


t.start();
}
}
class MaMicPri {
public static void main (String args[]){
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
ClasaFir mare=new ClasaFir(Thread,NORM_PRIORITY+2);
ClasaFir mic=new ClasaFir(Thread,NORM_PRIORITY-2);
mare.start();
mic.start();
try Thread.sleep(1000); catch(InterruptedException e);
mare.stop();
mic.stop();
System.out.println (mic.click+"comparat cu firul "+mare.click);}
}

24
}

3.4.3. Sincronizarea firelor

Alte sisteme multifir expun conceptul de monitor. Un monitor este obiectul ce foloseşte blocajul
mutual exclusiv 4 şi numai un fir poate deţine monitorul la un moment dat. Când un fir solicită
blocarea se spune că a intrat în monitor. Toate celelate fire care încearcă să intre şi să blocheze
monitorul sunt suspendate până când este eliberat, deşi un fir ce deţine monitor poate reintra la
acelaşi monitor dacă doreşte.Monitorizarea este soluţionată prin metoda syncronized.[Naugh_96]

Exemplu:
Clasa apel are o singură metodă - apel, cu parametru msg şi încearcă tipărirea mesajului după care
cheamă Thread.sleep. Constructorul clasei Apelant ia o referinţă către o instanţă a clasei Apel şi un
şir memorat în tinta şi mesajur respectiv msg. Constructorul crează un fir Thread care va apela
metoda run() a acestui obiect. Firul începe imediat şi metoda run a lui Apelant este simplă, apelând
doar instanţa tinta a lui Apel, trecând mesajul. In final, clasa Sync ia lucrurile, pornind de la
crearea unei instanţe Apel şi trei instanţe Apelant, fiecare cu mesajul său. Aceeaşi instanţă este
trimisă la fiecare Apelant.
Codul sursă:
class Apel {
void apel(String msg){
System.out.println ("["+msg);
try Thread.sleep(1000); catch(InterruptedException e);
System.out.println ("]");
}
}
class Apelant implements Runnable {
String msg;
Apel tinta;
public apelant (Apel t, String s){
tinta=t;
msg=s;
new Thread(this).start();
}
public void run(){
tinta.apel(msg);
}
}
class Sync {
public static void main(string args[]);
Apel tinta= new Apel();
new Apelant (tinta, "Bine");
new Apelant (tinta, "sincronizate");
new Apelant (tinta, "firele");
}
4
Mutual exclusive lock - mutex

25
}
Rezultat:
[Bine[sincronizate][firele]

inlocuind cu
syncronized void Apel(String msg){
apare ieşirea metodei sincronizate astfel:
[Bine]
[sincronizate]
[firele]

3.4.4. Comnunicarea între fire

Java include un mecanism de cumunicare inter-proces, prin wait, notify şi notifyAll implementate
ca metode finale în Object şi toate clasele acestuia. Cele trei metode pot fi apelate numai din
interiorul unei metode syncronized şi au rolul:
 wait- spune firului să lase monitorul şi apoi sa "doarmă" (sleep) până când alt fir intră
în acelaşi monitor şi apelează notify.
 notify - trezeşte primul fir ce a chemat wait pe acelaşi obiect.
 notifyAll - trezeşte toate firele ce au chemat wait pe acelaşi obiect şi firul cu prioritatea
cea mai mare este rulat primul.
Exemplu:
Construim 4 clase:Q care încearcă sincronizarea accesului, PC care crează simplu
următoarele clase, respectiv Producator- care produce intrări în coadă, Consumator şi obiectul
Threaded care consumă intrările din coadă

class Q{
int n;
syncronized int iau(){
System.out.println ("iau:"+n);
return n;
}
syncronized void pun (int n){
this.n=n;
System.out.println ("pun"+n);
}
}
class Producator implements Runnable {
Q q;
Producator( Q q) {
this.q=q;
new Thread(this, "producator").start();
}
public void run() {
int i=0;
while(true) {
q.pun(i++);

26
}
}
}

class Consumator implements Runnable {


Q q;
Consumator ( Q q) {
this.q=q;
new Thread(this, "Consumator").start();
}
public void run() {
int i=0;
while(true) {
q.iau(i++);
}
}
}

class PC {
public static void main(String args[]){
Q q=new Q();
new producator(q);
new Consumator(q);
}
}
Chiar dacă metodele pun şi iau sunt sincronizate, nu opreşte nimic pe Producător să ruleze
peste Consumator şi nici Consumatorul să consume o valoare d e2 ori astfel:
Rezultat:
Pun 1
Iau 1
Iau 1
Iau 1
Pun 2
Pun 3
Pun 4
Pun 5
Pun 6
Iau 6
Modalitatea polling fixează ceea ce se primeşte setând o variabilă booleană, trecând apoi într-un
loop de evaluare şi aşteptând valoare avariabilei consumate astfel:
class Q{
int n;
boolean valset=false;
int iau(){
while ( !valset){
System.out.println ("iau:"+n);
valset=false;

27
return n;
}
void pun (int n){
while ( !valset){
this.n=n;
valset=true;
System.out.println ("pun"+n);
}
}
Varianta anterioară consumă enorme resurse CPU şi practic nu face nimic. O altă soluţie
este:
class Q{
int n;
boolean valset=false;
sycronized int iau(){
if ( !valset){
try wait();
catch(Interrupted Exception e);
System.out.println ("iau:"+n);
valset=false;
notify();
return n;
}
syncronized void pun (int n){
if (valset){
try wait();
catch(Interrupted Exception e);
this.n=n;
valset=true;
System.out.println ("pun"+n);
notify();
}
}
Rezultat:
Pun 1
Iau 1
Pun 2
Iau 2
Pun 3
Iau 3

Pun 7
Iau 7

3.4.5. Blocajul

28
Practic blocajul5 este foarte greu sau nu poate fi depanat deloc când este condiţionat de 2 fire ce au
dependenţă circulară de o pereche de obiecte sincronizate. [An-96],[java_5] Spre exemplu, un fir
intră pe monitor pe obiectul X şi apoi încearcă să apeleze o metodă sincronizată pe y. Dacă y
încearcă să apeleze orice metodă sincronizată cu y aşteaptă întotdeauna până este deblocat de x
pentru că nu se poate elibera de propriul blocaj.
Exemplu:
class A {
syncronized void prima (B b){
String nume=Thread.current.Thread().getName();
System.out.println (nume+"introdus de metoda A.prima);
try Thread sleep(1000); catch (Exception e );
System.out.println (nume+"ce incearca apel B.last"+B.last);
b.last();
}
syncronized void last(){
System.out.println (" interior A.last");
}
}
class B{
syncronized void bar (A a){
String nume=Thread.current.Thread().getName();
System.out.println (nume+"introdus de metoda B.bar);
try Thread sleep(1000); catch (Exception e );
System.out.println (nume+"ce incearca apel A.last"+A.last);
a.last();
}
syncronized void last(){
System.out.println (" interior A.last");
}
}

class Deadlock implements Runnable{


A a = new A();
B b = new b();
Thread.currentThread().setName("firul primar"};
new Thread(this).start();
a.prima(b); // ia lock on in firul lui
System.out.println ("Inapoi la fir principal");
}
public void run(){
Thread.currentThread().setName("firul al doilea "};
b.last(a);
System.out.println ("Inapoi la ALT fir");
}
public static void main (String args[]){
new Deadlock();
5
deadlock

29
}
}

3.5. Aspecte particulare ale manipulării excepţiilor

Excepţia este o condiţie excepţională, deosebită ce apare în timpul execuţiei unui program.
Excepţională este condiţia a cărei cunoaştere este posibilă dar se aşteaptă să apară rar sau deloc.
Limbajul Java defineşte clasa java.lang.Throwable pentru încapsularea noţiunii de excepţie, prin
cele două clase ale sale: java.lang.Exception şi java.lang.Error. Excepţia poate fi prinsă (caucht)
şi anulată într-o manieră oarecare, chiar permiţând un impact negativ asupra execuţiei unui
program. Eroarea nu poate fi prinsă de utilizator şi în general obligă la terminarea programului 6.
Când apare o excepţie, metoda ce o generează proiecteaza excepţia şi în general se termină
execuţia metodei, trimiţând un mesaj apelantului în forma unui obiect excepţie din clasa
java.lang.Throwable. Când o metodă cauzează excepţie, aceasta poate fi prinsă (catch) prin
plasarea apelului "periculos" intr-o buclă try/catch sau poate fi ignorată (netratată). Dacă excepţia
care apare nu este controlată se spune că nu este proiectată (trown) sau dacă este tratată (catch)
poate genera la manipulare alte erori sau chiar o nouă excepţie.

Clasa Object

Throwable

Error Exception

Runtime Exception alte excepţii

Figura 2.1. Excepţiile în Java

Manipularea erorilor se realizează prin blocul try/catch cu sau fără finally cu sintaxa:
try {
//codul ce generează excepţia

} catch (ClasădeExcepţii nume) {
// codul ce le manipulează orice subclasă din ClasădeExcepţii
} catch (AltaClasădeExcepţii nume) {
// codul ce le manipulează orice subclasă din AltaClasădeExcepţii
}finally {
// cod ce preia execuţia
}
6
De obicei de foloseşte termenul de excepţie la ambii descendenţi (Exception şi Error)

30
Blocul try este utilizat pentru excepţii de orice tip şi ieşiri anormale (break, return, continue). La
apariţia unei excepţii, interpreterul analizează primul bloc try/catch întâlnit, în care caută clauza ce
marchează o clasă de excepţii. Din acest motiv se specifică întâi excepţiile frecvente şi apoi în
mod gradula cele generale.In blocul finally se preia execuţia dacă blocul try este completat normal
(fără excepţii), dacă unul din blocurile catch manipulează excepţii respectiv dacă in blocurile catch
nu este tratată excepţia respectivă. Acestea sunt aşa numitele excepţii trigger, caz în care fiecare
catch va avea asociat un bloc finally. Pentru a defini comportamentul în toate cazurile, indiferent
dacă excepţia apare sau nu, se specifică bloul finally, executat ori de câte ori se termină un bloc try
(normal sau nu) şi după execuţia unui bloc catch.

Excepţiile nemanipulate (unhandled exceptions) apar când blocul try/catch este inexistent sau nu
are clauză pentru excepţia apărută, caz în care interpreterul caută în cel mai apropiat bloc închis.
Dacă nici o metodă nu tratează excepţia, ea se propagă înapoi în metoda main() şi interpreterul va
ieşi, tipărind eroarea, un mesaj şi stack trace (urma stivei).[Chan_95] Dacă se decide ignorarea
unei excepţii, metoda trebuie să aibă precizată în declaraţie faptul că proiectează o clasă
particulară de excepţii, cu menţiunea că o metodă poate proiecta oricâte clase de excepţii, separate
prin virgulă în declaraţie. Metodele extinse nu pot proiecta excepţii.
Spre deosebire de excepţiile normale, apar excepţiile Runtime (anormale) subclasate în
java.lang.RuntimeException, care pot fi generate de o serie de acţiuni în timpul execuţiei (acces
nepermis la tablouri, operaţii aritmetice, etc.). Dacă metodele nu includ catch pentru aceste
excepţii nu este necesară includerea clauzei throws în declaraţia metodei. Spre exemplu, se omite
throws la apariţia ArrayIndexOutOfBounds xceptions sau ArithmeticExceptions.

Pentru exemplificare vom modifica exemplul anterior astfel încât să nu monopilizăm CPU.
Exemplu:
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.applet.Applet;

public class BandaDefilanta extends Applet {


String msg; // mesaj defilant
int x, y // coordonatele desenului
int orizPas;//dimensiune pas în pixeli
int pause;// numar de iteratii in bucla pauza
int msgWidth; dimesiunea mesajului în font curent
Thread proFir; // firul manipulează desenarea şi defilarea textului

public void init(){


msg="Applet Multithread fără monopolizarea CPU";
pause=100;
orizPas=2;
FontMetrics fm=get FontMetrics(get Font());
msgWidth=fm.stringWidth(msg);
// incepe x din dreapta

31
x=size().width;
// incepe y mai sus de capăt
y=size().height-(int)(fm.getHeight()/3);
}

public void start(){


proFir = new Thread(this);
//apel run() si intoarcere imediată
proFir.start();
}

public void run(){


// defilarea pana cand firul este oprit
while (proFir !=null){
repaint (); // apel update() si paint()
}

proFir = new Thread(this);


//apel run() si intoarcere imediată
proFir.start();
//avans stânga
if(x>0-msgWidth){
x=x-orizPas;
}else{
//incepe din dreapta
x=size().width;
}
try {
// pauza de milisecunde pentru a redesena CPU liber
proFir.sleep(pause);
}catch (InterruptedException e){
e.printStackTrace();// eroare de tiparire
}
}
}
public void paint(Graphics g){
// desenarea mesajului
g.drawString(msg,x,y);
}

public void stop(){


// definim fir candidat la garbage collector
proir=null;
}
}
Codul fişierului HTML conţine:
<applet code=BandaDefinlanta.class width=250, height=150>

32
</applet>

Rularea appletului
BandaDefinlanta are superclasa imediata Applet şi totuşi moşteneşte metoda abstractă run() din
interfaţa Runnable, care trebuie extinsă pentru instanţierea appletului propriu.După aceasta,
metoda poate fi trecută ca parametru în orice metodă care poate primi un obiect Runnable, de fapt
în metoda start().
Se instanţiază un obiect din java.lang.Thread (cum java.lang.* este importat automat) iar
constructorul Thread() utilizat ia obiectul Runnable ca parametru şi setează metoda run() a lui
Thread pentru a apela metoda run() transmisă în obiect.
Cu proFir instanţiat apelul proFir.start() este motivat deja, iar acesta apelează la rândul lui
proFir.run() şi apoi întoarce asincronismul.Se justifică de ce nu trebuie aşteptat ca proFir.run() să
se execute complet, în modul sincron, în care s-ar executa normal o metodă. Aceasta înseamnă că
se dă controlul lui BandaDerulanta.start() în firul principal, în timp ce metoda run() se execută în
firul paralel, ca fir separat (proFir). Acum BandaDerulanta.start() completează, returnând controlul
asupra sistemului astfel încât se pot asimila ca evenimente manipulate, poate chiar apelate de
propria metodă stop() a appletului.[java_5], [java_6]
Un aspect neobişnuit este faptul că BandaDerulanta şi proFir împart acceaşi metodă run() în timp
ce metodele proprii start() nu sunt echivalente. In fapt metodele run() au doar similitudini de apel,
funcţionalitatea lor fiind distinctă.Realitatea este că BandaDerulanta şi proFir nu împart acceaşi
metodă run() ci Thread este instanţiat într-un asemenea mod încât apelează metoda run() a
appletului.
După instanţierea firului şi apelul lui proFir.run() appletul are 2 fire de execuţie: cel principal, care
manipulează evenimentele şi apelează metodele din ciclul de viaţă al appletului şi al doilea care
produce execuţia animaţiei.Animaţia este de fapt o buclă întreruptă când firul este oprit (while
proFir !=null;). Deoarece se utilizează o variabilă locală pentru reprezentarea firului în metoda
run(), când metoda run() se termină firul îşi atinge scopul şi valoarea devine null (sinonim cu
terminarea firului).
Metoda repaint() a appeltului este moştenită din java.awt.Component şi apelează metoda
update() implicită, care redesenează fundalul şi apoi paint().

Pauza a fost implementată printr-o buclă iterativă, care de fapt consumă timpul procesorului fără a
face nimic (buzy-waiting). Apelând proFir.sleep() cu parametru întreg, se indică timpul după care
se eliberează CPU. In interiorul blocului try şi catch se apelează proFir.sleep() şi de fapt nu se
execută efectiv manipularea excepţiilor ci se indică ceea ce clasa nu poate proiecta ca excepţii
manipulate. In mod normal InterruptedException are un simplu return prin care metoda run() se
termină. Metoda stop() se apelează când utilizatorul comută diferite pagini sau monimizează
browserul, caz în care CPU este eliberat, proFir=null şi devine candidat la gerbage collector.
"Omorârea" (kill) nu presupune distrugerea lui (destroy), rămânând starea memorată în varibilele
de instanţă.La apelul lui start() se crează un nou fir, continuând proFir de unde a fost lăsat.[java_7]

4. Grafică şi animaţie în Java folosind pachetul java.awt

33
4.1. Utilizarea fonturilor şi culorilor în appleturi

Este deja cunoscut un principiu de bază în programerea OO şi anume reutilizarea codului, motiv
pentru care la extinderea unui applet care foloseşte clase din pachetul java.awt. se au în vedere
metodele proprii apletului şi cele extinse ale claselor java.awt.Color, java.awt.Font,
java.awt.Component, etc. Clasa java.awt.Color foloseşte culori încapsulate, declarând 13 culori
constante care pot fi nuanţate, specificând valori numerice din gama RGB (red,green,blue).
Appletul îşi poate seta fundalul şi primplanul prin setForeground() şi setBackground(), la fel
cum poate utiliza getForeground() şi getBackground() pentru a regăsi culorile de primplan şi
fundal. Cele 4 metode sunt moştenite din java.awt.Component. Clasa java.awt.Font foloseşte la
rândul ei fonturi încapsulate, declarând 3 constante pentru reprezentarea stilului de font
Font.PLAIN, Font.BOLD şi Font.ITALIC, care pot fi folosite în combinaţie, iar appletul îşi poate
seta fontull prin setFont() şi poate declara fontul dorit prin getFont() [java_4], [Lema_96]
Exemplu:
import java.awt.Toolkit;
public class TipFont extends java.applet.Applet {
String fontLista[ ];
public void init() {
fontLista=getToolkit.getFontList();
}

public void paint (java.awt.Graphics g){


int y=10;
for (int i=0; i<fontList.length(); i++){
g.drawString(fontLista[i],10,y+15);
}
}
}
Directorul
principal

Pachet 1 Pachet 2 .classes .java .html

Alte
clase

Baza.class Baza.java

Figura 4.1. Structura directoarelor pentru o aplicaţie Java

34
Deoarece s-au definit în paragrafele anterioare variante de înglobare a fişierelor grafice, imagini,
executabile din alte medii, este necesară structurarea lor în pachete şi clase pentru a asigura
accesul şi modificarea facilă, paralel cu reutilizarea codului pentru unele clase şi metode definite.
Recomandăm astfel ca appletul să aibă acces direct la directorul principal, creând astfel o structură
arborescentă, prezentată schematic în figura 4.1.:
Rădăcina structurii se denumeşte director principal (main) în care se plasează de obicei fişierele
HTML (opţional într-un subdirector al lui main şi un director numit classes (care poate fi opţional
o legătură simbolică cu directorul claselor centrale, oriunde în altă parte pe server).Toate
fişierele .class sunt memorate în acest director, sau în subdirectoare ale acestora, pentru a facilita
utilizarea pachetelor şi claselor în proiectele viitoare, referându-se şi extinzându-se ori de câte ori
este necesar.
In fişierele .HTML este necesară prezenţa atributului CODEBASE="classes" sau alte convenţii
corespunzătoare structurii de de directoare ( spre exemplu: CODEBASE="../classes"), calea
completă fiind specificată în CLASSPATH.Imaginile şi fişierele audio sunt memorate în
subdirectoare distincte (figura 7)corespunzător directorului main şi pot avea legături opţionale.
Structura prezentată are avantajele organizării serverului, mentenabilităţii facile şi posibilităţii
reutilizării codului. In plus, dezvoltarea ulterioară a appletului pe o altă maşină sau un alt server,
nu implică reîncărcarea appleturilor completate şi a paginilor Web spre directoare potrivite
serverului deoarece toate legăturile funcţionează şi oferă portabilitate maximă de la o maşină la
alta. Pentru o aplicaţie complexă se recomandă crearea unui pachet propriu. Proiectarea acestui
pachet este realizată astfel încât să fie memorat în locul unde poate fi accesat pentru necesităţile de
utilizare. Unele pachete sunt create cu uz local, iar altele necesate pentru paginile Web, sunt create
în directoare de unde clientul le poate încărca.
La momentul la care sistemul java trebuie să încarce o clasă, caută pentru fiecare locaţie
specificată în CLASSPATH directorul în care numele este identic cu numele pachetului clasei.
Găsindu-l, utilizează numele pachetului pentru a reconstitui calea potrivită pentru fişierul .class, în
caz contrar, caută în locaţia specificată în CODEBASE, în care se află fişierele .class ale
appletului.Cea mai simplă cale de a face pachetul disponibil clienţilor pentru execuţia appletului
este de a asigura acelaşi director pachetului şi appletului din care face parte.
Exemplu:
public class BandaSimplaextends toolBox ParamP implements Runnable{
int width;
int heigh;

4.4.1. Aspecte de alocare dinamică a cadrelor animate

Este deja cunoscut faptul că, la alocare dinamică a unui tablou Java, el nu are valoare. Dacă tabloul
este de tip obiect (opus tipurilor primitive) la instanţierea tabloului nu are loc şi alocarea memoriei
pentru obiectele comprimate în tablou. In fapt, instanţierea tabloului este realizată ca o colecţie de
manipulatori null.
Exemplu:
Se declară tabloul de imagini din clasa jaa.awt.Image:
Image cadruAnim[ ];

35
Apare manipulatorul null denumit cadruAnim care nu are valoare şi nici dimensiune

cadruAnim
= null

Figura 4.2. Tabloul de imagini

Când are loc instanţierea tabloului:


CadruAnim = new Image[nume_ cadru];
tabloul are deja manipulatori obiecte Image (figura 4.3.).
cadruAnim
0 1 2 3 4 5 6

= = = null
Figura 4.3. Tabloul de imagini instanţiat

Când se instanţiază elementele individuale de tablou, memoria este alocată individual şi


dinamic pentru fiecare grup de obiecte, aşezate unul în altul, în garbage-collector. In realitate
ele pot sau nu pot fi contigue în memorie, dar după bucla iterativă de instanţiere ele arată
conform figurii 4.4..

cadruAnim
0 1 2 3 4 5 6

= = = null

Figura 4.4. Schema de alocare dinamică a cadrelor în tablouri

Java utilizează schema de alocare dinamică pentru toate obiectele care sunt alocate static, nu şi
pentru tipuri primitive (int, float, long, char). Pentru manipularea tablourilor de cadrelor în
animaţie se utilizează clasa abstract java.awt.Image folosind:import java.awt.Image. Cum nu
se poate instanţia direct un obiect din clasa abstractă, se subclasează şi apoi se instanţiază:
Image cadruAnim[ ] ;
Când se instanţiază un tablou de manipulatori ai clasei Image nu se vor instanţia niciodată
elementele individuale ale tabloului ci se apelează Applet.getImage() care construieşte un
obiect independent de platformă, subclasă a lui java.awt.Image şi întoarce manipulator al
acestui obiect. Deoarece obiectul este subclasă a lui java.awt.Image, este compatibil cu aceasta
şi poate fi astfel atribuit unui element de tablou.

36
Metoda java.applet.Applet.getImage() returnează asincronism deoarece produce un fir către
metoda care încarcă imaginea şi nu aşteaptă completarea firului ci returnează un manipulator
către obiectul Image. Dar firul care încarcă imaginea este în plin proces de încărcare când are
loc getImage() şi return(). Chiar dacă se iniţiază incărcarea tururor imaginilor în timpul
metodei init(), are loc mai mult o încărcare paralel cu debutul buclei de afişare a imaginii pe
ecran. Astfel încât privind un applet care realizează animaţie cu tablouri de cadre afişate
succesiv, are loc o iniţializare a background-ului şi apoi o succesiune de imagini total sau
parţial încărcate, până în final când se încarcă integral tabloul şi are loc animaţia. In realitate
începe desenarea pe ecran inainte e a fi integral încărcate (datorită asincronismului care
permite execuţia simultană a mai multor fire).

Metoda java.applet.Applet.getDocumentBase() întoarce URL-ul directorului ce conţine


fişierul HTML referit de applet. Combinată cu calea relativă a fiecărui fişier imagine, se obţine
calea completă a URL-ului pentru fiecare imagine încărcată. Există o metodă similară
java.applet.Applet.getCode Base() care întoarce URL-ul directorului ce conţine fişierul .class
referit de applet deoarece nu este o regulă ca fişirul HTMl şi appletul să fie în acelaşi director
(nici măcar pe acelaşi server).
Metoda java.awt.Graphics.drawImage() a ca parametru Image şi (x,y) coordonatele ce indică
poziţia relativă faţă de colţul stânga-sus al appletului şi manipulează un obiect din clasa
java.awt.Image.ImageObserver. In realitate acesta nu est un obiect ci o interfaţă care permite
obiectelor din diferite ierarhii de clase să s eprezinte ca şi cum ar aparţine aceluiaşi nivel, unei
aceleiaşi clase, simulând astfel moştenirea multiplă. Deoarece java.applet.Applet
implementează ImageObserver practic se trece appletul către orice metodă dorită de acesta.
ImageObserver moşteneşte metodele din java.awt.Component deci nu putem vorbi de o
implementare directă ci mai degrabă de o extensie orin moştenire.
Dând this în ImageObserver se poate construi imaginea deoarece metoda paint() este apelată
odată, la fel ca şi drawImage() sau drawString(). Menţionăm că în metoda paint() a appletului s
epoat apela oricâte metode grafice care permit desenarea unei imagini, a unui şir la începutul
ei, urmată de altă imagine, poligo, etc. Nivelul de prioritate superior dă mai mult timp CPU,
motiv pentru care se execută mai repede acel fir care are prioritate mai mare. Nivelul de
prioritate poate fi modificat şi din fişierul HTML. In plus, depinzând de sistemul propriu, firele
cu prioritate mare pot ţine pe loc pe cele cu prioritate mai mică, făcându-le să aştepte până
când cele cu prioritate mai mare termină de exectat taskul lor.

4.4.2. Efectele speciale

Pîlpîirea sau vibraţia (flinker) este o metodă des utilizată în animaţie. La apelul metodei
repaint() sistemul invocă metoda update() a appletului, care este moştenită din clasa
java.awt.Component iar codul sursă al versiunii implicite este:
Exemplu:
public void update(Graphics g){
g.setColor(getBackground());
g.fillRect(0,0,width,height);
g.setColor(getForeground());
paint (g);
}

37
Metoda şterge porţiunea appletului pe ecran şi apoi apelează metoda paint(). Din acest
motiv, când se desenează o imagine, apare fundalul blank un timp scurt înainte ca imaginea să
fie desenată şi este parţial responsabil pentru vibraţiile (flinker) din animaţie.
Când se redesenează imaginea peste ea însuşi nu este nesară redesenarea fundalului de
fiecare dată, motiv pentru care se extinde metoda update care reduce pîlpîirea:
Exemplu:
public void update(Graphics g) {
paint (g);
}

Acest "truc" nu se aplică la desenarea textului în mişcare pentu că ştergerea fundalului este
necesară de această dată, permitând o afişare inteligibilă a informaţiei din text.
Whiteboard (hârtia albă) este reprezentarea analogică a contextului grafic, structura de
date pe care le utilizează sistemul şi interfeţele acestuia pentru a desena pe ecran. Utilizând
tehnica "double-buffering" se ţine invizibil contextul grafic din jur şi se desenează textul in
acest context. După finalizarea metodei paint() se face vizibil contextul grafic, ceea ce ai mai
puţin timp faţă de operaţiile actuale de desenare care au loc în spatele ecranului.

4.5. Ierarhia componentelor GUI

In GUI la nivelul cel mai înalt apar două tipuri de componente: componente de bază:
Canavas,Scroolbar, Button,Checkbox,etc şi conteinere sau componente ce conţin alte componente
ca şi Window şi subclasele Frame, Panel (cel mai familiară subclasă Applet) (figura 4.6.).
Containerele sunt subclasate în java.awt.Component (figura 4.5.).
Este util de precizat că ierahia componentelor este diferită de ierarhia de clasă. Structura
ierarhiilor (figura 4.6.) nu are legătură cu moştenirea, de accea componentele ce aparţin
conteinerelor sunt cele cu săgeată ar cele reprezentate cu linie simplă sunt clauze extends.
Clasa java.awt.Conteiner (figura 4.5.) include metoda add() ce adaugă componente în
conteiner, utilizată la secţiunea Panel prin:
TipPanel.add(CheckboxPanel);

java.awt.Object
4.6. Interfaţa LayoutManager

Pentru aşezarea pe ecran, AWT utilizează un obiect ce implementează interfaţa


LayoutManager, care controlează regulile prin care un Conteiner dat îşi va aşeza propriile
java.awt.Component java.awt.ImageObserver
componente constituente. Se instanţiază un obiect din LayoutManager pentru fiecare Conteiner
creat, utilizând metoda conteinerului getLayout() pentru a specifica ceea ce utilizează
LayoutManager.[java_7]
java.awt.Container

java.awt.Panel

java.applet.Applet

38
java.applet.AppletContext java.applet.AppletStub java.applet.AudioClip
Java.Applet
Figura 4.5. Gruparea componentelor Java
Exemplu:
middlePanel.setLayout(new BorderLayout());

Applet

Panel Panel Panel

Button

Checkbox Panel Label Chioce

Checkbox Checkbox

RectCanvas Scrollbar Scrollbar

Figura 4.6. Ierarhia componentelor GUI

Pachetul java.awt defineşte căteva LayoutManager standard, incluzând:FlowLayout,


BorderLayout, CardLauout, GridLayout, GridBayLayout,etc.

39
FlowLayout
Cel mai simplu LayoutManager este FlowLayout care aranjează componentele în Conteiner de la
stânga la dreapta. Când se umple un rând, FlowLayout crează un nou rând, punând componentele
în aceeaşi ordine. Dacă nu se specifică LayoutManager pentru Panel sau Applet, este folosit
implicit.

BorderLayout
BorderLayout divide în 5 regiuni spaţiul alocat, aranjând componentele în Conteiner în regiunile
specificate (figura 4.7.).

North

East Center Vest

South

Figura 4.7. Regiunile FlowLayout

CardLayout
Intr-un conteiner setat CardLayout, numai un component constituent este vizibil la un moment dat.
CardLayout furnizează metode first(), last(), next(), previous() şi show() pentru a selecta
componenta vizibilă. Tipic fiecare component adăugat în CardLayout va fi un Conteiner, ce
conţine alte componente. Acest mod este util pentru proiectarea ecranelor tabbed (tabulate) unde
fiecar ecran prezintă un set de controale legate în relaţie şi utilizatorul poate traversa ecranele în
ordine prin click pe un anume tip de control, de obicei simulând index tab la începutul
directoarelor de fişier.

GridLayout
Acest standard subdivide componentele într-un număr de linii şi coloane (specificate de
constructor). Componentele sunt plasate în celule divizate în ordinea adăugării lor.în Conteiner.
Celulele se extind sau se contractă cât este necesar pentru a se potrivi cu dimensiunea preferată de
componente.

GridBagLayout
Cea ma mare flexibilitate şi control al programatorului îl oferă "regina" LayoutManager-
GridBagLayout, deşi este cel mai complex de utilizat. La fel ca şi GridLayout se subdivide în
celule. Fiecare Component manipulat poate lua una sau mai multe celule, paote fi alungit pentru a
ocupa spaţiu mai mare relativ la alte componente şi poate dispune de o arie de aşezare ce permite
spaţiu liber între el şi alte componente. Pentru fiecare Component, GridBagLayout menţine o
instanţă a lui GridbagConstraints, care conţine constrângeri specifice, informaţii despre modul în
care va fi aşezat acest Component particular. Setarea acestor informaţii se face prin construcţia

40
unui obiect din clasa GridbagConstraints, setând câmpurile apropiate şi apoi trecând în metoda
setConstraints, pentu a referi componenta ce utilizează constrângerile setate.
Exemplu:
Gb= new GridBagLayout();
//referinta la gb apoi apelam metoda lui
c= new GridBagConstraints();
myConteiner.setLayout(gb);
c.wheightx=20;
//lugime orizontala relativa 2
gb.setConstraints(my Component, c);
myConteriner.add(myComponent);

la apelul gb.setConstraints(my Component, c); gb crează o copie a obiectului


GridBagConstraints şi o utilizează pentru manipularea lui myComponent. GridBagLayout nu
utilizează obiectul original ci o instanţă a lui GridBagConstraints. Este uşor de craet o singură
instanţă a lui GridBagConstraints, setarea câmpurilor după dorinţă şi apoi utilizarea lui pentru
adăugarea componentelor multiple ce se aşează cu aceleaşi caracteristici7.

4.7.Construcţia GUI cu pachetul java.awt

GUIExample.java este un program simplu de desenare, ce permite desenarea unui obiect de tip
Rectangle umplut sau nu cu o culoare. Prin acest exemplu se ilustrează diferenţa între desenarea
bitmap şi cea OOP8 . Fiecare dreptunghi este vizibil utilizatorului ca un obiect, modelat ca atare şi
tratat ca o colecţie de biţi, fără a face distincţie între obiectele individuale ce compun imaginea.
Extinzând moştenirea, se poate desena orice obiect.[Ramb_96]
Exemplu:
import java.applet.Applet;
import java.awt.*;
import java.util.vector;
// clasa ce extinde Rectangle
class DrawableRect extends Rectangle{
Color color=Color.black;
Boolean filled=false;
//construcţia dreptunghiului
DrawableRect (int x, int y, int width, int heigh, Color, color, boolean filled) {
Super(x,y,width, heigh);
this.color=Color;
this.filled=filled;
}

//desenare in contur offset specificat


void drawn (Graphics g, int offset_x, int offset_y) {
Color.temp=g.getColor();
g.getColor(color);
if (filled) {
7
Detalii se află în API Documentation
8
Painting program = program de desenare orientat obiect (OOP)

41
g.fill (x-offset_x, y- offset_y, width, heigh);
}else{
g.drawRect (x-offset_x, y- offset_y, width, heigh);
}
g.getColor(temp);
}
}
class CheckBoxPanel extends Panel {
// grup de CheckBox mutual exclusive
CheckBox Group myGroup;
//2 CheckBox in grup
CheckBox filledBox;
CheckBoxnotfilledBox;
CheckBoxPanel(){
//alt java.awt.Panel
super();
setLauout(new BorderLayout());
filledBox=new CheckBox("Filled",myGroup, false);
notfilledBox=new CheckBox("Not Filled",myGroup, true);
myGroup.setCurrent(notFilledBox);
add("North", filledBox);
add("South", notFilledBox);
}
// intoarce starea grupului CheckBox
boolean isFilled(){
return myGroup.getCurrent==filledBox);
}
}

Class RectCanavas extends Canavas {


//mouse punctul de jos
int orig_x;
int orig_y;
// cand se face scroll
public int offset_x=0;
public int offset_y=0;
// setare curenta pentru un nou dreptunghi
boolean filled=alse;
Color rectColor=Color.black;

//colectia d edreptunghiuri
int numRects=0;
Vector rects= new Vector(100,10);
//numai pentru convenienta
DrawableRect currentRect;
// crează un dreptunghi desenabil si il adauga in lista
DrawableRect addRect ( int x,int y ; int width, int height){

42
DrawableRect r = new DrawableRect (x,y,width;height, rectColor, filled);
rects.addElement ( r );
NumRects++;
return r;
}

//dispune toate dreptunghiurile si incepe o noua lista


void clearRects() {
numRects=0;
rects= new Vector(100,10);
repaint();
}

//seteaza culaorea pt. Adaugarea unui nou dreptunghi


void setRectColor(Color c) {
rectColor =c;
}

//seteaza atributele de umplere pt. Adaugarea unui nou dreptunghi


void setFilled(boolean b) {
filled =b;
}

//raspuns la eveniment mouseDrawn


//apelat de handleEvent mostenit
public boolean mouseDown (Event evt, int x, int y) {
//seteaza punct mouse down
orig_x=x;
orig_y=y;
//incepe un nou dreptunghi
current Rect=addRect(orig_x+offset_x,orig_y+offset_y,0,0);
return true;
}

//raspuns la eveniment mouseDrag


//apelat de handleEvent mostenit
public boolean mouseDrag (Event evt, int x, int y) {
//cat se trage punctul
int x_diff=x-orig_x;
int y_diff=y-orig_y;

//dreptunghiul nu are dimensiuni negatige


//cautam coltul stanga=sus
int x_val=(x_diff>0) ? orig_x+offset_x : x+offset_x;
int y_val=(y_diff>0) ? orig_y+offset_y : y+offset_y;

43
// inaltime si latime determinate prin lungime drag
int width_val=Math.abs(x_diff);
int height_val=Math.abs(y_diff);

//redesenare interactiva a dreptunghiului


current Rect=reshape(x_val, y_val,width_val, height_val);

//arata rezultat cand utilizatorul retrage


repaint();
return true;
}

//Deseneaza toate dreptunghiurile pe Canavas


public void paint(Graphics g){
DrawableRect r;

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


r=(DrawableRect).rects.elementAt(i);
//deseneaza fiecare dreptunghi offset fata de dimensiunea scroll
r.draw(g,offest_x,offset_y);
}
}
}
public GUIExample extends Applet {
//varful paletei si sub-itemii ei

panel topPanel = new Panel();


CheckboxPanel chechboxPanel= new CheckboxPanel();
Label colorLabel= new Label("color:");
Choice colorChoice= new Choice();

//mijlocul paletei si sub-itemii ei

panel middlePanel = new Panel();


RectCanavas rCanavas= new RectCanavas();
Scroll_bar x_scroll= new ScrollBar(Scrollbar.HORIZONTAL);
Scroll_bar y_scroll= new ScrollBar(Scrollbar.VERTICAL);

//sfarsitul paletei si sub-itemii ei

panel bottomPanel = new Panel();


Button clearButton=new Button("clear");
}
public void init() {
// crearea unui manager implicit si setarea appletului pt. Utilizare

44
this.setLayout (new BorderLayout());

//selectia culorilor
color.Choice.addItem("Black");
color.Choice.addItem("Blue");
color.Choice.addItem("Red");
color.Choice.addItem("Green");
color.Choice.addItem("Yelow");
color.Choice.addItem("Cyan");

color.Choice.selectItem("Black");

// adaugarea tuturot itemilor la inceputul paletei


topPanel.add(checkboxPanel);
topPanel.add(colorLabel);
topPanel.add(colorChoice);

//adaugarea inceputului paletei la applet


this.add("North",topPanel);

// mijlocul Panel
middlePanel.setLayout(new BorderLayout ( r )) ;

//setarea la mijlocul paletei a RectCanavas


rCanavas.setFilled(checkboxanel.isFilled());
rCanavas.setRectColor(getSelectedColor());
rCanavas.setBackground(Color.white);
//adaugarea tuturor itemilor la mijlocul paletei
middlePanel.add("South", x_scroll);
middlePanel.add("Est", y_scroll);
middlePanel.add("Center", rCanavas);

//sfarsitul paletei
bottomPanel.add(clearButton);

//adaugarea paletei la applet


this.add("South",bottomPanel);
resize(350,350);
}

public void paint (Graphics g){


rCanavas.repaint();
}

//se citeste culoarea selectata


Color getSelected.Color() {
if(colorChoice.getSelectedItem().eguals("Black")){

45
return Color.black;
}else { if(colorChoice.getSelectedItem().eguals("Blue")) {
} else {

}
}

//suprascrie java.awt.Component.handleEvent()
public boolean handleEvent(Event evt){
if (evt.target==colorChoice){
sCanavas.setRectColor(getSelectedColor());
}else { if (evt.target instance of Checkbox){
rCanavas.setFilled(checkboxPanel.isFilled());

}else if {evt.target== x_scroll){


switch (evt_id) {
case Event.SCROLL_LINE_UP:
case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_PAGE_UP:
case Event.SCROLL_PAGE_DOWN:
case Event.SCROLL_ABSOLUTE:

//evt.arg tin valorile cu care bara este deplasata


rCanavas.offset_x=((Integer)evt.arg).intValue();
break;
}
else if (evt.target==y_scroll){
switch (evt_id) {
case Event.SCROLL_LINE_UP:
case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_PAGE_UP:
case Event.SCROLL_PAGE_DOWN:
case Event.SCROLL_ABSOLUTE:

//evt.arg tine valoare cu care se deplaseaza bara


rCanavas.offset_y=((Integer)evt.arg).intValue();
break;
}
}
//canavas a fost deplasat
rCanavas.repaint();
// ne asiguram ca alte evenimente nu sunt manipulate
return super.handleEvent(evt));
}
//raspuns la actiunea evenimentelor
public boolean action(Event evt, Object what) {

46
if (evt.target.eqals(clearButton){
rCanavas.clearRects();
}
}
//numai cand parintele are nevoie de eveniment
return super.action(evt,what);
}

//suprascrie java.awt.Components.reshape()
//apelata la redimensionarea appletului
public void reshape(int x, int y, int width, int height){
super.reshape(x,y,width,height);

//ajustare scrollbar cu valori vizibile


x_scroll.setValues(rCanavas.offset_x,canavasWidth,0,1000-canavasWidth);
y_scroll.setValues(rCanavas.offset_y,canavasWidth,0,1000-canavasWidth);

rCanavas.repaint();
}
}

Explicaţia codului
Exemplul de mai sus are 4 clase, una dintre ele fiind chiar appletul GUIExample.
DrawableRectangle este o extensie a lui java.awt.Rectangle deoarece java.awt.Rectangle are rol de
a modela o cutie dreptunghiulară în general, iar obiectul appletului este modelarea unei clase de
dreptunghiri care să se deseneze şi în care să se poată include starea informaţiilor despre umplerea
dreptunghiurilor şi culoarea de umplere.
Celelalte 2 clase sunt extensii ale java.awt.Components din categoria widgets9 şi anume
RectCanavas este o colecţie de DrawableRectangles iar CheckBoxPanel dă un mod convenabil de
încapsulare a grupului de elemente Checkbox Group.
Un mare avantaj al funcţionalităţii appletului le dau widgets utilizate şi subclasate în (scrollbar,
buttons, checkbox, etc) avantaje ale OoP demonstrate prin proiectarea GUI.
OOP permite "mascarea" acestor widgets în ierarhii de clasă şi prezintă o interfaţă simplă şi relativ
abstractă a acestora. API reduce complexitatea dezvoltării programelor şi furnizează abstractizarea
necesară.
Componenta Checkbox Grup are capacitatea de a grupa în ea, folosind selecţii mutual exclusive de
Checkbox. Checkbox însuşi răspunde imediat la mouse-click selectându-se grafic pe el însuşi, şi
dacă programatorul a alocat un grup pentru el, deselectează celelalte checkbox din grup10 .
Elementul Choice automat oferă meniul de selecţie iar odată selectată opţiunea se poate transporta
cu metoda getSelectedChoice(). In aceste componente nu trebuie să răspundem de evenimentul
mouse-click pentru că este proiectată metoda handleEvent() în fiecare. In general, componentele
ce răspund în mod normal la evenimente mouse-click sau alte evenimente de la tastatură,
suprascriu handleEvent() şi gestionează click-mouse, generând alte evenimente, d eobicei de tip
ACTION_EVENT.

9
putem asimila widgets ca elemente grafice prefabricate
10
respectând selecţii mutual exclusive

47
4.8. Manipularea evenimentelor în funcţie de ierarhia componentelor

Când apare un eveniment, sistemul crează un obiect din clasa java.awt.Event, determinat de
componentă şi acesta ia evenimentul apelat de metoda handleEvent() a componentei, trecând
obiectul Event ca parametru.In manipularea evenimentelor trebuie să se ţină cont de iararhia
componentelro. Spre exemplu, ce se întâmplă dacă apare evenimentul mouse-click pe Canavas,
conţinut d ePanel, conţinut la rândul lui de Applet? Sistemul respectă următoarea regulă; începe cu
cel mai mic component din ierarhie şi îl tratează urmâd ca apoi să examineze alte evenimente din
ierarhie. Ierarhia de componente este cea stabilită de Components (figura 4.6.) şi Conteir-ele lor şi
nu este ierarhia moştenirii.Dacă handleEvent() a componentei întoarce true, însemnă că
evenimentul este manipulat de acel component şi nu se întreprinde nici o acţiune. Dacă returnează
true, sistemul apelează metoda handleEvent() a următorului component din ierarhie:conteinerul
componentului. Evenimentul continuă să se propage în sus pe ierarhie, până câd un component
întoarce true din handleEvent() sau nu au rămas componente cărora să le aparţină evenimentul.
Unele componente ca şi Checkbox, Button, Choice, ce nu au nivel cert al funcţionalităţii
moştenite, răspund la evenimente, generând evenimente adiţionale, cel mai frecvent
Event.ACTION_EVENT. Barele de defilare generează variate tipuri de evenimente. Listele de
selecţie generează Event.LIST_SELECT şi Event.LIST_DESELECT în plus faţă de
Event.ACTION_EVENT.

4.8.1. java.awt.Component.handleEvent()

Câteva tipuri de evenimete ca şi Event.MOUSE_DOWN, Event.MOUSE_DRAG şi


Event.ACTION_EVENT sunt manipulate de java.awt.Component.handleEvent() ce răspunde de
ele, apelând mouseDown(), mouseDrag() şi action(). In componentele generice (în particular
Applet, Panel şi Canavas) aceste metode sunt void. Dacă se doreşte ca un component să răspundă
într-un anume mod la aceste evenimente, se vor subclasa şi prin simpla suprascriere a metodelor
mouseDown(), mouseDrag() şi action() se va adăuga acţiunea dorită. Versiunea implicită a lui
handleEvent() nu răspunde la toate tipurile de Event definite în java.awt.Event. Dacă este necesar
un răspuns la evenimente ce n-au fost prinse în handleEvent(), implicit se suprascrie handleEvent()
ca şi clasa applet . Se poate utiliza o versiune proprie a lui handleEvent() , care răspunde la aceste
tipuri de evenimente şi care nu sunt prinse în versiunea implicită. Odată terminată verificarea
acestora, se apelează super.handleEvent, pentru a lăsa versiunea implicită să manipuleze
evenimente ce sunt deja programate pentru a fi manipulate ca şi ACTION_EVENT.
Codul java.awt.Component.handleEvent()11 este:
public boolean handleEvent(Event evt){
switch (evt.id0 {
case Event.MOUSE_ENTER:
return mouseEnter(evt, evt.x,evt.y);
case Event.MOUSE_EXIT:
return mouseExit(evt, evt.x,evt.y);
case Event.MOUSE_MOVE:
return mouseMove(evt, evt.x,evt.y);
case Event.MOUSE_DOWN:
return mouseDown(evt, evt.x,evt.y);
case Event.MOUSE_DRAG:
return mouseDrag(evt, evt.x,evt.y);

11
[java_4] Java Soft INC., Java Advanced API Specification, http://java.sun.com/products/java-media/jai

48
case Event.MOUSE_UP:
return mouseUp(evt, evt.x,evt.y);
case Event.KEY_PRESS:
case Event.KEY_ACTION:
return keyDown(evt, evt.key);
case Event.KEY_RELEASE:
return keyUp(evt, evt.key);
case Event.ACTION_EVENT:
return keyDown(evt, evt.arg);
case Event.GOT_FOCUS:
return gotFocus(evt, evt.arg);
case Event.LOST_FOCUS:
return lostFocus(evt, evt.arg);
}
return false;
}

4.8.2. Câmpuri din java.awt.Event

Obiectul Event are o serie de câmpuri dar facem referire doar la cele mai importante folosite în
programare:
• id - conţinut de tipul Event ca şi Event.ACTION_EVENT sau Event.MOUSE_DOWN;
• target - conţinând widgets ce generează evenimetul;
• when- caracteristica de timp indicată când evenimentul apare (utilizat numai pentru mouse şi
tastatură);
• x,y, coordonatele evenimentului (utilizat numai pentru mouse şi tastatură şi
WINDOW_MOVED);
• key -cod ASCII pentru cheia apăsată în evenimentul de la tastatură;
• modificatori- indicaţii asupra cheilor (SHIFT,CTRL) care sunt jos când evenimentul keyboard
sau mouse apare. Ele nu sunt utilizate la MOUSE_ENTER sau MOUSE_EXIT. Cheile
modificatoare nu generează ele însele evenimente. Fiecare este reprezentată de un set de biti
neacoperibili astfel încât se pot utiliza constante mască furnizate de clasa Event, pentru a
determina câd un modificator dat a fost jos în timpul evenimentului de la tastatură sau mouse.
• arg conţin un Object ce variază pentru tipurile particulare de evenimente. Pentru
ACTION_EVENT este String cu eticheta elementului selectat, generat când Button este apăsat
sau Choice, Checkbox sau MenuItem sunt selectate, ListItem sau double-click sau utilizatorul
apasă cheia Return din textField. Pentru evenimente din Scrollbar, fiecare dintre acestea conţine
un int ce indică poziţia cu care Scrollbar a fost mutată. In final, când utilizatorul dă single-click în
List, se generează unul din evenimentele LIST_SELECT sau LIST_DESELECTpentru acre
câmpul arg este int şi indică aloare indexului elementului pe care s-a acţionat click.[java_5]
Pentru a redimensiona componentele apelăm la metoda supascrisă a lui
java.awt.Component.reshape() deoarece appletul conţine Scroolbar şi sunt necesare modificări
de dimensiune pentru a asigura dimensiuni "vizibile" în conţinutul virtual dat de Canavas. In cazul
în care se suprascrie reshape(0 se apelează apoi super.reshape() dat fiind faptul că metoda
implicită face o serie de reamenajări care în cazul în care nu sunt realizate, conduc la apariţia unor
efecte nedorite pe ecran.

49

S-ar putea să vă placă și