Introduzione
È
inutile dire che al package AWT andrebbero dedicate due o tremila puntate
se si volesse in qualche modo dare anche una piccola spolverata sulle sue
possibilità. In questa panoramica rinunceremo quindi alla completezza
offrendo una visita ragionata delle principali classi del package lasciando
a chi ne a voglia l'arduo compito di approfondire e, soprattutto, sperimentare!!!
L'AWT
è stato uno dei package che ha decretato il successo di Java: per
la prima volta infatti nella libreria standard di un linguaggio si trovava
un'astrazione del concetto di interfaccia grafica. L'AWT sta infatti a
Java come la libreria stdio.h sta al C. Se infatti i linguaggi precedenti
avevano sempre scartato l'idea di standardizzare l'interfaccia grafica
(lasciando il povero programmatore in preda a mari di librerie) la Sun
introdusse l'AWT per consentire alle applet di aprire finestre sulla macchina
client e offrire un'interfaccia grafica per l'utente.
Inoltre
questo package è quello che più di altri rappresentato un
argine tra la versione 1.0.2 di Java e la versione 1.1 poiché è
ne è stato sconvolto l'impianto di base.
L'idea
originale dell'AWT era quella di offrire una libreria che fosse multipiattaforma
offrendo componenti grafici comuni a tutte le interfacce grafiche disponibili.
Quindi le varie componenti come bottoni, liste, combobox, checkbox, radio
button, caselle di testo e quanto altro sono controllabili da Java nello
stesso modo sia su Windows, che su Unix che su Mac. Ad ogni componente
offerto dall'interfaccia grafica nativa è associato un peer in Java
(un oggetto che consente da Java la manipolazione dell'oggetto reale).
Così troviamo classi come Button, TextField, etc. che sono solo
dei rappresentanti Java dei peer dell'interfaccia grafica.
Nella
sua prima implementazione l'AWT adottava una struttura simile ai framework
di classi per l'interfaccia grafica come MFC o OWL. In un primo momento
la gestione degli eventi veniva propagata attraverso la gerarchia delle
classi (secondo la relazione di ereditarietà); successivamente fu
adottato il delegation event model per alleggerire il costo della gestione
dei messaggi e ottimizzare l'intero framework.
Questa
panoramica coprirà i tre aspetti fondamentali della gestione dell'interfaccia:
la gestione degli eventi, la gestione dei componenti, la gestione delle
finestre e il layout dei componenti.
La struttura generale
del package AWT
Il
package AWT contiene svariati sottopackage che sono cresciuti al succedersi
delle nuove funzioni. In particolare troviamo i seguenti package nella
versione 1.2 di Java:
java.awt.color
java.awt.datatransfer
java.awt.dnd
java.awt.event
java.awt.font
java.awt.geom
java.awt.im
java.awt.image
java.awt.image.renderable
java.awt.print
Il package
java.awt.color contiene classi per la gestione avanzata del color space.
Il package java.awt.datatransfer definisce le classi necessarie per il
trasferimento dei dati dall'applicazione Java ad altre applicazioni, possibilmente
anche non Java. Questo trasferimento di dati può esprimersi tramite
il passaggio di dati nella clipboard di sistema oppure tramite l'azione
di drag and drop. La clipboard può essere gestita direttamente con
questo package mentre il drag and drop è gestito dal package java.awt.dnd.
Il package java.awt.event offre il supporto per la gestione degli eventi
come vedremo in seguito. Il package java.awt.font contiene interfacce e
classi per il trattamento avanzato delle fonti; contiene ad esempio l'utilissima
classe LineBreakMeasurer che spezza una stringa in più stringhe
in modo tale che una linea di testo occupi una certa larghezza dato il
font usato per realizzarla. Il package java.awt.geom offre varie classi
ed interfacce per la gestione della grafica 2D fornendo la possibilità
anche di disegnare curve come le classi QuadCurve2D.Double e QuadCurve2D.Float.
Il package java.awt.im si occupa di offrire un'interfaccia per la gestione
dell'input per la realizzazione di editor consentendo l'immissione di caratteri
che non siano quelli occidentali (Kanji, ideogrammi...). I package java.awt.image
e java.awt.image.renderable offrono il supporto per la manipolazione delle
immagini. Non abbiamo sufficiente spazio per descrivere questi due package
che offrono tra l'altro il supporto per il filtering delle immagini e la
loro generazione. Infine il package java.awt.print offre il supporto per
stampare documenti usando Java.
Nel
seguito di questo appuntamento ci concentreremo sul package java.awt trascurando
gli altri package eccezion fatta per il package java.awt.event indispensabile
per gestire gli eventi dell'interfaccia grafica.
Gli eventi in AWT
Come
abbiamo già accennato nell'introduzione la gestione degli eventi
è un aspetto cruciale nella gestione dell'interfaccia grafica. Il
sistema di gestione degli eventi ha subito una profonda trasformazione
dalla sua prima versione per migliorare l'efficienza della grafica in Java.
Noi
ci concentreremo quindi sul nuovo modello di gestione degli eventi chiamato
delegation event model. Questo modello prevede che ogni componente tenga
una lista di oggetti ascoltatori degli eventi che lui è in grado
di produrre. Nel momento in cui si produce l'evento il componente in questione
invoca un metodo che identifica l'evento per ogni oggetto ascoltatore.
Quindi che è interessato a ricevere gli eventi da un oggetto si
deve registrare presso quell'oggetto essendo un ascoltatore per gli eventi
emessi. Essere un ascoltatore significa implementare una precisa interfaccia
Java.
Il
package java.awt.event definisce tutte le interfacce per gli ascoltatori
di tutti gli eventi lanciati dai componenti dell'AWT.
Le
principali sono:
ActionListener |
L'interfaccia
per ricevere gli eventi collegati alle azioni. |
AdjustmentListener |
L'interfaccia
per ascoltare gli eventi di cambiamento di un valore |
ComponentListener |
L'interfaccia
per ricevere gli eventi dei componenti |
ContainerListener |
L'interfaccia
per ascoltare gli eventi dei contenitori |
FocusListener |
L'interfaccia
per sapere quando un componente ha il fuoco della tastiera. |
ItemListener |
L'interfaccia
per selezionare gli oggetti. |
KeyListener |
L'interfaccia
che permette di ascoltare gli eventi che provengono dalla tastiera. |
MouseListener |
L'interfaccia
che consente di ascoltare gli eventi principali del mouse: quando entra,
esce da un componente o quando viene premuto il bottone. |
MouseMotionListener |
L'interfaccia
che riceve gli eventi corrispondenti al movimento del mouse. |
TextListener |
L'interfaccia
che consente di capire quando è cambiato il contenuto di una casella
di testo. |
WindowListener |
L'interfaccia
per ricevere gli eventi lanciati da una finestra. |
Come
esempio consideriamo la gestione della pressione di un bottone:
/**
Classe che gestirà l'evento. */
class
ButtonHandler implements ActionListerner {
void actionPerformed(ActionEvent e) {
System.out.println("Bottone "+getActionCommand());
}
}
//
Codice che registra l'ascoltatore presso il bottone
...
Button
b = new Button("Prova");
b.addActionListener(new
ButtonHandler());
...
Poiché
molte interfacce hanno molti metodi da implementare il package java.awt.event
offre anche degli Adapter ovvero delle classi che implementano le interfacce
degli ascoltatori offrendo una gestione di default agli eventi. In questo
modo è possibile estendere una classe da un Adapter e ridefinire
solo i metodi corrispondenti agli eventi che si vogliono gestire.
Gestire
i componenti
La
gestione dei componenti è semplice nell'AWT: si crea un oggetto
istanziando una classe e lo si aggiunge ad un contenitore che lo ospiterà
visualizzandolo. I componenti più importanti presenti nel package
sono:
Button |
Classe
associata ai bottoni dell'interfaccia grafica. |
Canvas |
Componente
base per creare i propri componenti. |
Checkbox |
Casella
spuntabile con testo associato. |
Label |
È
un'etichetta di testo. |
List |
Lista
di elementi. |
Scrollbar |
Barra
di scorrimento (può essere orizzontale o verticale). |
TextArea |
Casella
di testo multilinea. |
TextField |
Casella
di testo a linea singola. |
Ognuno
di questi componenti può essere istanziato (passando gli opportuni
parametri al costruttore), possono essere aggiunti gli ascoltatori di eventi,
ed infine può essere visualizzato. Tutte le classi elencate sono
derivate dalla classe base Component che astrae il concetto di componente.
Questi componenti sono opachi nel senso che coprono completamente l'area
su cui risiedono eventualmente con un colore di background. Con l'avvento
del JDK1.1 sono stati introdotti i cosiddetti lightweight components ovvero
i componenti leggeri. Questi si caratterizzano perchè non viene
allocata una finestra per loro (come avviene invece nel caso di componenti
definiti a partire da un Canvas) e quindi possono assumere qualsiasi forma
senza essere costretti ad assumere la classica forma rettangolare. Un componente
lightweight si ottiene semplicemente estendendo la classe Component piuttosto
che la classe Canvas.
I
contenitori, le finestre e i layout
I
componenti sono inseriti in contenitori che si occupano di organizzarli
graficamente secondo il LayoutManager correntemente impostato.
I
contenitori di più alto livello sono le finestre (Frame, Dialog,
Window, ...).
una
delle trovate più geniali dell'AWT è stata sicuramente l'introduzione
del componente Panel che è sia un componente (come un bottone, una
casella di testo, etc.) che un contenitore di componenti (come una finestra).
La forza di questa trovata è che i pannelli possono essere "incastonati"
uno dentro l'altro ottenendo dei layout dei componenti anche molto sofisticati.
Poiché
le prime versioni di Java non disponevano di ambienti di sviluppo grafici
i programmatori della Sun si ingegnarono e risolsero il problema della
disposizione dei componenti in una finestra in un modo a dir poco geniale
che spesso passa ingiustamente in sordina. La soluzione proposta è
secondo me un capolavoro di concettualizzazione per una strutturazione
ad oggetti della libreria.
Ogni
contenitore ha associato un oggetto che è un LayoutManager ovvero
un oggetto che implementa l'interfaccia omonima. Questo oggetto è
investito del compito di disporre i componenti all'interno del contenitore
secondo una politica. Inoltre, quando si rende necessario, questo oggetto
dovrà ricalcolare la disposizione dei componenti.
Nel
package java.awt sono distribuiti vari layout manager che adottano differenti
politiche nella disposizione dei componenti. Troviamo ad esempio il BorderLayout
che in grado di disporre di al più cinque componenti; oppure il
complesso ma potentissimo GridBagLayout.
La
rivoluzionarietà di questa strutturazione concettuale è legata
al fatto che la disposizione dei componenti non dipende più dai
pixel come spesso accade nelle interfacce grafiche ma da specifiche che
non dipendono dalla dimensione del contenitore. Questo è possibile
al prezzo di un sacrificio della completa generalità nella disposizione
dei componenti. D'altronde la possibilità di incastrare i pannelli
uno dentro l'altro consente di usare differenti layout all'interno di uno
stesso contenitore.
Due
metodi della classe Component che rivestono un ruolo chiave nel funzionamento
dei layout manager sono il metodo getMinimumSize() e il metodo getPreferredSize():
spesso i layout manager sfruttano queste indicazioni fornite da un componente
per decidere l'effettiva disposizione dei componenti all'interno di un
contenitore.
Conclusioni
Fare
una panoramica sul package AWT non è cosa facile e spero di esservi
riuscito
(almeno un pochino). Questo perché è la libreria più
vasta e complessa di Java (dopo Swing che è costruita sopra di essa)
che sicuramente ne ha decretato il successo.
Non
esistono inoltre esempi tipo che non scadano nel banale. Per cui mi sembrava
più corretto cercare di dare una visione coerente del package piuttosto
che una serie di esempi del suo uso. |