Appleturi Java

34
Appleturi Java (I) Mirela Stefania Andronescu Articolul de fata face parte dintr-un set de articole care se adreseaza atat celor familiarizati cu programarea orientata pe obiecte cat si celor care nu cunosc limbaje OO. Voi aminti pe scurt in 1.1. caracteristicile unui limbaj orientat pe obiecte. Pentru mai multe detalii despre obiecte, recititi articolele despre Java aparute in numerele trecute ale revistei noastre. In 1.2. voi prezenta caracteristicile programarii orientate pe obiecte in Java si apoi vom trece la construirea de exemple (un prim exemplu este 1.3. ). Astfel veti invata din exemple Daca o anumita notiune nu este clara la un moment dat, nu-i nimic, vom reveni asupra ei. Totul se va clarifica folosind exemplele. Exemplele prezentate pot fi compilate folosind Java Development Kit (JDK) care poate fi obtinut free de la adresa www.sun.com , Microsoft Vijual J++ sau orice alt mediu de dezvoltare Java. 1.1. Introducere. Programarea orientata pe obiecte Programarea orientata pe obiecte este procesul de construire a aplicatiilor cu obiecte. Pentru a intelege cum lucreaza un limbaj orientat pe obiecte, iata cateva notiuni de baza: O clasa defineste un tip abstract de date. Ea are o definitie al carei format simplificat este: class nume {lista_elementelor_membru} Lista_elementelor_membru cuprinde date membru si functii membru (metode). Un obiect este o data de un tip definit printr-o clasa. Se spune ca un obiect este o instantiere a clasei respective. Un limbaj orientat pe obiecte are urmatoarele caracteristici: incapsularea, mostenirea si polimorfismul. Incapsularea este un mecanism care leaga impreuna functii si date si le pastreaza in siguranta fata de interventii din afara si de utilizari gresite. Asadar un obiect este o entitate logica ce incapsuleaza atat date cat si functii care manevreaza aceste date. Mostenirea este procesul prin care un obiect poate sa preia prototipul altui obiect. Acest lucru introduce conceptul de clasificare. De exemplu, un trandafir face parte din clasa floare care face parte din clasa plante etc. Mecanismul mostenirii este acela care face posibil ca un obiect sa fie un exemplar specific al unui caz mai general. Clasa initiala se numeste clasa de baza, clasa parinte sau superclasa si clasa care deriva din clasa de baza se numeste clasa derivata, clasa copil sau subclasa. Polimorfismul. Uneori o metoda a clasei parinte nu se potriveste si clasei copil. Atunci functia va fi suprascrisa in clasa derivata. Alteori aceeasi functie trebuie sa execute altceva in functie de situatie. Acest proces se numeste polimorfism. 1.2. Programarea orientata pe obiecte in Java Limbajul Java a fost construit de firma Sun pornind de la limbajul C++, dar au fost indepartate unele aspecte din C++, precum supraincarcarea operatorilor si mostenirea multipla. De asemenea, pointerii lipsesc

description

apleturi java

Transcript of Appleturi Java

Page 1: Appleturi Java

Appleturi Java (I) Mirela Stefania Andronescu

Articolul de fata face parte dintr-un set de articole care se adreseaza atat celor familiarizati cu programarea orientata pe obiecte cat si celor care nu cunosc limbaje OO. Voi aminti pe scurt in 1.1. caracteristicile unui limbaj orientat pe obiecte. Pentru mai multe detalii despre obiecte, recititi articolele despre Java aparute in numerele trecute ale revistei noastre. In 1.2. voi prezenta caracteristicile programarii orientate pe obiecte in Java si apoi vom trece la construirea de exemple (un prim exemplu este 1.3.). Astfel veti invata din exemple Daca o anumita notiune nu este clara la un moment dat, nu-i nimic, vom reveni asupra ei. Totul se va clarifica folosind exemplele. Exemplele prezentate pot fi compilate folosind Java Development Kit (JDK) care poate fi obtinut free de la adresa www.sun.com, Microsoft Vijual J++ sau orice alt mediu de dezvoltare Java.1.1. Introducere. Programarea orientata pe obiecte Programarea orientata pe obiecte este procesul de construire a aplicatiilor cu obiecte. Pentru a intelege cum lucreaza un limbaj orientat pe obiecte, iata cateva notiuni de baza: O clasa defineste un tip abstract de date. Ea are o definitie al carei format simplificat este: class nume {lista_elementelor_membru}Lista_elementelor_membru cuprinde date membru si functii membru (metode). Un obiect este o data de un tip definit printr-o clasa. Se spune ca un obiect este o instantiere a clasei respective. Un limbaj orientat pe obiecte are urmatoarele caracteristici: incapsularea, mostenirea si polimorfismul. Incapsularea este un mecanism care leaga impreuna functii si date si le pastreaza in siguranta fata de interventii din afara si de utilizari gresite. Asadar un obiect este o entitate logica ce incapsuleaza atat date cat si functii care manevreaza aceste date. Mostenirea este procesul prin care un obiect poate sa preia prototipul altui obiect. Acest lucru introduce conceptul de clasificare. De exemplu, un trandafir face parte din clasa floare care face parte din clasa plante etc. Mecanismul mostenirii este acela care face posibil ca un obiect sa fie un exemplar specific al unui caz mai general. Clasa initiala se numeste clasa de baza, clasa parinte sau superclasa si clasa care deriva din clasa de baza se numeste clasa derivata, clasa copil sau subclasa.Polimorfismul. Uneori o metoda a clasei parinte nu se potriveste si clasei copil. Atunci functia va fi suprascrisa in clasa derivata. Alteori aceeasi functie trebuie sa execute altceva in functie de situatie. Acest proces se numeste polimorfism. 1.2. Programarea orientata pe obiecte in Java Limbajul Java a fost construit de firma Sun pornind de la limbajul C++, dar au fost indepartate unele aspecte din C++, precum supraincarcarea operatorilor si mostenirea multipla. De asemenea, pointerii lipsesc complet din limbajul Java, eliminandu-se astfel una din principalele surse de erori. In plus, eliberarea memoriei ocupate de obiecte si masive se face automat, printr-un "mecanism de colectare de gunoaie". Limbajul Java mai are inclus un suport pentru aplicatii care lucreaza cu mai multe fire de executie, inclusiv primitive de sincronizare intre firele de executie (vom vedea acest lucru mai tarziu). Limbajul Java lucreaza folosind setul de caractere Unicode. Acesta este un standard international al carui set de caractere este reprezentat pe 16 biti. Vechiul standard ASCII este un subset al standardului Unicode, adica vom regasi aici caracterele ASCII cu exact aceleasi coduri. Diferenta majora este ca o variabila Java de tip caracter, de exemplu, este reprezentata pe 16 biti, iar un sir de caractere va ocupa de doua ori mai multa memorie decat numarul caracterelor. Analog, o variabila de tip intreg, care in C era reprezentata pe 16 biti, acum va fi reprezentata pe 32 de biti. Avantajul setului Unicode este ca, fiind reprezentat pe 16 biti, are posibilitati mult mai mari. Spre deosebire de alte limbaje orientate pe obiecte (de ex. C++), in Java fiecare linie de cod apartine unei clase. Alfel spus, un program sursa Java este format numai din clase si interfete (veti vedea in curand ce inseamna toate acestea). Pentru ca un program scris in Java sa devina functionabil, trebuie sa fie mai intai compilat si apoi interpretat. Un program sursa are extensia .java. Numele sau trebuie sa fie identic cu numele clasei sau interfetei publice declarate in interiorul sursei. In urma compilarii rezulta fisiere cu

Page 2: Appleturi Java

nume identice cu numele claselor, dar cu extensia .class, indiferent daca este vorba de o clasa sau o interfata (vor fi create atatea fisiere .class cate clase si interfete sunt definite in fisierul sursa). O data fisierele compilate, acestea pot rula ca aplicatii sau apleturi. O aplicatie este un program care va fi rulat de sine-statator, cu ajutorul unui interpretor (java sau jview). Un aplet Java ruleaza intr-un document HTML si fisierele compilate .class sunt interpretate de Java Virtual Machine. Acesta este un software care sta pe masina unde fisierele compilate .class vor fi rulate (JVM este instalat o data cu instalarea browserului de web). Scopul acestui set de articole este crearea de apleturi Java (de cele mai multe ori codul pentru apleturi difera intr-o oarecare masura de codul pentru aplicatii).

Sintaxa folosita pentru a crea o noua clasa in Java este: modificator class numeclasa [extends clasaparinte] [implements interfete] modificator poate fi unul din urmatoarele cuvinte cheie: public – o clasa declarata public poate fi folosita de orice obiect. De retinut ca un fisier sursa .java poate avea o singura clasa publica. Numele fisierului sursa trebuie sa fie identic cu numele clasei publice; private – o clasa declarata private poate fi folosita numai de clase din acelasi fisier sursa. O sursa .java poate contine numai o clasa publica, dar mai multe clase private; <nimic> - daca nu este specificat nici un modificator, clasa va fi considerata "friendly" (prietenoasa) (a nu se confunda cu clasele sau functiile friend din C++!), ceea ce inseamna ca toate celelalte clase din acelasi pachet (veti vedea mai jos ce este un pachet) pot accesa clasa respectiva; synchronizable – este folosit pentru a sincroniza elementele (vom vedea mai tarziu); abstract – o clasa abstracta contine numai metode fara implementare (corpul functiei nu este definit aici) si este folosita drept clasa de baza pentru eventuale clase care deriva din ea; final – o clasa finala nu poate fi mostenita (alte clase pot accesa clasa finala, dar nici o alta clasa nu poate deriva din ea).Urmatorul exemplu arata o clasa publica si una privata care pot fi create in acelasi fisier sursa: Public class clasa1 {     int x;     MetodaX(int x); } private class clasa2 {     int y;     MetodaY(int y); } Asa cum clasele pot fi declarate folosind modificatorii descrisi mai sus, Java permite si ca variabilele si metodele sa fie prefixate de unul din urmatorii modificatori: public – o metoda sau variabila declarata public poate fi accesata de orice clasa; protected – poate fi accesata numai de subclase; private – poate fi accesata numai de metode din aceeasi clasa; <nimic> - daca nu este specificat nici un modificator, metoda sau variabila poate fi accesata de orice alta clasa din acelasi pachet; static – specifica o metoda sau variabila valabila global pentru toate instantele unei clase; native – denota o metoda implementata in alt limbaj de programare (de ex. C++) final – specifica o variabila constanta (valoarea ei nu poate fi schimbata in momentul rularii) sau o metoda care nu poate fi supraincarcata de o clasa derivata. synchronized – acest cuvant cheie blocheaza obiectul atunci cand aceasta metoda este apelata si il deblocheaza atunci cand se iese din metoda.

In Java mostenirea se realizeaza prin folosirea cuvantului cheie extends. Astfel, clasa derivata va "mosteni" toate variabilele si metodele definite in clasa de baza si va adauga variabile si

Page 3: Appleturi Java

metode specifice (veti vedea putin mai jos un exemplu). Spre deosebire de limbajul C++, in Java o clasa poate mosteni numai o singura clasa. Java permite extinderea acestei functionalitati prin intermediul interfetelor. O interfata este o declaratie a unui set de metode care nu sunt implementate. O clasa implemeteaza o interfata prin cuvantul cheie implements si este responsabila pentru scrierea codului metodelor definite in interfata. O interfata poate deriva din una sau mai multe interfete. Desi o clasa poate mosteni o singura clasa, ea poate implementa oricate interfete. Exemplu de derivare a unei clase folosind mostenirea si implementarea: Sa presupunem clasa de baza om si interfata comportament, definite astfel: public class om {    int anul_nasterii;    char sex;    int returneaza_varsta(int anul_nasterii) {      cod…   }; }

public interface comportament {    void citeste();    void mananca();    void danseaza(); }

Sa derivam clasa student din clasa om si sa implementam interfata comportament :public class student extends om implements comportament{    String facultatea;    int anul;    int note[20];    int calculeaza_media(int note[]){cod…};    void citeste(){       corpul_functiei_citeste;    }    void mananca(){       corpul_functiei_mananca;    }    void danseaza();{       corpul_functiei_danseaza;    }}

Mai multe clase si interfete care au ceva in comun pot fi grupate intr-un pachet (package) adaugand urmatoarea linie la inceputul fiecarui fisier sursa: package nume_pachet; Sa presupunem ca am creat clase si interfete care reprezinta persoane: class om; class student; interface comportament; class profesor; class muncitor; Putem grupa aceste clase si interfete intr-un pachet numit persoana scriind linia package persoana la inceputul fiecarui fisier sursa care contine clasele de mai sus.Realizatorii limbajului Java au creat si un numar mare de pachete (dintre care enumar: java.applet, java.awt, java.io, java.lang, java.math, java.net, java.security, java.sql, java.text, java.util). Fiecare contine clase si interfete pentru a fi reutilizate de programator. Daca aveti JDK, in directorul unde l-ati instalat se afla un fisier \lib\classes.zip. Daca ati instalat Vijual J++, in directorul c:\windows\java\classes\java\ veti

Page 4: Appleturi Java

gasi mai multe directoare. Daca nu ati instalat inca un mediu de dezvoltare Java, dar aveti un browser cu capacitati Java, de exemplu Internet Explorer pe un mediu Windows 95/98, uitati-va prin fisierele .zip din directorul c:\windows\java\packages\. Exista o conventie conform careia numele pachetelor au fost create pe structura directoarelor. Astfel, pentru a crea subpachetul cu numele java.applet, a fost creat un director cu numele java, apoi un subdirector al acestuia cu numele applet. Toate subpachetele lui applet se vor afla in directorul applet. Va recomand ca pe masura ce invatati sa programati in Java, sa va uitati prin fisierele acestor directoare pentru a intelege structura ierarhica a claselor si functiile si variabilele definite de fiecare clasa. Asadar, iata, pe scurt, cate ceva despre cateva dintre aceste pachete:

1. Pachetul java.applet contine clase folosite pentru a crea apleturi Java si pentru a lucra cu ele. Fiecare aplet este derivat direct din clasa java.applet.Applet din acest pachet.

2. Pachetul java.awt contine clasele si subpachetele care alcatuiesc Java Abstract Windowing Toolkit (AWT). Acest pachet furnizeaza principalele clase care permit unei aplicatii GUI (Graphical User Interface) scrise in Java sa ruleze pe orice platforma. Cateva exemple de clase incluse in pachetul java.awt sunt: Button, List, Menu, CheckBox, Color, Font, Graphics, Image, Point, Rectangle, Polygon, Window etc.

3. Pachetul java.io contine clase cu capacitati de intrare/iesire. Programatorul poate citi de la intrarea standard sau scrie la iesirea standard: File, FileInputStream, FileOutputStream, DataInputStream etc.

4. Pachetul java.lang contine clasele care corespund tipurilor de date de baza (Integer, Boolean, Float, Character, Long, Double). In acelasi pachet sunt incluse si clasele System ( furnizeaza informatii ale sistemului unde ruleaza) si Thread (furnizeaza posibilitatea crearii mai multor fire de executie);

5. Pachetul java.net include clase pentru comunicatii intre procese pe masini diferite (dintr-o retea de calculatoare). Clasele URL, URLConnection, Socket, InetAddress sunt cateva exemple.

Pachetul java.util ofera un mare numar de clase utile ca: Date, Dictionary, Hashtable, Stack, Vector etc.Clasele cuprinse in aceste pachete si functionalitatile lor vor fi explicate pe masura ce voi prezenta exemple. Fiecare exemplu va folosi clase din aceste pachete.

1.3. Exemplul 1 In primul exemplu vom invata sa scriem un text, sa desenam diferite forme geometrice etc.

Clasele din pachetele despre care tocmai am vorbit sunt folosite intr-un program prin includerea la inceput a unei linii de forma: import numeClasa; Clasa java.applet.Applet este clasa de baza din care deriva orice aplet, deci ea trebuie inclusa intotdeauna cand construim un aplet. Pentru a putea folosi elemente grafice, vom mai include clase din pachetul java.awt.

Iata un prim exemplu de aplet: import java.applet.Applet; import java.awt.Graphics;

public class PrimulAplet extends Applet{     public void paint(Graphics g){         g.drawString("Primul aplet",50,25);     }}

Page 5: Appleturi Java

Metoda paint este mostenita de clasa Applet (de la clasa Component) si se foloseste pentru a desena obiecte. Ea are antetul public void paint(Graphics g). Aici am suprascris-o

(iata deci un exemplu de polimorfism!) pentru a executa ceea ce dorim noi. Functia care realizeaza afisarea unui text este drawString (functie membra a clasei Graphics), ce primeste ca parametri textul de afisat si coordonatele x si y unde textul respectiv va fi scris pe ecran.

Pentru a vedea rezultatele rularii acestui aplet, trebuie ca fisierul HTML sa contina urmatoarea linie: <applet code="PrimulAplet.class" width=150 height=25></applet>Putem introduce in sursa HTML parametrii care vor fi transmisi apletului, astfel: <applet  ...> <param name=titlu value="Acesta este primul meu aplet"> </applet>

Atunci modificam codul apletului folosind functia getParameter(String nume), membra a clasei Applet:public class PrimulAplet extends Applet{     private String sir;     public void init(){         sir=getParameter("titlu");         if(sir==null) sir="Primul aplet";     }     public void paint(Graphics g){         g.drawString(sir,50,25);     } }

Intr-un aplet java nu exista o functie main (cum este in C++ sau in aplicatiile java), care determina apelul celorlalte functii. Atunci care este ordinea in care vor fi executate functiile? Executia unui aplet este marcata de cateva evenimente importante generate de catre browser. La intalnirea etichetei <applet>, browserul incarca fisierul necesar rularii apletului (fisierele .class). Apletul nu poate rula pana cand codul nu a ajuns pe calculatorul client.Dupa incarcarea codului, apletul este apelat automat pentru initializare prin functia init(). Este momentul in care apletul isi pregateste parametrii si obtine de la sistem resursele necesare rularii. In exemplul nostru functia init citeste parametrul titlu transmis apletului de fisierul

HTML. Dupa ce initializarea a fost terminata, browserul trimite catre aplet o comanda de pornire (functia start()). Un aplet ruleaza atat timp cat navigatorul este activ. La schimbarea paginii curente, apleturile din vechea pagina primesc o comanda de oprire temporara (functia stop()). La inchiderea browserului este lansata functia destroy() care distruge toate variabilele alocate, eliberand memoria. Toate aceste functii sunt definite in clasa Applet si sunt apelate automat de sistem. Daca sunteti atenti, atunci cand Internet Explorer incarca un aplet java, scrie pe bara de jos mai intai "Applet initialized", apoi "Applet started", care va sta scris atata vreme cat apletul este activ. Daca apasati butonul "Refresh", va scrie "Applet stopped", si apoi va trece iar la initializare (cu init()) si va porni din nou apletul (cu start()). Orice aplet Java reprezinta deci un nou tip de obiect, derivat din obiectul standard Applet. Sa desenam acum pe ecran diferite obiecte grafice. Pentru aceasta, sa folosim urmatoarele functii, care au fost definite in clasa java.awt.Graphics astfel: - public abstract void drawLine(int x1, int y1, int x2, int y2); deseneaza o linie de la punctul (x1,y1) la punctul (x2,y2), cu culoarea curenta (vom vedea cum o putem

Page 6: Appleturi Java

schimba); - public void drawRect(int x, int y, int width, int height); deseneaza un

patrat cu coltul din stanga sus (x,y) si de latimea width si inaltimea height; - public abstract void fillRect(int x, int y, int width, int height);

deseneaza un patrat plin; - public abstract void drawRoundRect(int x, int y, int width, int

height, int arcWidth, int arcHeight); deseneaza un patrat cu colturile rotunde; - public abstract void fillRoundRect(int x, int y, int width, int

height, int arcWidth, int arcHeight); deseneaza un patrat plin cu colturile rotunde; - public void draw3DRect(int x, int y, int width, int height, boolean raised); daca parametrul raised are valoarea true, deseneaza un patrat cu umbra (asa

cum sunt butoanele); iar daca este false, deseneaza un patrat ca un buton apasat; - public void fill3DRect(int x, int y, int width, int height, boolean

raised); un patrat plin cu umbra; - public abstract void drawOval(int x, int y, int width, int height); deseneaza un oval cu parametri specificati (desigur ca daca width si height sunt egale, va fi

desenat un cerc); - public abstract void fillOval(int x, int y, int width, int height); un oval (cerc) plin; - public abstract void drawPolygon(int xPoints[], int yPoints[], int

nPoints); deseneaza un poligon cu nPoints colturi definite de vectorii xPoints si yPoints; - public abstract void fillPolygon(int xPoints[], int yPoints[], int

nPoints); un poligon plin. Pentru alte functii definite in clasa Graphics, cititi fisierul Graphics.java (din directorul java\

awt\). Putem schimba culoarea curenta cu ajutorul functiei definita tot in clasa Graphics astfel: public abstract void setColor(Color c); Pentru aceasta trebuie sa cunoastem mai intai clasa Color, care face parte tot din pachetul

java.awt. Clasa Color defineste constante corespunzatoare culorilor uzuale: white, lightGray, gray, darkGray, black, red, pink, orange, yellow, green, magenta, cyan si blue. Astfel, de exemplu, pentru a seta culoarea curenta pe rosu vom scrie linia g.setColor(Color.red), unde g este un obiect de tipul Graphics. Putem seta culoarea curenta pe o culoare care nu a fost definita ca o constanta apeland unul dintre constructori (vezi fisierul Color.java), ca exemplu: Color c = new Color(123,200,255). Culoarea de background a apletului se seteaza cu ajutorul functiei setBackground(Color c), mostenita de clasa Applet. Acesta linie trebuie scrisa in corpul metodei init() pentru ca apletul trebuie sa stie inca de la initializare care este culoarea de background (nu poate fi schimbata dupa aceea); Acum aveti destule cunostinte pentru a putea desena cu orice culoare obiecte grafice pe ecran. Va recomand sa construiti apleturi folosind functiile prezentate si eventual si alte functii definite in clasele Graphics si Color. Iata un exemplu! Aici puteti vedea apletul ruland.

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

public class Desene extends Applet {

 private String mesaj;

Page 7: Appleturi Java

 public void init() {      mesaj = getParameter("titlu");      if(mesaj==null) mesaj="Uite ce-am invatat sa desenez in Java! :)) :";      setBackground(Color.cyan);  }

 public void paint(Graphics g) {      g.setColor(Color.black);g.drawString(mesaj,10,15);      g.setColor(Color.blue);      g.drawLine(10,50,30,100);      g.drawRect(50,50,50,50);      g.setColor(Color.red);      g.fillRoundRect(120,50,50,50,20,20);      g.setColor(Color.magenta);      g.fill3DRect(190,50,50,50,true);      g.setColor(Color.pink);      int xpoli[]={250,300,320,380,320,250,250};      int ypoli[]={50,50,80,80,120,100,50};      g.fillPolygon(xpoli,ypoli,7);      Color c = new Color(100,20,200);      g.setColor(c);      g.drawOval(400,50,50,50);  } }

Appleturi Java (2)

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.

Page 8: Appleturi Java

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

Page 9: Appleturi Java

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.

Page 10: Appleturi Java

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;

Page 11: Appleturi Java

    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 .

Apleturi Java (III): Fire de executie

In episodul de luna aceasta vom studia ceva specific limbajului Java, si anume crearea si folosirea firelor de executie.Apletul deseneaza niste cercuri rosii in miscare la fiecare click pe suprafata lui. Care este legatura lui cu firele de executie? Raspunsul este urmatorul: la fiecare click pe suprafata apletului se genereaza un nou fir de executie. Dar haideti sa aflam mai multe despre firele de executie:

Un fir de executie (thread) executa o serie de instructiuni. Un fir poate trai pe tot parcursul apletului sau doar cateva milisecunde. De asemenea un fir poate da nastere altui fir sau poate omori un fir existent.

Chiar si in apleturile din episoadele trecute exista unul sau mai multe fire de executie "ascunse", create de browser. Atunci cand are loc un eveniment de gen click de mouse, sau cand se apeleaza o functie ca repaint(), este executat un anumit fir ascuns. Firele ascunse sunt create si executate automat de limbaj si sunt transparente pentru programator. Daca rulati orice aplet in modul debugger al mediului de dezvoltare Java pe care il folositi, veti vedea cateva fire de executie create automat. Exista si situatii in care programatorul are nevoie sa creeze el insusi propriile fire de executie. Trebuie stiut ca in timp ce un fir ruleaza in cadrul apletului, respectivul fir nu poate face altceva. Daca apletul tine un fir prea mult, poate bloca browserul. De aceea daca apletul are nevoie sa ruleze o metoda a sa pentru mai mult timp, este necesar ca un nou fir sa fie creat. Iata care sunt situatiile cele mai frecvent intalnite in care este nevoie de un nou fir de executie:- Timp indelungat pentru initializare (functia init() a apletului). De exemplu, apletul are nevoie de ceva timp pentru a incarca o imagine. Un fir este folosit pentru ca sistemul sa poata primi alte evenimente.

Page 12: Appleturi Java

- Task-uri repetitive sau care trebuie sa dureze o anumita perioada de timp. De exemplu pentru animatii. La fiecare cateva milisecunde este afisat un nou frame. Firul deseneaza frame-ul, sta o perioada de timp, apoi reia procesul.- Evenimente asincrone. De exemplu un click de mouse. Daca utilizatorul apasa butonul mouse-ului, un nou fir este creat pentru a reda un nou frame dintr-o imagine.- Mai multe task-uri. Firele sunt folosite pentru a face mai mult de un lucru o data. De exemplu un fir controleaza o animatie in timp ce altul face un calcul.

Pentru a crea si controla firele de executie se folosesc clasa Thread si interfata Runnable din pachetul java.lang. Exista doua metode pentru a crea un fir:1. Implementand interfata Runnable. In acest caz nu este nevoie sa creati o noua clasa. De exemplu daca vreti sa creati un fir chiar in cadrul apletului, faceti apletul sa implementeze aceasta interfata (amintiti-va ca o clasa nu poate mosteni mai multe clase, deci nu poate mosteni si clasa Applet, si clasa Thread). 2. Mostenind clasa Thread. O clasa nou creata mosteneste clasa Thread si firul va incepe sa ruleze conform functiei run() (veti vedea imediat in exemplu).

Nu este aproape nici o diferenta intre cele doua metode. In general metoda a doua se foloseste atunci cand doriti ca firul sa ruleze din clasa-aplet. Daca firul va rula in propria lui clasa, va fi mai convenabila prima metoda.

Dar pentru a intelege mai bine, sa vedem ce contin clasa Thread si interfata Runnable (pentru aceasta cititi si fisierele Thread.java si Runnable.java din pachetul java.lang), si pe urma voi prezenta exemple concrete.

Interfata Runnable are o singura metoda: public abstract void run(). Ea trebuie definita obligatoriu de clasa care implementeaza interfata Runnable. Functia run() va contine codul care va fi executat de firul de executie respectiv.Clasa Thread implementeaza interfata Runnable si contine (printre altele) urmatoarele metode:- mai multi constructori; - start() - face ca firul de executie sa inceapa sa ruleze. In acest moment Java Virtual Machine va apela functia run();- functia run() care suprascrie functia run() a interfetei Runnable; acesta functie trebuie suprascrisa cu codul ce se doreste a fi executat de firul respectiv;- stop() - forteaza oprirea firului de executie.

Crearea si controlul unui fir de executie folosind prima metoda se face parcurgand urmatorii pasi:1. se declara clasa-aplet ca implementand interfata Runnable;2. se declara obiectul de tip Thread;3. se scrie functia init() in care se construieste firul;4. se scrie functia de pornire a firului (start);5. se scrie functia de oprire a firului (stop);6. se suprascrie metoda run();Exemplul urmator creeaza un fir pentru rularea unui contor care numara de la 1 la 100:

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

public class RunnableExample extends Applet     implements Runnable { //pasul 1

Page 13: Appleturi Java

  Thread thread; //pasul 2   int count; //variabila contor   String displayStr; //sirul care va fi afisat in functia paint  Font font;

  public void init() { //pasul 3    font = new Font("TimesRoman", Font.PLAIN, 72);     setFont(font);     count = 0;     displayStr = "";    thread = new Thread(this); //se creeaza firul apeland un constructor   }

  public void start() { //pasul 4     thread.start(); //se porneste firul  }

  public void stop() { //pasul 5    thread.stop();   }

  public void run() { //pasul 6     while (count < 100) { //executa firul atata vreme cat count<100      ++count;       displayStr = String.valueOf(count); //transforma variabila int in String      repaint(); //redeseneaza      try {         thread.sleep(100); //firul sta 100 milisecunde, dupa care reia corpul lui while      }      catch (InterruptedException e) {      }    } }

  public void paint(Graphics g) {     g.drawString(displayStr, 50, 130);   }}

(Nu va bateti capul cu secventa try - catch de mai sus, va voi explica mai pe larg intr-un episod in care voi trata exceptiile in Java.)Nota. Nu este obligatoriu ca metoda stop() (pasul 5) sau linia thread.stop() sa existe, Java va opri automat firul atunci cand nu va mai exista nici o referinta catre el. Totusi este recomandat sa o scrieti. Apelul thread.start() este obligatoriu, fara el firul nu va porni,adica nu se va executa functia run(). Insa nu este obligatoriu ca el sa fie in functia public void start(). Putea sa fie in alta parte unde se stie ca se executa inaintea apelului celorlalte functii care apeleaza firul, de exemplu putea fi ultima linie a functiei public void init().Daca ati urmarit cu atentie ce am explicat pana acum, acest exemplu ar trebui sa vi se para chiar usor. Pentru intrebari, scrieti la [email protected].

Haideti acum sa vedem cum se face acelasi lucru folosind cea de a doua metoda. Vom parcurge

Page 14: Appleturi Java

urmatorii pasi:1. cream clasa ThreadExample care mosteneste clasa Applet;2. scriem functia init() care va crea un fir prin apelul constructorului clasei MyThread; 3. cream clasa MyThread care mosteneste clasa Thread;4. declaram campurile clasei MyThread, printre care obligatoriu trebuie sa fie un obiect de tipul ThreadExample sau Applet;5. cream constructorul clasei MyThread care are ca parametru o clasa-aplet;6. in acest constructor apelam functia start() pentru a porni firul de executie;7. suprascriem functia run().Iata mai jos codul acestui exemplu:

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

public class ThreadExample extends Applet { //pasul 1  String displayStr;   Font font;

  public void init() { //pasul 2     font = new Font("TimesRoman", Font.PLAIN, 72);    setFont(font);     displayStr = "";     new MyThread(this);      }

  public void paint(Graphics g) {     g.drawString(displayStr, 50, 150);  }

}

class MyThread extends Thread { //pasul 3   ThreadExample applet; //pasul 4  int count;     MyThread(ThreadExample applet) { //pasul 5     this.applet = applet; start(); //pasul 6   }

  public void run() { //pasul 7    count = 0;     while (count < 100) {       ++count;      applet.displayStr = String.valueOf(count);      applet.repaint();       try {         sleep(100);       }      catch (InterruptedException e) {      }    }  }

}

Page 15: Appleturi Java

Nota1: Scrieti intreaga sursa de mai sus intr-un singur fisier. Puteti crea doua fisiere, cate unul pentru fiecare clasa, dar pentru aceasta trebuie sa mai adaugati in fisierul-aplet linia: import MyThread;si trebuie sa declarati clasa MyThread ca publica.Nota2: Se mai obisnuieste ca in clasa ThreadExample sa existe linia MyThread thread; (declararea unei variabile de tip MyThread). Astfel, apelul constructorului (pasul 2) va fi thread=new MyThread(this);. De asemenea metodele public void start() si public void stop() pot exista (la fel ca la prima metoda), dar nu este obligatoriu. Va recomand sa rulati totusi codul si intr-un fel si in altul, pentru a intelege mai bine functionarea firelor de executie in Java.

Este de remarcat urmatorul lucru: constructorul clasei MyThread are ca argument un obiect de tip ThreadExample, care este apletul de unde firul de executie va fi rulat. Acest lucru este necesar pentru ca firul sa poata comunica cu apletul.Apoi, priviti functia run(). Clasa-fir acceseaza acum obiectul de tip aplet pentru a-i transmite noua valoare a sirului si pentru a apela functia repaint(). In prima versiune, firul era asociat cu clasa-aplet, altfel spus facea parte din ea, iar acum este un proces complet separat.Acum aveti destule cunostinte despre firele de executie pentru a putea intelege sursa apletului pe care l-ati vazut ruland la inceputul articolului. Vom folosi a doua modalitate deoarece, asa cum va spuneam, la fiecare click se va genera un nou fir de executie, deci la un moment dat pot rula mai multe fire de executie, depinzand de cate click-uri au fost date in ultimul timp. Vom parcurge urmatorii pasi:1. cream clasa OvalThreadExample care mosteneste clasa Applet;2. declaram variabila Image offImage;3. declaram variabila Graphics offGraphics;Vom folosi aceste variabile pentru a evita licarirea ecranului in timpul animatiei. O animatie se realizeaza prin redesenarea cadrelor. Daca acest lucru se face direct pe ecran, se va produce o licarire a ecranului (puteti incerca!). Acest lucru poate fi inlaturat prin tehnica descrisa in urmatorii pasi:4. se creeaza o imagine (careia i se mai spune buffer si care la noi este variabila offImage) care contine imaginea curenta a apletului (sau numai o parte a suprafetei sale).5. se ia apoi contextul grafic al acestei imagini (in variabila offGraphics), care se adapteaza pentru fiecare cadru in parte;6. se apeleaza in metoda paint() functia drawImage (care este din clasa Graphics la fel ca si drawLine, drawOval etc.) avand ca parametru imaginea offImage.7. se scrie functia update(Graphics g). Aceasta functie este apelata automat la executia functiei repaint(). (repaint() apeleaza automat update si aceasta apeleaza paint. Pentru mai multe detalii cititi fisierul Component.java). Functia update va fi deci apelata cu noul context grafic, adica offGraphics, dupa ce acesta a fost modificat.Pasii 3-7 sunt folositi deci pentru a inlatura licarirea imaginii.8. se apeleaza functia public boolean mouseDown(Event e, int x, int y). Aceasta functie face urmatorul lucru: atunci cand se constata o apasare a butonului mouse-ului, se executa corpul acestei functii. x si y sunt coordonatele mouse-ului unde a avut loc evenimentul. Functia returneaza true daca s-a inregistrat evenimentul respectiv. Alte functii care reactioneaza la anumite evenimente mai sunt: mouseDrag, mouseEnter, mouseExit, mouseUp, cu aceiasi parametri. Ele sunt metode tot ale clasei Component. (Pentru exersarea acestor metode va propun urmatorul exercitiu: modificati apletul din episodul trecut: Triunghiul lui Sierpinski astfel incat cand utilizatorul da click undeva pe suprafata apletului, varful cel mai apropiat sa se deplaseze in acel punct. Astept sa-mi trimiteti prin mail raspunsul! :))9. in corpul metodei de la pasul 8 se scrie deci codul ce se va executa atunci cand se da un click, si anume se creeaza un nou fir, deci se apeleaza constructorul clasei-fir; 10. se creeaza clasa DrawTarget care mosteneste clasa Thread si care are acelasi rol ca si clasa MyThread din exemplul anterior.11. printre variabilele sale trebuie sa fie si una de tip Applet sau clasa-aplet;

Page 16: Appleturi Java

12. se scrie constructorul clasei DrawTarget, care ca avea ca parametri clasa Applet, coordonatele mouse-ului unde s-a dat click si contextul grafic care urmeaza sa fie modificat;13. in constructor se apeleaza si functia start() pentru pornirea firului de executie;14. se scrie functia run();15. in functia run() se seteaza culoarea de foreground pe alb pentru contexul offGraphics;16. se apeleaza functia setXORMode, care seteaza modul de desenare al acestui context grafic sa alterneze intre culoarea setata la pasul 15 (alb) si culoarea setata aici (rosu). (vezi clasa Graphics);17. in doua cicluri for realizeaza desenarea cercurilor in 8 pasi cand se maresc si tot 8 cand se micsoreaza;18. se apeleaza functia repaint() a apletului;

19. se opreste executia firului pentru 200 de milisecunde.

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

public class OvalThreadExample extends Applet { //pasul 1  Image offImage; //pasul 2  Graphics offGraphics; //pasul 3

public void init() {     offImage=createImage(size().width,size().height); //pasul 4;    offGraphics=offImage.getGraphics(); //pasul 5  }

  public void paint(Graphics g) {    g.drawImage(offImage,0,0,null); //pasul 6  }

  public void update(Graphics g) { //pasul 7    paint(g);  }

  public boolean mouseDown(Event e, int x, int y) { //pasul 8    new DrawTarget(this,x,y,offGraphics); //pasul 9    return true;  }

}

class DrawTarget extends Thread { //pasul 10  int xPos,yPos; //pozitia unde se vor desena cercurile  Applet applet; //pasul 11  Graphics offGraphics;

  public DrawTarget(Applet a, int x, int y, Graphics g) { //pasul 12    xPos=x;     yPos=y;

applet=a;     offGraphics=g;     start(); //pasul 13  }

Page 17: Appleturi Java

  public void run() { //pasul 14    int i;    int r;     offGraphics.setColor(Color.white); //pasul 15    offGraphics.setXORMode(Color.red); //pasul 16    for(r=0,i=10;i>-20;i-=20) // i=(10,-10) //pasul 17      for(r+=i;(r<90)&&(r>0);r+=i) { // r=(10,20...80,80,70...10)         offGraphics.fillOval(xPos-r,yPos-r,2*r,2*r);        applet.repaint(); //pasul 18        try {          sleep(200); //pasul 19        }        catch (InterruptedException e) {        }     }   }

}

Ei, de data aceasta nu a mai fost asa usor, nu-i asa? (m-am gandit ca ar fi bine sa incepeti anul cu mult avant, ca sa o tineti tot asa pana la sfarsitul lui... glumesc :)))Asupra tehnicii de buffering voi reveni cand voi mai prezenta apleturi cu animatii, pentru ca vom folosi acelasi procedeu, iar asupra firelor de executie voi reveni luna viitoare, cand vom intra mai amanuntit in sincronizarea firelor de executie.

Apleturi Java (IV): Exceptii

In episodul din numarul trecut v-am promis ca acum voi prezenta sincronizarea firelor de executie. Dar fiindca pentru aceasta voi folosi si exceptii, cu care v-ati mai intalnit, de altfel, si in episoadele trecute, m-am gandit sa lamuresc in acest numar ce sunt exceptiile si cum se trateaza ele, urmand ca in numarul urmator sa revin asupra sincronizarii firelor de executie.

In programare in general, indiferent de limbaj, pot aparea erori, fie din cauza ca programatorul nu a anticipat chiar toate situatiile care pot aparea, fie ca o conexiune de retea nu s-a realizat cu succes, fie ca un fisier din care se citesc niste date nu poate fi accesat etc. Cand spun "erori" ma refer la erorile care apar la momentul interpretarii, deci al executiei, nu la erorile are apar la compilare! In Java, aceste evenimente care pot cauza esuarea programului se numesc exceptii.Exceptiile nu apar pur si simplu, ele sunt "aruncate". Exceptiile pot fi aruncate de sistem sau de programator. Pentru a controla executia programului atunci cand apare o exceptie, aceasta trebuie "prinsa". Echivalentul expresiei "a aparut o eroare" in terminologia Java este "o exceptie a fost aruncata".Asadar Java arunca o exceptie ca raspuns la aparitia unei situatii neobisnuite. Programatorul poate fie sa arunce o exceptie, fie sa o prinda.Exceptiile in Java sunt de fapt niste obiecte, instante ale claselor care mostenesc clasa Throwable. Figura de mai jos arata o ierarhie partiala a exceptiilor:

Page 18: Appleturi Java

Clasa Throwable are doua subclase: Error si Exception. Instantele clasei Error sunt erorile interne ale masinii virtuale. Aceste erori sunt rare, dar de cele mai multe ori atunci cand apar, sunt fatale. Programatorul nu le poate influenta cu nimic (nu le poate prinde sau arunca), dar ele exista astfel incat Java sa le poata folosi daca are nevoie de ele.Felul in care programatorul poate influenta cursul programului in functie de erorile care apar este prin intermediul clasei Exception.Facand o clasificare a exceptiilor dupa modul in care programatorul este obligat sa le prinda sau nu, le putem imparti in doua categorii:I. Exceptii care nu trebuie prinse neaparat, adica Java permite

compilarea sursei fara prinderea lor. Acestea sunt generate de sistem atunci cand se intampla lucruri de genul: alocarea memoriei esueaza, se incearca o impartire la 0, o valoare nula este folosita necorespunzator etc. In cazul acestora, programatorul alege daca le trateaza sau nu.II. Exceptii care trebuie prinse neaparat, compilatorul dand eroare in cazul neprinderii lor.

I.In tabelul de mai jos am explicat cateva dintre cele mai intalnite exceptii din prima categorie:

Exceptii DescriereArithmeticException

Cauzata de erori matematice ca impartirea la zero

ArrayIndexOutOfBoundsException Cauzata de incercarea de alocare a unui element dintr-un vector in afara spatiului alocat

ArrayStoreException Apare cand un program incearca sa stocheze un tip de data necorespunzator intr-un vector (tablou)

FileNotFoundException Cauzata de incercarea de accesare a unui fisier inexistent

Exceptii DescriereIOException Cauzata de esecuri generale de input/output, ca esuarea de a citi dintr-un fisier

NullPointerException Cauzata de referirea unui obiect null

Page 19: Appleturi Java

NumberFormatException Apare atunci cand o conversie intre siruri si numere esueaza

OutOfMemoryException Apare cand nu este destula memorie necesara alocarii unui obiect

SecurityException Apare cand un aplet incearca sa execute o actiune care nu este permisa de setarile de securitate ale browserului

StackOverflowException Apare cand sistemul nu mai are loc pe stiva

StringIndexOutOfBoundsException Apare cand un program incearca sa acceseze un caracter dintr-un sir (String) a carui pozitie nu exista.

Urmatorul exemplu realizeaza impartirea a doua numere intregi introduse de utilizator. Rulati acest exemplu cu AppletViewer:

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

public class ExceptionApplet extends Applet {  TextField textField1 = new TextField();   TextField textField2 = new TextField();   String rezultat;

  public void init() {     setLayout(null);     textField1.reshape(30,30,50,20);    add(textField1);    textField2.reshape(100,30,50,20);     add(textField2);    rezultat = "Nedefinit";  }    public void paint(Graphics g) {    g.drawString(rezultat, 30, 100);  }

  public boolean action(Event evt, Object arg) {    String str1 = textField1.getText();     String str2 = textField2.getText();    int int1 = Integer.parseInt(str1);    int int2 = Integer.parseInt(str2); int answer = int1 / int2;    rezultat = String.valueOf(answer);    repaint();     return true;   } }

Mai intai sa analizam putin sursa de mai sus: - daca in metoda action nu se testeaza evt sau arg, atunci codul din aceasta functie se executa la apasarea tasei Enter;- linia int int1 = Integer.parseInt(str1); face conversia sirului str1 la int folosind functia parseInt a clasei java.lang.Integer care primeste ca parametru un sir de caractere si returneaza un int (sirul convertit la int);- linia rezultat = String.valueOf(answer); face conversia int-String; o alta modalitate, mai simpla, este urmatoarea: rezultat = "" + answer;- restul liniilor le cunoasteti din episodul din decembrie, acela cu Triunghiul lui Sierpinski.

Page 20: Appleturi Java

Daca introduceti in campurile de text numere intregi obisnuite, atunci apletul functioneaza bine. Dar ce se intampla daca introduceti in loc de numere cateva litere, sau orice altceva care nu este numar intreg? Pe fereastra tip DOS a lui AppletViewer va aparea o eroare, si anume: java.lang.NumberFormatException. De asemenea, daca introduceti in al doilea camp valoarea 0, va aparea alta eroare, si anume: java.lang.ArithmeticException. Iata cum putem prinde aceste exceptii: urmand pasii urmatori:1. Identificam liniile de cod care ar putea cauza exceptia: in cazul nostru aceste linii sunt acelea din metoda action care fac conversia textului introdus in int si calculeaza sirul de transmis ca rezultat:    int int1 = Integer.parseInt(str1);    int int2 = Integer.parseInt(str2);    int answer = int1 / int2;    rezultat = String.valueOf(answer);2. Plasam aceste linii intr-un bloc try {//liniile de cod identificate la pasul 1}3. In continuarea blocului try scriem atatea blocuri catch cate exceptii vrem sa prindem, iar ca parametru la fiecare bloc catch trecem tipul exceptiei de prins;4. in corpul instructiunii catch scriem liniile de cod care se vor executa in cazul ca exceptia respectiva a aparut.Asadar inlocuiti metoda action de mai sus cu urmatoarea:

  public boolean action(Event evt, Object arg) {    String str1 = textField1.getText();     String str2 = textField2.getText();    try {       int int1 = Integer.parseInt(str1);      int int2 = Integer.parseInt(str2);      int answer = int1 / int2;      rezultat = String.valueOf(answer);    }    catch (NumberFormatException e) {        rezultat = "Numar prost!";}     catch (ArithmeticException e) {        rezultat = "Impartire la 0!";      }     repaint();     return true;   }

Acum exceptiile sunt prinse si sunt tratate ca atare.

Exista cazuri insa cand apar exceptii care nu trebuiesc prinse, ci rezolvate in alt fel.Sa luam un mic exemplu care incearca sa afiseze un buton:

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

public class mic extends Applet {   Button buton;

  public void init() {    buton.setLabel("Buton");

Page 21: Appleturi Java

    add(buton);  }}

Daca rulati acest aplet, nu o sa va dea eroare la compilare, dar pe fereastra AppletViewer va scrie java.lang.NullPointerException si nici nu va rula nimic. Aceasta eroare a aparut din cauza faptului ca in metoda init se apeleaza functia setLabel a instantei buton care nu a fost initializata (creata). Prin urmare trebuie sa rezolvati eroarea prin initializarea obiectului: Button buton = new Button();Atentie! Toate obiectele trebuiesc create prin apelul unui constructor al clasei respective! Exceptie de la aceasta regula il fac obiectele care instantiaza o clasa abstracta (care nici nu are constructori). Aceste obiecte sunt de obicei create prin apeluri de functii (voi reveni). Daca un obiect al unei clase care nu este abstracta nu este creat apeland un constructor, interpretorul va da intotdeauna exceptia NullPointerException si nu va rula programul!

II. Haideti sa vedem cum si cand prindem exceptiile pe care le-am clasat in categoria a doua si care trebuiesc prinse obligatoriu.In exemplul cu firele de executie de luna trecuta ne-am intalnit cu urmatoarea secventa de instructiuni:  try {     thread.sleep(100);   }  catch (InterruptedException e) {  } Daca in loc de aceste linii scriam doar thread.sleep(100); atunci ne dadea eroare la compilare. De ce? Pentru ca metoda sleep a clasei Thread este declarata astfel:public static native void sleep(long millis) throws InterruptedException Cuvintele throws InterruptedException spun compilatorului ca aceasta metoda poate arunca exceptia specificata si de aceea ea trebuie neaparat prinsa. Apoi in corpul functiei sleep exista o linie de genul if(conditie) throw new Exceptie(); adica aceasta exceptie este aruncata atunci cand este intalnita conditia.Bineinteles ca in corpul catch trebuie scris codul care se va executa atunci cand are loc exceptia respectiva. Dar chiar daca nu avem ceva anume de executat, blocul try-catch trebuie scris in toate cazurile din aceasta categorie.Atentie! Cuvantul cheie try nu are sens fara cuvantul catch si nici catch fara try; ele merg intotdeauna impreuna! (este ca in cazul switch - case).

Iata un exemplu in care vom crea propriile noastre exceptii. Exemplul creeaza o stiva la care utilizatorul poate adauga sau scoate elemente prin apasarea unor butoane: Push pentru a adauga, Pop pentru a scoate. Stiva are o capacitate maxima data prin program (la noi 10). Atunci cand stiva se umple este aruncata o exceptie, cand este goala, este aruncata alta exceptie. Urmam pasii:Pas 1. Cream doua clase care mostenesc clasa Exception pentru a arunca exceptii in caz de stiva plina si goala;Pas 2. Cream clasa TestStack pentru stiva;Pas 3. Definim constructorul clasei TestStack pe care il vom apela din aplet;Pas 4. Definim metoda push care adauga elemente in stiva si arunca exceptia StackFullException;Pas 5. In metoda push, daca stiva este plina, este creata si aruncata o noua exceptie, dupa care cuvantul throw determina si iesirea din metoda;Pas 6. La fel, metoda pop scoate elemente din stiva si daca stiva este goala, arunca exceptia StackEmptyException.Pas 7. Metoda draw deseneaza stiva.import java.applet.*;import java.awt.*;

Page 22: Appleturi Java

class StackFullException extends Exception { } //pas 1class StackEmptyException extends Exception { } //pas 1

class TestStack { //pas 2  Applet parent; //apletul parinte  int capacitate; //capacitatea maxima a stivei  int top; //varful curent al stivei

  public TestStack(Applet p,int cap) { //pas 3    parent=p;     capacitate=cap;    top = -1; //initial stiva este goala  }

  public void push() throws StackFullException { //pas 4    if (top+1 == capacitate) throw new StackFullException(); //pas 5    top++;  }

  public void pop() throws StackEmptyException { //pas 6    if (top < 0) throw new stackemptyexception();top--;  }

  public void draw(Graphics g) { //pas 7    g.setColor(Color.blue);    for (int i = 0; i <= top; ++i) {      int latime = (capacitate-i)*20;       g.fill3DRect((parent.size().width- latime)/2,parent.size().height-70- i*20,latime,20,true);    }   }

}

Si iata si clasa care mosteneste Applet, care parcurge urmatorii pasi:Pas 1. Creeaza butoanele Push si Pop si declara obiectul stack de tip TestStack;Pas 2. In functia init cream o noua instanta a clasei mai sus descrise TestStack;Pas 3. In metoda paint apelam functia draw a obiectului stack;Pas 4. In metoda action: daca se apasa butonul Push, se apeleaza metoda push a obiectului stack folosind blocul try-catch. La prinderea exceptiei, se afiseaza pe fereastra AppletViewer un mesaj. Daca se apasa butonul Pop se apeleaza metoda pop, iar la prinderea exceptiei se afiseaza alt mesaj.

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

public class StackApplet extends Applet {   TestStack stack; //pas 1  Button pushButton = new Button(); //pas 1  Button popButton = new Button(); //pas 1

 public void init() {   setLayout(null);   pushButton.setLabel("Push");   pushButton.reshape((size().width-110)/2,size().height-25,50,20);

Page 23: Appleturi Java

   add(pushButton);   popButton.setLabel("Pop");    popButton.reshape((size().width-110)/2+60,size().height-25,50,20); add(popButton);    stack = new TestStack(this,10); //pas 2 } 

 public void paint(Graphics g) {    stack.draw(g); //pas 3 }

 public boolean action(Event evt, Object arg) {   if(evt.target instanceof Button)     if(arg=="Push") //pas 4       try {          stack.push();         repaint();        }       catch (StackFullException e) { System.out.println("Stiva plina!");       }      else if(arg=="Pop") //pas 4       try {          stack.pop();          repaint();       }        catch(StackEmptyException e) {         System.out.println("Stiva goala!");       }   return true; }

}

Appleturi Java V: Ferestre si meniuri

          In episodul de astazi veti invata cum sa creati ferestre, meniuri, cutii de dialog etc. intr-un applet Java. Si in Java exista functii specializate pentru a crea astfel de obiecte, sau elemente API, ca in orice limbaj de programare sau mediu de programare vizual (Delphi, Visual C, Visual Basic etc.). Daca ati urmarit episoadele despre Java din numerele trecute, inseamna ca stiti deja in ce pachet (package) se afla clasele care creeaza astfel de obiecte vizuale: in pachetul java.awt.

Clasele Window si Frame           Clasa Window se foloseste pentru a crea ferestre care pot aparea in afara spatiului alocat pentru applet din cadrul browserului. Clasa Window mosteneste clasa Container si astfel poate contine si alte componente. Spre deosebire de un aplet care este legat in mod direct de pagina browserului, ferestrele create cu clasa Window nu sunt restrictionate la o suprafata specificata din ecran. Obiectele de tip Window astfel create pot fi redimensionate dupa dorinta utilizatorului. Acest lucru se realizeaza cu ajutorul metodei pack(), care este apelata inainte ca fereastra respectiva sa fie afisata. Pentru ca ea sa fie apoi vizibila, trebuie apelata metoda show(). Fereastra va fi stearsa de pe ecran si din memoria calculatorului la invocarea metodei dispose().           Clasa Frame extinde clasa Window prin adaugarea unei bare de titlu, unei margini pentru redimensionare, suport pentru meniu si abilitatea de a modifica forma cursorului mouse-ului.           Felul cum va arata fereastra respectiva depinde de platforma GUI (Graphical User Interface) deoarece va imprumuta din sistem butoanele de tip minimize, maximize, restore sau close.

Page 24: Appleturi Java

          Dupa cum vedeti, clasa Frame are tot ce ii trebuie pentru a face un applet sa arate ca o adevarata aplicatie, cu meniuri si bara de titlu cu butoane de control Clasele de formare a meniurilor           Clasa Frame si clasele prin care se construiesc meniurile sunt intr-o stransa legatura deoarece clasa Frame este singura clasa din pachetul awt care are suport pentru meniuri.           Primul pas este crearea unui obiect de tip MenuBar. Acest obiect este legat de obiectul de tip Frame cu ajutorul metodei setMenuBar() a clasei Frame.           Al doilea pas este adaugarea de meniuri individuale obiectului MenuBar creat anterior. Aceste meniuri individuale sunt obiecte ale clasei Menu. Constructorul clasei Menu primeste ca parametru textul care va fi asociat meniului respectiv. Meniurile astfel create vor fi adaugate obiectului de tip MenuBar prin metoda acestei din urma clase, add(). Metoda remove() poate fi folosita pentru a sterge un obiect Menu dintr-un MenuBar.           Ultimul pas in crearea meniurilor este crearea meniurilor "atom" individuale cu ajutorul clasei MenuItem. Aceasta clasa este o subclasa a clasei MenuComponent si furnizeaza operatii suplimentare pentru obiectele "atom", de exemplu de a activa sau dezactiva o optiune. Constructorul clasei MenuItem va primi ca parametru textul care va fi afisat pentru atomul respectiv. Metoda add() a clasei Menu este folosita pentru a adauga unui meniu submeniuri. Un atom poate fi sters prin metoda remove(), asa cum este si in cazul clasei MenuBar. Un separator care sa desparta doua grupuri de atomi poate fi adaugat cu metoda addSeparator() a clasei Menu. Acesta este folositor pentru meniuri care au categorii diferite de optiuni.

Clasa Dialog           Ca si clasa Frame, clasa Dialog este o subclasa a clasei Window. Diferenta cea mai importanta dintre Dialog si Frame este ca un obiect Dialog poate fi modal. Acest lucru inseamna ca atunci cand un obiect Dialog modal este afisat, alte ferestre ale apletului nu pot fi editate pana cand obiectul Dialog respectiv nu este eliberat. Acest lucru este folosit atunci cand se doreste informarea utilizatorului cu un mesaj de avertisment sau se cere o decizie fara de care programul nu poate continua.           Clasa Dialog are doi constructori: ambii iau ca parametru un obiect de tip Frame, adica fereastra parinte, si un parametru de tip boolean. Daca acesta este true, fereastra va fi de tip modal, daca nu, nu. Unul dintre constructori mai are un parametru care specifica titlul ferestrei.           Sa luam acum un exemplu, si anume un applet care construieste o fereastra cu o bara de meniu. Pentru aceasta parcurgem urmatorii pasi:

1. Cream clasa FrameMenuApplet care mosteneste clasa Applet si care contine un buton la apasarea caruia se va deschide o fereastra;

2. Cream clasa FrameMenu careia ii asociem o bara de meniuri cu mai multe meniuri (constructorul);

3. In clasa FrameMenu cream functia handleEvent(Event e), cu ajutorul careia vom seta actiunile aferente fiecarei optiuni selectate din meniu. Clasa Event are variabila id, care indica ce tip de eveniment a fost selectat. Astfel, daca a fost apasat butonul de close din coltul din dreapta sus al ferestrei, variabila id are valoarea WINDOW_DESTROY. Aceasta este o componenta a clasei Event declarata astfel: public static final int WINDOW_DESTROY. Altele de acest tip sunt:ACTION_EVENT (un eveniment a aparut), DELETE ( tasta Delete a fost apasata ), DOWN, UP, ENTER, ESCAPE, MOUSE_ENTER, MOUSE_EXIT, MOUSE_MOVE, WINDOW_ICONIFY, WINDOW_MOVED etc. Pentru alte detalii cititi sursa clasa Event.

import java.awt.*;import java.lang.*;import java.applet.*;

public class FrameMenuApplet extends Applet { Button button;

public void init() { setBackground(Color.white);

Page 25: Appleturi Java

button = new Button("Deschide fereastra!"); add(button); }

public boolean action(Event evt, Object arg) { new FrameMenu("Fereastra cu meniu"); return true; }}

class FrameMenu extends Frame { public FrameMenu(String title) { super(title); MenuBar mbar = new MenuBar(); setMenuBar(mbar); Menu menu1 = new Menu("Fisier"); Menu menu2 = new Menu("Culoare fundal"); Menu menu3 = new Menu("Cursoare"); mbar.add(menu1); mbar.add(menu2); mbar.add(menu3); menu1.add(new MenuItem("Iesire"));

menu2.add(new MenuItem("Alb")); menu2.add(new MenuItem("Galben")); menu2.add(new MenuItem("Portocaliu")); menu2.add(new MenuItem("Rosu"));

menu2.addSeparator(); menu2.add(new MenuItem("Albastru")); menu2.add(new MenuItem("Verde")); menu2.add(new MenuItem("Negru"));

menu3.add(new MenuItem("Implicit")); menu3.add(new MenuItem("Wait")); menu3.add(new MenuItem("Hand")); menu3.add(new MenuItem("Move")); menu3.add(new MenuItem("Text")); menu3.add(new MenuItem("SE Resize"));

pack(); resize(300,200); show(); }

public boolean handleEvent(Event e) { switch(e.id) { case e.WINDOW_DESTROY: dispose(); return true; case e.ACTION_EVENT: if (e.target instanceof MenuItem) { String menuName = e.arg.toString(); if (menuName.equals("Iesire")) dispose(); if (menuName.equals("Alb"))

Page 26: Appleturi Java

setBackground(Color.white); if (menuName.equals("Galben")) setBackground(Color.yellow); if (menuName.equals("Portocaliu")) setBackground(Color.orange); if (menuName.equals("Rosu")) setBackground(Color.red); if (menuName.equals("Albastru")) setBackground(Color.blue); if (menuName.equals("Verde")) setBackground(Color.green); if (menuName.equals("Negru")) setBackground(Color.black);

if (menuName.equals("Implicit")) setCursor(Frame.DEFAULT_CURSOR); if (menuName.equals("Wait")) setCursor(Frame.WAIT_CURSOR); if (menuName.equals("Hand")) setCursor(Frame.HAND_CURSOR); if (menuName.equals("Move")) setCursor(Frame.MOVE_CURSOR); if (menuName.equals("Text")) setCursor(Frame.TEXT_CURSOR); if (menuName.equals("SE Resize")) setCursor(Frame.SE_RESIZE_CURSOR); return true; } // end if return true; default: return false; } }}