Asa cum am promis in episodul
trecut al serialului "Apleturi Java", in acest episod, ca si in cele ce
vor urma, voi prezenta cate un exemplu. Din acest exemplu veti invata cum
puteti crea interactiune cu utilizatorul folosind butoane, campuri de text
etc.
Exemplul din acest episod se numeste
Triunghiul lui Sierpinski. Dati un click aici
pentru a vedea apletul ruland, enuntul problemei si cateva alte informatii.
Deoarece apleturile java trebuie sa fie portabile relativ la sistemul de operare, orice mediu de dezvoltare Java furnizeaza clase pentru crearea elementelor de baza necesare unei interfete grafice. Aceste elemente includ: etichete (labels), campuri de text (text fields), butoane (buttons), radio butoane (radio buttons), cutii de selectie (check boxes), meniuri de selectie (choice menus) etc. Toate aceste elemente sunt incluse, asa cum va spuneam si data trecuta, in pachetul java.awt.
Etichete
O eticheta se creeaza apeland
constructorul clasei Label,
in felul urmator:
Label eticheta = new
Label(str, align); unde str
este o variabila de tip String
care defineste sirul de caractere care va fi scris pe aceasta eticheta,
iar align
este una dintre valorile Label.LEFT,
Label.CENTER
sau Label.RIGHT,
reprezentand alinierea etichetei la stanga, in centru sau la dreapta.
Dupa crearea etichetei,
aceasta trebuie adaugata apletului scriind in cadrul functiei init()
urmatoarea linie: add(eticheta).
Dupa cum puteti vedea, eticheta
creata mai sus va fi afisata pe suprafata apletului in stanga, in centru
sau in dreapta. Acest lucru nu va da prea multa libertate. De exemplu,
cum puteti afisa o eticheta la anumite coordonate si cum puteti seta latimea
si inaltimea etichetei dupa anumite valori?
Atunci cand creati un aplet,
Java creeaza si asigneaza in mod automat un layout implicit. Puteti seta
layout-ul ca avand diferite
valori, printre care enumar
FlowLayout,
GridLayout, BorderLayout, CardLayout,
GridBagLayout. Acestea sunt clase care
fac parte din pachetul java.awt.
Prin urmare le puteti gasi acolo. Eu nu imi propun sa explic aceste clase
pentru ca personal nu le folosesc, preferand sa am libertatea de a seta
coordonatele si dimensiunile. Cum se face acest lucru? Pentru aceasta,
trebuie sa nu fie setat nici un layout, ceea ce se face prin comanda setLayout(null).
Apelati aceasta functie prima in init()
si va va permite sa dati ce coordonate si dimensiuni doriti etichetelor.
Haideti incetul cu incetul sa construim apletul pe care vi l-am propus:
import java.applet.Applet;
import java.awt.*;
public class proba extends
Applet {
Label labelxa = new Label();
Label labelya = new Label();
public void init() {
setLayout(null);
labelxa.setText("xa");
labelxa.reshape(52,12,24,24);
add(labelxa);
labelya.setText("ya");
labelya.reshape(88,12,24,24);
add(labelya);
}
}
Am notat in acest exemplu
si voi nota si de acum incolo conventional instantele claselor de tip Label,
Button
etc. dupa clasa din care fac parte. Astfel, un obiect de tip Label
il voi nota de exemplu cu labelxa
sau labelya.
Deci in exemplul de mai
sus am creat mai intai doua obiecte de tip Label.
Apoi, in cadrul metodei init()
am setat layout-ul pe null.
Dintre metodele clasei Label,
mai folosite sunt:
public void setText(String
str); seteaza sirul de scris pe str,
public String getText();
returneaza sirul afisat.
Clasa Label
mosteneste clasa Component,
deci si toate metodele implementate de aceasta.
Clasa Component
reprezinta o componenta generica ce are ca atribute: coordonata x, coordonata
y, latime, inaltime, culoare de foreground, culoare de background, font,
vizibilitate etc.
Printre metodele implementate
de clasa Component,
mai folosite sunt:
public void move(int
x, int y); muta obiectul la coordonatele
x si y specificate;
public void resize(int
latime, int inaltime); redimensioneaza
latimea si inaltimea cu valorile specificate;
public synchronized
void reshape(int x, int y, int latime, int inaltime);
muta si redimensioneaza obiectul la valorile specificate.
Prin urmare, clasa Component
ofera mai multe atribute necesare claselor de tip
Label, Button etc, si chiar si clasa
Applet
mosteneste aceasta clasa, chiar daca nu direct (clasa Applet
mosteneste clasa Panel,
care mosteneste clasa Container,
care mosteneste clasa Component).
Daca cititi fisierele applet.java,
component.java, label.java etc. va
veti clarifica in ceea ce priveste mostenirile si metodele acestor clase.
Revenind la exemplul nostru,
dupa ce am stabilit textul de scris si pozitia si dimensiunile obiectului,
acesta trebuie adaugat apletului prin add(labelxa).
Adaugati in acelasi fel etichetele
labelxb, labelyb, labelxc, labelyc, labelIteratii,
corespunzand celorlalte etichete pe care le-ati vazut in aplet. Apoi compilati
programul si rulati-l, apelandu-l dintr-un fisier .html
in care sa aveti linia:
<applet code=triunghi.class
width=500 height=500></applet>
Campuri de text
Obiectele de tip TextField
sunt asemanatoare cu cele de tip Label.
Deci le veti crea astfel:
TextField textFieldxa
= new textField();
TextField textFieldya
= new textField();
In corpul functiei init()
veti seta textul implicit, coordonatele si dimensiunile, si apoi le veti
adauga apletului astfel:
textFieldxa.setText("250");
textFieldxa.reshape(42,36,36,24);
add(textFieldxa);
textFieldya.setText("100");
textFieldya.reshape(88,36,36,24);
add(textFieldya);
Creati si celelalte campuri de text, si anume textFieldxb, textFieldyb, textFieldxc, textFieldyc si textFieldIteratii.
Butoane
Asa cum va asteptati, butoanele
pot fi create in mod asemanator cu etichetele si campurile de text:
Button buttonRedeseneaza
= new Button();
buttonRedeseneaza.setLabel("Redeseneaza");
buttonRedeseneaza.reshape(356,36,96,24);
add(buttonRedeseneaza);
Sa vedem acum partea cea mai interesanta, si anume: interactiunea cu utilizatorul: cum putem citi datele introduse in campurile de text?
Pentru a executa o actiune
de gen apasarea unui buton, se apeleaza metoda action,
astfel:
public boolean action(Event
evt, Object arg);
Primul parametru, evt,
este un obiect de tip Event,
care desemneaza un eveniment primit de aplet, de exemplu poate fi vorba
de un eveniment de la tastatura sau de la mouse. Campul target
al unui obiect de tip Event
indica tipul obiectului care a generat evenimentul. Pentru a determina
acest obiect, folosim cuvantul cheie instanceof
astfel:
if (evt.target instanceof
Button). Daca acesta este adevarat,
pentru a vedea exact care buton a fost apasat, de exemplu se scrie linia:
if (arg == "Redeseneaza")
pentru a vedea daca a fost apasat butonul
cu textul "Redeseneaza".
In exemplul prezentat nu
avem mai multe butoane, deci nu e nevoie sa folosim aceasta din urma linie,
dar o puteti exersa construind mai multe butoane si adaugand evenimente
diferite pentru fiecare dintre ele.
Sa revenim la exemplul nostru.
Dupa ce ati construit etichetele, campurile de text si un buton, sa citim
datele introduse.
Pentru aceasta, mai declarati
ca variabila a apletului variabila sir
de tip String
pentru a citi in ea datele introduse intr-un camp de text:
String sir;
Apoi adaugati urmatoarele
doua metode apletului:
public boolean action(Event
evt, Object arg) {
if(evt.target
instanceof Button) {
sir=textFieldxa.getText();
repaint();
return true;
}
return false;
}
public void paint(Graphics
g) {
g.drawString(sir,10,100);
}
Functia action
citeste sirul de caractere introdus in campul textFieldxa
si il introduce in variabila sir
declarata anterior. Apoi apeleaza functia repaint().
Aceasta este definita in clasa Component
si executa metoda paint(Graphics
g). Nu mai ramane deci decat sa apelam
functia drawString
(pe care am explicat-o luna trecuta) in corpul functiei paint.
Sa citim acum datele introduse
in campurile corespunzatoare coordonatelor si sa desenam un triunghi.
Trebuie sa declaram mai
intai 6 variabile pentru cele 6 coordonate:
int xa, ya, xb, yb,
xc, yc;
In locul variabilei declarate
anterior String sir;
vom declara Integer temp;
pentru a citi datele introduse. Metoda action
va deveni:
public boolean action(Event
evt, Object arg) {
if(evt.target
instanceof Button) {
temp=Integer.valueOf(textFieldxa.getText());
xa=temp.intValue();
temp=Integer.valueOf(TextFieldya.getText());
ya=temp.intValue();
temp=Integer.valueOf(TextFieldxb.getText());
xb=temp.intValue();
temp=Integer.valueOf(TextFieldyb.getText());
yb=temp.intValue();
temp=Integer.valueOf(TextFieldxc.getText());
xc=temp.intValue();
temp=Integer.valueOf(TextFieldyc.getText());
yc=temp.intValue();
repaint();
return true;
}
return
false;
}
Am citit in temp
valoarea introdusa in campul textFieldxa
ca Integer,
si apoi am trecut-o in variabila xa
transformand-o mai intai in int.
Transformand textul introdus intr-o valoare de tip int,
realizam si o validare, in sensul ca daca introduceti in vreunul din campuri
o alta valoare decat un numar intreg, ea va fi ignorata.
Functia paint
devine:
public void paint(Graphics
g) {
g.drawLine(xa,ya,xb,yb);
g.drawLine(xb,yb,xc,yc);
g.drawLine(xc,yc,xa,ya);
}
Rulati tot ce am facut pana
acum si veti vedea ca apasand butonul veti desena un triunghi, iar daca
modificati valorile campurilor si apasati din nou butonul, triunghiul va
avea alta forma.
Pentru ca triunghiul sa
apara de prima data (pentru niste valori initiale ale coordonatelor), fara
sa mai fie nevoie sa mai apasati o data butonul, trebuie sa copiati liniile
de tipul:
temp=Integer.valueOf(textFieldxa.getText());
xa=temp.intValue();
astfel incat ele sa apara
si la sfarsitul functiei init().
Initial valorile xa, ya, xb, yb,
xc, yc au valoarea zero ( la declararea
unei variabile, acesteia i se asigneaza valoarea 0
sau null)
si de aceea nu apare nimic desenat.
In sfarsit, sa desenam figura
care reprezinta Triunghiul lui Sierpinski. Pentru aceasta trebuie definita
o functie recursiva care imparte triunghiul initial in 4 triunghiuri egale
si care se autoapeleaza pentru toate triunghiurile, exceptand triunghiul
din mijloc. Aceasta este o problema de programare si nu mi-am propus sa
o explic in acest exemplu. Daca nu ati mai facut functii recursive sau
nu sunteti obisnuiti cu programarea, luati-o ca atare si incercati sa o
intelegeti. Nu este atat de grea precum pare.
Aceasta functie este data
mai jos:
void Sierpinski(Graphics
g,int xa,int ya,int xb,int yb,int xc,int yc,int iteratii) {
int
x1,y1,x2,y2,x3,y3; //coordonatele
mijloacelor laturilor
x1=(xa+xb)/2;
y1=(ya+yb)/2;
x2=(xb+xc)/2;
y2=(yb+yc)/2;
x3=(xa+xc)/2;
y3=(ya+yc)/2;
g.drawLine(x1,y1,x2,y2);
g.drawLine(x1,y1,x3,y3);
g.drawLine(x2,y2,x3,y3);
int
xpoly[]={x1,x2,x3};
int
ypoly[]={y1,y2,y3};
g.fillPolygon(xpoly,ypoly,3);
//umplerea triunghiurilor exterioare cu culoarea implicita
if(iteratii>1)
{
Sierpinski(g,xa,ya,x1,y1,x3,y3,iteratii-1);
Sierpinski(g,x1,y1,xb,yb,x2,y2,iteratii-1);
Sierpinski(g,x3,y3,x2,y2,xc,yc,iteratii-1);
}
}
Aceasta functie trebuie apelata
din functia paint,
astfel incat ea devine:
public void paint(Graphics
g) {
g.drawLine(xa,ya,xb,yb);
g.drawLine(xb,yb,xc,yc);
g.drawLine(xc,yc,xa,ya);
Sierpinski(g,xa,ya,xb,yb,xc,yc,nr_iteratii);
}
unde nr_iteratii
este o variabila de tip int
a carei valoare o citim la fel ca si xa,
ya etc.
Alte clase inrudite cu cele prezentate mai sunt: CheckBox, Choice, TextArea, Menu, MenuItem, MenuBar, ScrollBar etc. Unele sunt foarte mult asemanatoare cu cele din acest episod, altele au elemente specifice. Voi prezenta detalii asupra lor atunci cand le vom folosi in alte exemple.
Pentru a ne cunoaste mai bine, pentru
ca voi sa fiti stimulati sa invatati Java si pentru ca eu sa obtin un raspuns
la ceea ce va explic, va propun ca de acum incolo sa realizati unul sau mai
multe apleturi in care sa folositi ce ati invatat in fiecare episod (si eventual
alte elemente, cu cat mai multe si mai interesante, cu atat mai bine) si sa
le trimiteti la adresa mirela.andronescu@er.dntis.ro.
Cele mai interesante apleturi vor fi apoi puse pe Internet la adresa revistei
noastre http://er.dntis.ro.
De asemenea orice intrebari, neclaritati,
propuneri, critici pe teme de Java sunt binevenite la aceeasi adresa de e-mail.
Va astept sa imi scrieti,
Sarbatori Fericite, si sa ne auzim cu bine in anul 2000!