Corso di programmazione Java (C) by Fabio Ciucci PARTE 2: LA CLASSE GRAPHICS, LE APPLET E L'AWT Fino ad ora abbiamo visto la logica di funzionamento e la sintassi del linguaggio Java, in altre parole si e' imparato a parlare questo linguaggio come lo parla un bambino: correttamente, ma senza conoscere le parole piu' raffinate e ricercate. Un bambino non conosce il significato di parole come dermatologia, perpendicolare, sinergico; d'altronde e' in grado di intendere tutte le frasi contenenti le poche parole che conosce. In java con le conoscenze della scorsa lezione si riesce a fare una qualsiasi applicazione in modo testo che legga dati, li elabori e dia un output. Pero' se si volesse disegnare un rettangolo rosso, o una interfaccia utente con dei bottoni, magari utilizzabile anche in una pagina web, incontreremmo le sconosciute parole "dermatologia, perpendicolare, sinergico". Ebbene, la cosa piu' importante e' quella di aver compreso la logica di base del Java, il resto e' solo un progressivo imparare nuovi metodi per fare le cose piu' disparate In questa lezione vedremo i concetti basilari di Applet, Graphics e AWT, ma non sara' una trattazione approfondita. L'importante per ora e' avere una visione chiara e globale del sistema grafico e interattivo di java. In lezioni future ogni singolo aspetto sara' approfondito, ma e' inutile approfondire qualcosa prima di conoscere a grandi linee awt, graphics e applet. -------------------------------------------------------------------------- APPLET -------------------------------------------------------------------------- Come gia' detto in precedenza, le applicazioni sono programmi autonomi eseguibili con "java.exe" o comunque con l'interprete java disponibile sul proprio sistema, mentre le Applet sono programmi che devono essere eseguiti in una pagina html da un browser web Java enabled. Per ora abbiamo visto solo applicazioni, distinguibili per la presenza del metodo main(), (o meglio per l'assenza di "extends Applet"), che NON possono essere attaccate ad una pagina web. Allo stesso modo, una Applet (distinguibile per il fatto che la classe principale estende la classe Applet, ovvero e' una sua figlia-derivata), non puo' essere eseguita fuori dal web browser. E' possibile pero' fare un'applet che sia anche una applicazione, basta che sia presente il main() e che contemporaneamente la classe sia derivata da Applet: in tal caso avremo una classe "attaccabile" ad una pagina web html ed eseguibile eventualmente anche come applicazione autonoma. Per scopi didattici, e per una mia preferenza, faremo quest'ultimo tipo di programmi java, "omnieseguibili". Ma allora, direte voi, il comportamento dei programmi e' sempre uguale, sia che siano eseguiti come applet che come applicazioni? Naturalmente no, altrimenti non sarebbe stata necessaria questa separazione. Le applet, essendo distribuite sulle pagine web di internet, sono molto pericolose, perche' scaricate ed eseguite su milioni di computer senza poterle controllare. Di conseguenza la Sun ha cercato di disabilitare tutte quelle funzionalita' adatte alla creazione di virus o "trojan", ossia applicazioni che "sembra" facciano una cosa, ma invece quando eseguite nel nostro computer fanno danni (da qui l'attinenza con il cavallo di troia). Le cose piu' importanti che le applet NON possono fare sono: 1) Leggere e soprattutto SCRIVERE nel computer dell'utente, a meno che quest'ultimo non specifichi (poco prudentemente) delle directory in cui le applet possono accedere. Comunque i browser normalmente non concedono l'accesso a nessuna directory e non si puo' sperare che gli utenti l'abbiamo abilitato. Tra le altre cose NON puo' eseguire programmi sul computer degli utenti (ad esempio far partire il comando "format C:" o "delete *.*", cosa poco educata). 2) Comunicare con server diversi da quello in cui e' stata scaricata l'applet stessa: con le funzioni di rete e' possibile stabilire un contatto tra un'applet ed il server su cui e' stata scaricata, per scambiare dati, ma non con altri server nella rete. Se l'applet e' in una pagina di www.baubau.com, essa non potra' comunicare con altri server. Quindi un virus come Applet non potrebbe fare danni, mentre come applicazione avrebbe possibilita' di rovinarci l'esistenza. In questa lezione opereremo soltanto nel campo delle interfacce grafiche, quindi non ci saranno differenze tra esecuzione come applet o appliczioni. Vediamo quindi come "applettizzare" una applicazione. Innanzitutto occorre fare in modo che la classe principale sia una figlia derivata da Applet: import java.applet.Applet // Importo Applet public class miaClasse extends Applet { // Questa e' un'applet ... } A questo punto si possono definire dei metodi fondamentali dell'applet: public void init() { ... } // Metodo in cui si definiscono le operazioni // da eseguire come inizializzazione quando // un applet viene caricato. public void start() { ... } // Avvio (o riavvio) dell'applet public void stop() { ... } // Arresto dell'applet Quando un'applet viene attivata viene eseguito init(), poi start(), che pero' puo' essere richiamato ogni volta che l'applet "riparte" dopo una qualche pausa (se per esempio si era chiamato stop o si era visualizzata un'altra pagina, poi si torna indietro). Le istruzioni presenti in start() e stop() dunque sono eseguite quando la pagina html contenente l'applet e' attivata o disattivata. Vedremo che sono metodi molto usati per la gestione dei thread, infatti quando un'applet che esegue continuamente istruzioni (come un'animazione) non e' piu' visibile, perche' l'utente e' passato ad un'altra pagina, occorre fermare le operazioni, divenute inutili: cio' si fa scrivendo le routine di "ferma tutto" nel metodo stop(). Naturalmente se l'utente torna indietro col browser e l'applet torna visibile, viene rieseguito start(), in cui risiederanno le routine di riabilitazione complementari a stop(). Se non si devono eseguire particolari istruzioni all'inizializzazione e all'avvio(start)/disattivazione(stop), questi metodi si possono omettere. Un altro metodo "particolare" e' il paint(), che fa parte della classe Graphics, la quale si occupa di cio' che viene disegnato nell'Applet: import java.awt.Graphics; // Occorre importare la classe Graphics public void paint(Graphics g) { ... } Come si vede al paint() viene passato un parametro "g" di tipo Graphics, che non e' altro che l'area dell'applet su cui disegneremo tramite i metodi della classe Graphics (che trattiamo piu' avanti in questa lezione). Il paint() viene eseguito all'inizio, ma anche tutte le volte che l'area dell'applet viene spostata, coperta con un'altra finestra e poi riscoperta, eccetera, ossia quando occorre ridisegnarla, tutta o in parte. Giusto per testare la nostra applet, introduciamo il metodo drawString() della classe Graphics, che serve a stampare stringhe di testo (tipo il println, ma per aree grafiche). L'applet e' questa: import java.applet.*; import java.awt.*; public class MiaApplet1 extends Applet { public void paint(Graphics g) { // l'oggetto g e' l'area dell'applet // Ora abbiamo l'oggetto g di tipo Graphics che e' l'area dell'applet, su // cui possiamo scrivere, tramite il metodo drawString(), ad esempio: g.drawString("Salute a tutti.", 50, 50); // Stampa in x=50, y=50 } } // Fine classe MiaApplet1 Una volta compilato questo sorgente abbiamo la classe, che pero' dovra' essere attaccata ad una pagina html, mettendo un riferimento all'applet. Da notare la mancanza del metodo main(), per cui non si puo' eseguire come applicazione, otterremmo solo un messaggio di errore. Qua si suppone che si conosca almeno la struttura minima di una pagina html. In una pagina html per far riferimento ad un'applet esiste un tag apposito, che funziona analogamente agli altri tag per caricare immagini: Spiacente, il browser non supporta il Java Come si vede, dentro si ha l'attributo CODE per specificare il nome della classe, e i parametri obbligatori WIDTH (larghezza) e HEIGHT (altezza), che se non ridefiniti dall'applet devono essere immessi secondo le esigenze ben precise dell'applet stessa. E' possibile usare anche i parametri ALIGN, VSPACE e HSPACE che funzionano come definito dall'html per altri elementi come IMG. Se il .class non e' nella stessa directory dell'html, occorre specificare il path (eventualmente comprendente anche l'URL) con il tag CODEBASE. Il testo "Spiacente, ...", tra e viene visualizzato solo sui browser che non supportano il java, per cui si possono mettere messaggi di avvertimento per chi non puo' vedere la nostra applet, magari invitandoli a munirsi di un browser java enabled. Ora possiamo provare l'applet caricando con appletviewer (o con un browser java enabled) MiaApplet1.html, naturalmente dopo aver generato il MiaApplet1.class compilando MiaApplet1.java. Attenzione, dovete scrivere "AppletViewer MiaApplet1.html", esattamente. Dal menu "applet" di appletviewer potete notare, selezionando la voce "tag", i parametri del tag , ma senza il testo da visualizzare in caso di browser non java enabled o il resto dell'html, in quanto questa utility serve a vedere le sole applet, non l'intera pagina html. In realta' MiaApplet1.java puo' essere eseguito anche come applicazione, perche' gli ho aggiunto anche il metodo main. Nel caso venga eseguita come applicazione, il main deve fare "manualmente" cio' che l'applet fa automaticamente; innanzitutto si deve creare il frame grafico e istanziare l'applet (con il metodo paint) che dovra' poi operare sul frame stesso: Frame AppFram = new Frame("MiaApplet1"); // Creo un frame grafico // inizialmente invisibile, // e lo chiamo MiaApplet1. MiaApplet1 MiaAppIst = new MiaApplet1(); // Istanzio l'applet AppFram.add("Center", MiaAppIst); // Attacca l'applet al centro del // frame. Vedrete meglio il metodo add() nella parte sull'AWT. A questo punto si devono eseguire gli eventuali metodi init() e start(), che non sono eseguiti automaticamente in questo caso. In questa applet non li abbiamo, comunque mettiamoli disabilitati (con //) per usi futuri. Non dibbiamo dimenticarci nemmeno che ci manca l'html, in cui abbiamo specificato altezza e larghezza dell'applet... anche in questo caso dovremo farlo a mano con resize(), infine il frame dovra' essere visualizzato esplicitamente con show(): AppFram.resize(160, 100); // Ridimensiono (non ho WIDTH di html!) AppFram.show(); // Visualizza il frame, ora che e' OK. Un'ultimo problema e' che la finestra dell'applicazione non si riesce a chiudere con il gadget apposito... e' "inchiudibile", a differenza di un'applet, dove basta chiudere l'appletviewer o il browser. Per implementare la chiusura, occorrerebbe gestire l'evento WINDOW_DESTROY, che pero' non funzionerebbe se non creando una classe derivata da Frame appositamente per la visualizzazione come applicazione, e cio' complica le cose inutilmente. Tra l'altro gli eventi li vediamo meglio dopo. Quindi il sistema piu' adatto in questo momento e' l'uscita tramite la pressione del tasto Fine (sopra i cursori) o del tasto q (minuscolo): public boolean keyDown(Event evento, int tasto) { if(tasto == Event.END) System.exit(0); // Tasto Fine premuto = esci if(tasto == 113) System.exit(0); // tasto q (ascii 113) = esci return true; } Da notare che nell'esecuzione come Applet questo causa un'eccezione di sicurezza, quindi e' utile solo nel caso di esecuzione come applicazione. La gestione degli eventi sara' trattata in particolare piu' avanti. Vediamo il listato nella sua totalita': import java.applet.*; import java.awt.*; public class MiaApplet1 extends Applet { // Il main() viene chiamato quando eseguiamo come applicazione con java.exe public static void main(String args[]) { Frame AppFram = new Frame("MiaApplet1"); // Creo un frame grafico // inizialmente invisibile, // e lo chiamo MiaApplet1. MiaApplet1 MiaAppIst = new MiaApplet1(); // Istanzio l'applet // MiaAppIst.init(); // Se esiste init() eseguilo... // MiaAppIst.start(); // Se esiste start() eseguilo... AppFram.add("Center", MiaAppIst); // Attacca l'applet al centro del // frame. AppFram.resize(160, 100); // Ridimensiono (non ho WIDTH di html!) AppFram.show(); // Visualizza il frame, ora che e' OK. } // Il paint(), che lavorera' o sull'applet o sull'applicazione. public void paint(Graphics g) { // l'oggetto g e' l'area dell'applet g.drawString("Salute a tutti.", 50, 50); // Stampa in x=50, y=50 } // Questo permette l'uscita col tasto end (fine) o col q, ed e' utile // in quanto l'esecuzione come applicazione non fa uscire clickando il // gadget di chiusura della finestra. public boolean keyDown(Event evento, int tasto) { if(tasto == Event.END) System.exit(0); // Tasto Fine premuto = esci if(tasto == 113) System.exit(0); // tasto q (ascii 113) = esci return false; } } // Fine classe MiaApplet1 Provate quindi a caricarla come applicazione, con "java MiaApplet1". Tornando alle applet, una delle loro caratteristiche peculiari e' quella di accettare parametri da noi "inventati", passati tramite l'html. Per esempio, se volessimo modificare l'applet che abbiamo visto in modo che stampi un testo da noi indicato nell'html, si potrebbe stabilire un parametro "testopri": Spiacente, il browser non supporta il Java Si possono passare anche piu' parametri, basta aggiungerli. Per leggere i parametri durante l'esecuzione dell'applet, solitamente nel metodo init(), si usa il metodo getParameter(), a cui si deve passare la stringa contenente il nome del parametro (nel nostro caso "testopri"), in modo che ci restituisca il suo valore, sempre come stringa. Se si verifica un errore, restituisce "null", quindi si puo' controllare con un if ed eventualmente segnalare l'errore: Miotesto = getParameter("testopri"); if(Miotesto == null) Miotesto = "Errore nel getParameter!"; I parametri dell'html sono come gli argomenti della linea di comando di una applicazione. A proposito: quando eseguiamo questa applet come applicazione non si possono leggere i parametri dall'html! In questo caso, potremmo leggere gli argomenti della linea di comando, e ignorare il getParameter(). Comunque complicheremmo le cose senza spiegare niente di nuovo. Quindi MiaApplet2.class puo' essere eseguita solo come Applet, leggendo MiaApplet2.html con il browser o l'appletviewer. E' una applet "pura", quindi. -------------------------------------------------------------------------- GRAPHICS -------------------------------------------------------------------------- La classe Graphics e' nel package AWT, e per poterla usare occorre importarla mettendo all'inizio del sorgente: import java.awt.Graphics; I metodi di questa classe si basano sulle coordinate dell'area grafica dell'applet o dell'applicazione: il punto 0,0 e' l'angolo in alto a sinistra: la X aumenta verso destra e la Y verso il basso: 0,0 -----------> x,0 | | P. (x,y) | \_/ 0,y Da notare che i valori delle coordinate sono interi, dato che i pixel, cioe' i puntini che compongono i disegni sullo schermo, sono un numero ben determinato (500x400, 200,200 etc.) e non si puo' disegnare tra un pixel e l'altro. L'origine 0,0 come specificato non e' l'angolo in alto a sinistra dello schermo, ma l'angolo dell'applet/applicazione, attenzione! I piu' matematici avranno notato che questo sistema di riferimento ha le Y rovesciate rispetto a cio' che insegnano a scuola, quindi fate attenzione a non sbagliarvi: se la Y cresce, si va verso il basso. Non ci resta che vedere i metodi piu' importanti per disegnare le cosiddette "primitive grafiche": linee, rettangoli, circonferenze, ecc. prima tra tutte pero' la gestione del testo. Abbiamo visto il metodo drawString(String, int x, int y), che stampa un testo. Pero' se vogliamo cambiare la dimensione, il tipo e lo stile del carattere, serve la classe Font, con cui si istanziano oggetti adatti al metodo setFont() di Graphics. Ad esempio: Font carolina = new Font("TimesRoman", Font.PLAIN, 24); g.setFont(carolina); // Ora il font e' carolina g.drawString("Stampo con un mio font", 10, 30); In questo caso ho definito il font "carolina" che sara' di tipo TimesRoman, larghezza corpo 24, nessun modificatore. Se avessi messo Font.BOLD o Font.ITALIC avrei ottenuto il grassetto o il corsivo, ad esempio. Vediamo i parametri possibili di Font(): - Nome del font, ad esempio "Courier", "Helvetica", "TimesRoman". Attenzione a non usare font "insoliti", perche' se non sono presenti sulla macchina che esegue l'applet sara' usato un font di default. - Stile, che puo' essere Font.PLAIN (normale), Font.BOLD (grassetto), Font.ITALIC (corsivo). Si possono anche sommare piu' stili, basta considerarli come numeri (cosa che sono in realta'): ad esempio un Font.BOLD + Font.ITALIC crea uno stile grassetto corsivo. - Corpo: la dimensione del carattere, ad esempio 8, 12, 24, 48, 72... Chi ha un minimo di esperienza con i word processor non dovrebbe trovare problemi con Font(). >>>> Vediamo un esempio in VariFont.class/html. NOTA: con .class/html da qua in avanti indichero' che siccome l'applet e' anche eseguibile come applicazione, grazie al metodo main(), l'esempio potra' essere visto sia come applet, leggendo xxxxx.html tramite un browser o l'appletviewer, che come applicazione, con "java xxxxx.class". Naturalmente e' presente solo xxxxx.java, che dovra' essere prima compilato. Dato che si stampano anche font molto alti, occorre specificare che le coordinate x,y di drawString() non si riferiscono all'angolo in alto a sinistra del primo carattere, bensi' all'angolo in basso a sinistra. Vediamo ora le primitive grafiche, sinteticamente: drawLine(x1,y1, x2,y2) ; Disegna una linea dal punto x1,y1 al punto ; x2,y2. Si usa anche per disegnare punti, ; specificando lo stesso punto di partenza e ; di arrivo: non esiste un drawPoint(). drawRect(x1,y1, width,height) ; Disegna un rettangolo il cui angolo in alto ; a sinistra e' x1,y1, di larghezza e ; altezza width, height. fillRect(x1,y1, width,height) ; come sopra, ma il rettangolo e' riempito. drawRoundRect(x1,y1, width,height, curvx, curvy) ; come sopra... ; ma il rettangolo ha gli angoli smussati ; secondo curvx e curvy. ; Esiste fillRoundRect(). drawOval(x1,y1, width,height) ; Disegna un ovale (o un cerchio) fillOval(x1,y1, width,height) ; Disegna un ovale riempito drawArc(x1,y1, width,height, startAngle, SweepAngle) ; Disegna un arco... ; ... idealmente incluso nel rettangolo 90 ; definito dai primi 4 parametri, con | ; startAngle come angolo di partenza 180 --o-- 0 ; (attenzione che 0 gradi = le 3 per le | ; langette di orologio, 90 gradi = le 12, 270 ; e cosi' via proseguenzo in senso ; antiorario). fillArc(x1,y1, width,height) ; Disegna un arco riempito (tipo una torta ; con uno spicchio mancante, dato che il ; riempimento dagli apici dell'apertura ; converge verso il centro). >>>> Vediamo un esempio in VariGfx1.class/html. Esistono anche draw3DRect(x1,y1, width,height, orientamento) e il relativo fill3DRect(), che disegnano dei rettangoli che sembrano "rialzati": draw3DRect(x1,y1, width,height, orientamento) ; L'orientamento e' un... ; booleano (true o false) che determina ; se deve essere sporgente o rientrante. fill3DRect(x1,y1, width,height, orientamento) ; Come sopra, ma riempito. >>>> Vediamo un esempio in d3DRect.class/html. Una primitiva piu' complessa e' il poligono, che e' una figura (aperta o chiusa) formata da una linea a zig-zag, o meglio da una serie di punti uniti tra loro, che possono formare stelle, esagoni, o figure qualsiasi, basta dare le coordinate dei vari punti da unire, come quei giochetti sui giornali di enigmistica in cui si devono tracciare linee tra i punti seguendo l'ordine. Il comando drawPolygon() vuole la lista dei punti x,y in questo formato: un array coordsX[] con la lista dei punti X, e un array coordsY[] con la lista dei punti Y. Quindi coordsX[0] e coordYs[0] sono le coordinate x,y del primo punto, fino all'ultimo punto (naturalmente che i due array avranno lo stesso numero di elementi!). Come terzo parametro drawPolygon() richiede il numero di punti del poligono, che sara' uguale al numero di elementi di uno dei due array, quindi si puo' ottenere con coordsX.length o con coordsY.length. Vediamo in pratica il disegno di un poligono: int coordsX[] = {10, 20, 30, 40}; // Array con le coordinate x del pol. int coordsY[] = {10, 20, 30, 40}; // Array con le coordinate y del pol. int polpunti = coordsX.length; g.drawPolygon(coordsX, coordsY, polpunti); Anche per i poligoni esiste il comando che riempie, e' fillPolygon(). Questo unisce eventualmente il primo e l'ultimo punto per chiudere la figura, se questa non era gia' chiusa, e in casi di "ingarbugliamento" riempie le aree in alternanza, in modo che accanto ad una riempita ce ne sia una "vuota" e poi un'altra riempita, come una scacchiera. >>>> Vediamo un esempio in Polygon1.class/html. Non vi siete stancati di veder scrivere in nero su grigio? Sicuramente. Allora, vediamo come gestire i colori. Bisogna premettere che Java deve funzionare su molti sistemi operativi diversi, capaci di visualizzare a volte un massimo di 256 colori, di 65mila o 16milioni, per cui a parte l'ultimo fortunato caso deve "arrangiarsi" e visualizzare il colore piu' simile a quello selezionato, che e' a 24 bit (256*256*256, 16 milioni di possibili colori). Per rappresentare i colori esiste l'apposita classe Color, ed ogni colore e' rappresentabile a seconda delle percentuali di ROSSO, VERDE, BLU che contengono (si tratta di sintesi additiva, come nella fusione della luce, e non si sintesi sottrattiva, come nell'unione di tinte colorate.. questo lo dico per i pittori che potrebbero trovarsi un po' indispettiti dai risultati del mischiaggio). Il colore e' detto RGB (red, green, blue). Esistono dei colori predefiniti, molto standard; date un'occhiata ai valori RGB per rendervi conto di come modificare secondo le vostre esigenze i colori: R G B Color.white 255, 255, 255 - Bianco Color.black 0, 0, 0 - Nero Color.lightGray 192, 192, 192 - Grigio chiaro Color.gray 128, 128, 128 - Grigio Color.darkGray 64, 64, 64 - Grigio scuro Color.red 255, 0, 0 - Rosso Color.green 0, 255, 0 - Verde Color.blue 0, 0, 255 - Blu Color.yellow 255, 255, 0 - Giallo Color.magenta 255, 0, 255 - Magenta Color.cyan 0, 255, 255 - Ciano Color.pink 255, 175, 175 - Rosa Color.orange 255, 200, 0 - Arancione Per crearsi un particolare colore basta passare al costruttore Color() le componenti RGB che vogliamo: Color miocolore1 = new Color(123, 234, 210); I metodi relativi al colore sono SetColor() (nella classe Graphics) , per settare il colore con cui disegnare, e setBackground()/setForeground() per cambiare il colore di sfondo e primo piano di un applet (o componente qualsiasi, infatti questi 2 metodi sono in java.awt.Component). Per settare il colore si puo' fare in questi modi: g.setColor(Color.red); // Colore di disegno corrente: rosso standard Color miocol1 = new Color(100,200,250); // Creo un mio colore g.setColor(miocol1); // Setto miocol1 come colore di disegno corrente g.setColor(new Color(100,200,250)); // Creo e setto un mio colore. I metodi setBackground() e setForeground() servono soprattuto nelle applet per cambiare il colore di tutto lo sfondo o il primo piano in un sol colpo. >>>> Vediamo un esempio in Colors1.class/html. A questo punto possiamo disegnare caratteri, cerchi, poligoni colorati... Ma manca una delle cose importanti: l'inserimanto di immagini jpg o gif, infatti non possiamo pensare di disegnare una foto a forza di puntini! L'argomento del caricamento e visualizzazione delle immagini e' piuttosto vasto, per cui vedremo soltanto come caricare un'immagine con GetImage() e come visualizzarla con drawImage(). Le immagini in Java sono oggetti di tipo Image, e uno dei modi per definirne una e' di caricarla (da internet o dall'hard disk), tramite getImage() del package java.awt.Image. Una volta che abbiamo la nostra immagine, basta visualizzarla passandola al metodo drawImage della classe Graphics, che sara' esegito nel metodo paint() dell'applet. Vediamo intanto come usare getImage: questo metodo vuole l'URL (ossia l'indirizzo di base internet o l'hard disk) dove si trova l'immagine, e naturalmente il nome del file con eventuale path. In nostro aiuto puo' venire il metodo getDocumentBase() della classe Applet, che ci restituisce l'URL dove e' collocato il file html che contiene l'applet. A questo punto bastera' aggiungere il resto (nome del file ed eventuale altro subpath). Pero' nel caso dell'applicazione non abbiamo l'hmtl, quindi forse e' meglio usare GetCodeBase(), che restutuisce l'URL dove si trova il .class che dobbiamo avere per forza. Per caricare l'immagine anfy.gif che si trovi nella stessa directory dell'applet, si dovra' eseguire: Image miaimage1 = getImage(getCodeBase(), "anfy.gif"); Il metodo getCodeBase() puo' restituire l'indirizzo internet dove si trova il .class, ad esempio "http://www.anfiteatro.it/java/", oppure la directory nell'harddisk. Nel caso che l'immagine sia in una subdir "immagini", invece: Image miaimage1 = getImage(getCodeBase(), "immagini/baubau.jpg"); Il problema e' che anche getCodeBase() puo' restituire un "null", in quanto spesso non e' settato il CODEBASE come variabile di environment, o e' settata in altre directory. Quindi come soluzione di "salvataggio" facciamo in modo di sapere se l'esecuzione e' come applicazione, e in quel caso carichiamo con il path tra virgolette "" usando una versione di getImage che si trova in java.awt.ToolKit. Per usare i metodi di quel toolkit dobbiamo prima creare un'istanza del toolkit stesso: Toolkit defToolKit = Toolkit.getDefaultToolkit(); Dato che devo usare getImage(String), che si trova in java.awt.ToolKit, devo istanziare tale toolkit. Dopo bastera' defToolKit.metodo() per chiamare i metodi del toolkit. A questo punto, stabilito che la variabile SiamApplet e' vera solo se l'esecuzione e' di tipo applet (basta settarla falsa nel main(), eseguito solo nelle applicazioni), ecco come carichiamo l'immagine: if(SiamApplet) { miaimage1 = getImage(getDocumentBase(), "anfy.gif"); // Applet } else { // Altrimenti Carica come applicazione miaimage1 = defToolKit.getImage("anfy.gif"); } Una volta ottenuta l'immagine, per visualizzarla basta passarla al metodo drawImage(img, x, y, this), dove img e' l'immagine (istanza della classe Image), x,y sono le coordinate dell'angolo superiore sinistro, e this consideratelo un parametro "standard", in quanto occorrerebbe fare una disgressione sugli ImageObserver non opportuna in questa lezione. >>>> Vediamo un esempio in LoadImg1.class/html. Si puo' anche fare in modo che l'immagine da caricare sia decisa da un parametro scritto nel tag applet dell'html, in modo che l'applet possa essere usata anche da terzi per le proprie esigente (ed immagini). Supponendo che il parametro sia imag1: Image miaimage1 = getImage(getDocumentBase(), getParameter("imag1")); Nell'HTML si dovra' aggiungere . Se l'immagine non viene caricata con successo per qualche motivo, getImage restituisce un valore null (una "specie" di zero), ed e' buona regola considerare e controllare questa eventualita', magari con un "if". >>>> Vediamo un esempio in LoadImg2.html. Naturalmente e' eseguibile solo come Applet. -------------------------------------------------------------------------- AWT -------------------------------------------------------------------------- L'Abstract Windows Toolkit (AWT), come dice il nome, e' un sistema di finestre, bottoni e altre interfacce, caratteristico in sistemi come X-Windows, Windows 95 o System7 del Mac, guidati intuitivamente da una freccia puntatore mossa tramite mouse. Il problema piu' grande e' stato quello di rendere Abstract tutto cio', ossia funzionante su tutte le piattaforme. Si e' deciso di sfruttare i toolkit nativi di ogni piattaforma (ossia bottoni, finestre, barre di scorrimento del sistema presente sulla macchina che esegue il codice), in modo da rendere piu' veloce e sicura l'implementazione. In questo modo, se si fa un applet che apre una finestra con un bottone, sotto windows 95 la finestra avra' la classica forma delle finestre win95, con gli stessi gadget, mentre sotto System7 del Mac avra' la forma delle finestre mac. Purtroppo pero' la versione 1.0 di AWT non e' gran che, dato il poco tempo avuto a disposizione per terminarlo, si spera la situazioni migliori in futuro. Gli elementi che compongono un'interfaccia utente AWT sono composte da vari componenti, gerarchicamente annidati: la finestra principale contiene i pannelli, all'interno dei quali ci sono altri componenti come i bottoni, e cosi' via. Le applet, in particolare, sono una subclasse di pannello, dedicata ai web browsers di internet. Un'altra parte di AWT gestisce gli eventi come la pressione dei tasti del mouse e il suo spostamento, la pressione di tasti da tastiera, e tutta la gestione dei componenti delle interfacce (pressione bottoni eccetera). Abbiamo visto il gestore di eventi della tastiera keyDown(), che viene chiamato quando un tasto viene premuto, e come argomento e' passato proprio il codice del tasto. Per la gestione delle interfacce utente esiste il metodo action(), in particolare: public boolean action(Event eventuccio, Object argomento) Viene passato l'evento, e un oggetto il cui tipo dipende dall'evento che si e' vefificato (si tratta di informazioni addizionali come il testo del bottone premuto, l'elemento selezionato in un menu', ecc.). Si dovra' prima di tutto verificare quale oggetto ha generato l'evento, e per far cio' si verifica la sua variabile "target" tramite l'operatore instanceof (che significa "istanza di"): if(eventuccio.target instanceof Button) { // Uno dei bottoni premuti??? Cosi' per tutti gli altri componenti che abbiamo nella nostra interfaccia e potrebbero generare un evento. Vediamo le classi piu' importanti di AWT: Component: E' una superclasse abstract da cui derivano le altre, come Container, che si occupa della disposizione dei componenti che contiene (tramite l'interfaccia LayoutManager). Window: Una finestra senza bordi e menubar. Puo' servire per implementare dei pop-up menu. Il tipo di layout di default e' BorderLayout. Frame: Una subclasse di Window, che sta "davanti" alle altre cose ed ha un titolo. Il tipo di layout di default e' BorderLayout. Panel: Una subclasse concreta di Container (usabile), che permette annidamenti (un panel puo' stare dentro un'altro panel). Per aggiungere nuovi componenti ad un Panel si usa il metodo add(), poi con i metodi move(), resize(), reshape() si possono spostare e ridimensionare. Da notare che Applet e' una subclasse di Panel, per cui i metodi paint() e update() lavorano su un Panel. Per aggiungere un componente ad un pannello si deve creare tale componente ed aggiungerla al pannello stesso con il metodo add(): Button bottoncino = new Button("Esci di qui"); add(bottoncino); Vedremo poi in che punto viene aggiunto il bottoncino, e come fare per decidere le disposizioni dei componenti tramite LayoutManager. Canvas: Una subclasse (solitamente) concreta di Component. Rappresenta una specie di "superficie libera" su cui si puo' fare di tutto, agendo col metodo paint(). Label: Una subclasse di Canvas per visualizzare stringhe di testo, o meglio etichette con un particolare Font e Color. In seguito si possono modificare con i metodi getFont(), setFont() e setText(). Le label servono per lo piu' ad aggiungere un nome o una descrizione ad altri componenti, magari affiancati ad esse: se per esempio abbiamo un campo in cui si puo' scrivere (TextField), occorrera' scrivere accanto cosa occorre immettere (ad es: nome, cognome...). Per la giustificazione a destra, sinistra o centro del testo esistono le tre costanti LEFT,RIGHT,CENTER. >>>> Vediamo un esempio in Label1.class/html. Button: E' un componente che genera un Event quando viene premuto, e fisicamente e' un bottone rettangolare con un'etichetta String. Caratteristici sono i bottoni "ok - cancel" che compaiono sovente nei vari sistemi operativi quando si fa qualcosa di pericoloso. >>>> Vediamo un esempio in Button1.class/html. Checkbox: Serve per fare pulsantini selezionabili con etichetta a fianco. Si tratta di quei pulsantini che quando si clickano diventano barrati, e se si riclickano tornano "vuoti". Servono per indicare condizioni boleane (VERO-SI/NO-FALSO). Al costruttore si passa la stringa e lo stato iniziale (barrato o no). Da notare che ogni Checkbox, se non e' incluso in un CheckBoxGroup, e' indipendente e singolarmente selezionabile o deselezionabile: clickandone uno non si cambiano gli altri. I box (pulsantini) di questo tipo sono quadrati. Con i metodi getState() e setState() si possono sapere o modificare gli stati (selezionato/deselezionato) dei checkbox. Se si usa il costruttore "CheckBox(String)" si crea la casella deselezionata col testo String alla sua destra. Se si volesse fare in modo che qualche Box sia gia' selezionato all'inizio, si puo' usare setState o crearlo con: checkBox(String, null, true) In pratica si aggiungono 2 parametri: il null, che va messo comunque (ci va un eventuale checkboxgroup) e lo stato iniziale, true o false. >>>> Vediamo un esempio in CheckBox1.class/html. CheckBoxGroup: E' un oggetto che serve a raggruppare vari checkbox, in modo che uno solo nel gruppo possa essere attivato, e attivandone eventualmente un'altro si disattivi quello precedentemente selezionato. I box (pulsantini) di questo tipo sono rotondi. Per decidere/sapere l'appartenenza di un CheckBox ad un gruppo si usano i metodi getCheckBoxGroup() e setCheckBoxGroup(), mentre per dedidere/sapere quale checkbox e' selezionato si usano getCurrent() e setCurrent(). >>>> Vediamo un esempio in CheckBoxG1.class/html. Choice: Crea un menu' di selezione a "tendina" (pop-up). In pratica di questi menu' si vede soltanto la stringa dell'elemento correntemente selezionato, con un pulsantino alla sua destra con disegnata una freccina verso il basso: clickando in questo pulsantino si "dispiega" il menu', con tutte le stringhe di testo una sotto l'altra. Una volta selezionata quella che interessa, il choice menu torna ad occupare una sola linea, contenente la sola stringa selezionata. Per costruire un choice serve la serie di stringhe nello stesso ordine in cui si vorra' tenere il menu'. Come in CheckBoxGroup, si puo' selezionare un solo componente. I metodi utili sono: addItem() per aggiungere nuove stringhe, conuntItems() che restituisce il num. di elementi, select() per stabilire l'elemento selezionato correntemente, infine per leggere quale elemento e' selezionato su possono usare, a seconda se si desidera sapere la stringa o il numero di elemento, i metodi getSelectedItem() e getSelectedIndex(). Ecco un esempio: Choice miascelta = new Choice(); // Creo il Choice miascelta.addItem("Verde"); // Aggiungo gli elementi al choice miascelta.addItem("Bianco"); miascelta.addItem("Rosso"); add(miascelta); // Aggiungo il choice al pannello Si noti l'annidamento: il pannello contiene il choice che contiene i suoi item. Si possono aggiungere item anche dopo che il choice e' stato aggiunto al pannello. >>>> Vediamo un esempio in Choice1.class/html. List: E' una lista (o elenco) di opzioni una sotto l'altra, con o senza barra di scorrimento. A differenza di choice visualizza tutta la lista, o almeno un certo numero di elementi da noi stabiliti, e non solo l'elemento selezionato. Per di piu' si puo' selezionare piu' di un elemento, facendo scelte multiple. Ad esempio: List mialista = new List(3, true); // Creo una lista che puo' visualizzare al max 3 elem. ed e' possibile la selezione multipla (true). mialista.addItem("Pane"); // Aggiunge gli elementi alla list mialista.addItem("Burro"); mialista.addItem("Marmellata"); add(mialista); // Aggiunge la lista al pannello. Piu' precisamente, se il numero di elementi e' superiore alla lunghezza della lista (che permettera' di visualizzare al massimo un certo numero di elementi), viene aggiunta automaticamente la barra di scorrimento. >>>> Vediamo un esempio in List1.class/html. Scrollbar: Si tratta di barre di scorrimento, utili per far scegliere all'utente un valore tra un minimo x e un massimo y. Una scrollbar e' costituita da un rettangolo, con due pulsantini freccia alle estremita', e un quadrato scorrevole al suo interno, che rappresenta graficamente la posizione del valore scelto nel campo di azione possibile. Si puo' modificare il valore scelto sia spostando il quadratino scorrevole che clickando sui pulsantini freccia agli estremi, che variano di 1 in + o - il valore (una specie di taratura fine); si puo' opzionalmente stabilire che varino di piu' di uno. Se si clicka fuori dal quadratino scorrevole si fa scattare quest'ultimo spostando il valore di 10 (o di un valore da noi diversamente stabilito). Comunque chi usa i sistemi operativi a finestre dovrebbe conoscere bene le scrollbar. Altre cose che ci interessano sono le costanti VERTICAL e HORIZONTAL, da passare al costruttore per decidere l'orientamento. Con getValue() e setValue() si puo' leggere e modificare il valore corrente. >>>> Vediamo un esempio in Scrollbar1.class/html. TextField: Crea delle righe di input in cui l'utente puo' scrivere del testo liberamente. E' possibile scrivere un'etichetta alla destra o alla sinistra dell'area editabile. Il valore corrente si puo' ottenere/modificare con i metodi getText() e setText(). Ad esempio creiamo un textfield che richieda l'immissione del nome dell'utente, lungo al massimo 20 caratteri. TextField campotesto = new TextField("nome",20); // Creo... add(campotesto); // e aggiungo E' possibile anche fare in modo che non si veda quello che l'utente scrive, per occasioni tipo l'immissione di passwords: per questo si usa setEchoCharacter(). >>>> Vediamo un esempio in Textfield1.class/html. Visto che abbiamo la possibilita' di immettere stringhe con AWT, vediamo un po' meglio i metodi della classe String: >>>> Vediamo un esempio in String1.class/html. TextArea: Crea un'area editabile di dimensioni (righe e colonne) definite passandole al costruttore, assieme ad una stringa con eventuale testo che deve essere gia' presente. Si tratta praticamente di un piccolo editor di testi. >>>> Vediamo un esempio in TextArea1.class/html. - Nella prossima versione del corso questa lezione sara' terminata con la parte relativa alla gestione avanzata dei layout.