Introduzione
Come
e' ormai noto, la piu' grossa sfida affrontata dai progettisti di java
nello studio della JVM fu quello di realizzare un package grafico capace
di funzionare con un buon livello di prestazioni su piattaforme molto differenti
tra di loro. La soluzione proposta nel 1996 fu AWT, un package che mappava
i componenti grafici del sistema ospite con una serie di classi scritte
in gran parte in codice nativo.
Questa
scelta limitava pesantemente la scelta dei componenti da includere nell'API,
poiche' costringeva a prendere in considerazione solamente quel limitato
insieme di controlli grafici che costituivano il "minimo comun denominatore"
tra tutti i sistemi a finestre esistenti.
Inoltre
comportava dei grossi problemi di visualizzazione, poiche' le interfacce
grafiche realizzate su una JVM apparivano spesso con dei grossi difetti
se eseguite su una JVM differente.
Il
package Swing, al contrario, e' stato realizzato totalmente in codice java,
senza ricorrere alle primitive di sistema. In questo modo sono stati risolti
alla radice i problemi di compatibilita', dal momento che la stessa identica
API viene utilizzata, senza alcuna modifica, su qualunque JVM. Dal momento
che la Sun Microsystem ha pubblicato il codice delle API java, e' addirittura
possibile studiarne i sorgenti e localizzare, ad esempio, i metodi che
si occupano di disegnare i singoli componenti sullo schermo.
Liberi
dal vincolo del "minimo comun denominatore", i progettisti di Swing hanno
scelto di percorrere la via opposta, creando un package ricco di funzionalita'
spesso non presenti nella piattaforma ospite.
Per
risolvere definitivamente il problema della differenza di visualizzazione,
viene offerta al programmatore la possibilita' di scegliere il Look &
Feel con cui visualizzare le proprie GUI, al contrario di quanto avveniva
su AWT, che era vincolato alla rappresentazione dei componenti della macchina
ospite.
|
Figura
1 - Pluggable Look & Feel
Questa
caratteristica, denominata "Pluggable Look & Feel", e' forse l'aspetto
piu' sorprendente di Swing, in quanto e' totalmente trasparente al programmatore.
Qualsiasi GUI realizzata in Swing puo' essere visualizzata in uno qualunque
dei L&F disponibili sul sistema, senza che venga richiesta alcuna modifica
a livello di codice sorgente. Non esistono problemi di compatibilita' nel
passaggio tra un L&F e l'altro, dal momento che i componenti Swing
sono stati progettati per mantenere una netta separazione tra la rappresentazione
grafica di un componente, le informazioni che contiene e il controllo che
implementa. Questo design, definito "Model Control View" (MCV), risulta,
nella maggior parte dei casi, del tutto trasparente al programmatore, che
puo' utilizzare i componenti Swing nello stesso modo in cui era abituato
con quelli AWT. Nel momento in cui ci fosse la necessita' di progettare
componenti personalizzati, si potranno sfruttare pienamente le funzionalita'
offerte da questo design.
La
presenza di queste features non va ad incidere sulla caratteristica
piu' richiesta da un programmatore: la facilita' d'uso. Chi avesse gia'
maturato una buona conoscenza di AWT, si trovera' a proprio agio con Swing,
data la sostanziale compatibilita' a livello sorgente. Chi invece fosse
alla ricerca di nuove modalita' operative, trovera' soddisfazione nell'esplorare
le caratteristiche piu' avanzate di questa straordinaria API grafica
Il padre di tutti
i componenti Swing: JComponent
Il
package Swing contiene piu' di 70 classi, quasi tutte sottoclassi di JComponent,
una classe astratta derivata da Component e da Container. Al pari di Component,
JComponent e' un'oggetto grafico che ha una posizione e una dimensione
sullo schermo, al cui interno e' possibile disegnare, scrivere o ricevere
eventi dal mouse e dalla tastiera. Come Container invece, offre la possibilita'
di disporre altri componenti al suo interno, nonche' il supporto ai LayoutManager,
che facilitano l'impaginazione dei componenti.
|
Figura
2 - JComponent eredita il proprio comportamento sia da JComponent che
da Container. Di nuovo aggiunge la capacita' di aggiungere bordi e Tooltip
La
classe JComponent fornisce in esclusiva alcune funzionalita', che vengono
ereditate da qualunque componente Swing. Tra queste possiamo segnalare:
-
Tool tips:
il metodo setToolTipText(String) permette di aggiungere un ToolTip, un
messaggio testuale che compare sul componente dopo che l'utente vi ha lasciato
fermo il mouse per qualche istante.
-
Bordi:
ogni componente Swing puo' essere dotato di un bordo grazie al metodo setBorder(Border).
La classe BorderFactory fornisce strumenti per creare diversi tipi di bordo,
da semplici contorni a sofisticate decorazioni
-
Pluggable
look and feel: e' la possibilita' offerta da ogni JComponent di essere
visualizzato in maniera differente a seconda del Look & Feel impostato
dall'utente.
-
Double
buffering: il Double Buffering rende il refresh delle interfacce grafiche
Swing molto piu' naturale di quanto avvenisse con i componenti AWT.
Classificazione
funzionale dei componenti Swing
E'
possibile classificare i componenti Swing in base all'uso che se ne fa,
secondo una classificazione che non corrisponde necessariamente all'organizzazione
gerarchica delle classi all'interno del package; questa classificazione
funzionale e' indispensabile per stabilire un ordine di esposizione
La
prima categoria e' quella dei "Top Level Containers", indispensabili per
realizzare qualunque interfaccia grafica. Sono gli unici componenti
Swing che non derivano da JComponent, essendo sottoclassi dei rispettivi
componenti AWT. Il piu' usato di questi e' JFrame, corrispondente
ad una finestra di sistema. JDialog implementa invece una finestra modale,
cioe' una finestra che "blocca" il frame principale in attesa di un evento
utente. Meno usati sono invece JWindow, che implementa una finestra priva
di pulsanti di controllo (utile nella realizzazione di Splash Screen) e
JApplet, l'implementazione Swing dell'Applet AWT.
La
seconda categoria e' quella dei Contenitori, che sono componenti entro
i quali e' possibile collocare altri componenti, secondo il Layout definito
dal programmatore. Alcuni contenitori forniscono delle funzionalita' aggiuntive:
ecco una rassegna di quelli di uso piu' comune
-
JPanel:
e' il contenitore di base per controlli grafici.
-
JScrollPane
: e' un JPanel dotato di scrollbar, che puo' contenere superfici piu' grandi
dell'area visibile.
-
JSplitPane:
contiene due pannelli separati da una barra di split riposizionabile
-
JTabbedPane:
permette di creare un insieme di pannelli richiamabili attraverso tab
-
JToolBar:
e' la caratteristica pulsantiera presente ormai su qualunque programma
grafico
I
seguenti contenitori meritano di essere trattati a parte, dal momento che
sono destinati ad un uso piu' specialistico.
-
JLayeredPane:
permette di disporre componenti su livelli sovrapposti, visibili in trasparenza.
-
JDesktopPane:
e' un pannello che offre la capacita' di creare ambienti tipo Desktop,
con oggetti grafici e finestre al suo interno.
-
JInternalFrame:
e' un contenitore simile ad una finestra, realizzato apposta per essere
visualizzato all'interno di JDesktopPane.
Su
Swing troviamo qualunque tipo di Controllo Grafico presente in un moderno
sistema a finestre, come pulsanti, menu o checkbox. Rispetto agli analoghi
componenti AWT possiamo segnalare fin da subito la possibilita' di inserire
icone e label all'interno di qualunque componente, sia esso un pulsante,
un menu o un ComboBox.
Il
package Swing contiene di serie alcuni strumenti per lavorare su strutture
dati complesse, come JTable che permette di generare report formattati
in stile Spreadsheet, o JTree che fornisce una vista su strutture
ad albero come ad esempio i FileSystem.
Per
navigare tra i colori di sistema o attraverso il File System, sono stati
realizzati i componenti JColorChooser e JFileChooser.
Per
finire, un set completo di Text Components permette di affrontare qualunque
situazione in cui sia necessario manipolare dei testi.
-
JTextField
implementa il classico campo di testo a singola riga.
-
JPasswordField
permette di inserire in un campo di testo informazioni riservate, invisibili
ad occhi indiscreti
-
JTextArea
e' un componente di testo ideale per lavorare su documenti di media lunghezza
privi di formattazione
-
JEditorPane
e' un componente di testo in grado di manipolare documenti formati. Dispone,
per default, della capacita' di trattare RTF o HTML, ma e' possibile crearne
delle estensioni per renderlo adatto a trattare qualunque altro formato.
-
JTextPane
infine permette di lavorare su qualunque tipo di testo, utilizzando qualunque
combinazione di font, stile, colore e persino di aggiungere immagini o
collegamenti ipertestuali.
I Top Level
Container
|
Figura
3 - I Top Level Container Swing derivano dai corrispondenti componenti
AWT
I Top
Level Container sono i componenti all'interno dei quali si creano le interfacce
grafiche: ogni programma grafico ne possiede almeno uno, di solito un JFrame,
che rappresenta la finestra principale.
Come
si puo' vedere dalla gerarchia delle classi, i Top Level Container sono
l'interfaccia tra il mondo AWT e quello Swing. Diverse proprieta' dei controlli
grafici non sono presenti nei Top Level Container: in particolare il cambio
di Look & Feel non va ad incidere sull'aspetto delle finestre, che
rimangono sempre e comunque uguali alle altre finestre di sistema.
Dal
punto di vista implementativo, i Top Level Container presentano una struttura
a strati piuttosto complessa, che verra' illustrata piu' avanti, dopo aver
introdotto alcuni importanti concetti. L'unica implicazione degna di nota
per l'utente comune e' la presenza di un "Pannello di Contenimento" (Content
Pane), accessibile attraverso il metodo getContentPane(): questo pannello,
e non il JFrame, verra' utilizzato come contenitore base per tutti gli
altri controlli . Questo dettaglio e' l'unica vistosa differenza a cui
il programmatore AWT deve abituarsi nel passaggio a Swing: se su AWT si
era abituati a scrivere
Frame
f = new Frame();
f.setLayout(new
FlowLayout());
f.add(new
Button("OK));
ora
e' necessario scrivere
JFrame
jf = new JFrame();
Container
contentPane = jf.getContentPane();
contentPane.setLayout(new
FlowLayout());
contentPane.add(new
Button("OK));
o piu'
brevemente
JFrame
jf = new JFrame();
jf.getContentPane().setLayout(new
FlowLayout());
jf.getContentPane().contentPane.add(new
Button("OK));
JFrame
Possiamo
creare una finestra usando i seguenti costruttori
public
JFrame():crea
una finestra
public
JFrame(String title):
crea una finestra con il titolo specificato dal parametro
I seguenti
metodi permettono di lavorare su alcune proprieta' dell'oggetto
-
public
void setSize(int width, int height):
specifica la larghezza e l'altezza della finestra.
-
public
void setResizable(boolean b):
permette di stabilire se si desidera che la finestra sia ridimensionabile.
-
public
void pack():
ridimensiona la finestra tenendo conto della dimensione ottimale dei componenti
posti al suo interno.
-
public
void setBounds(int x, int y, int width, int height):
oltre alle dimensioni, permette di specificare anche le coordinate dell'angolo
in alto a sinistra
-
public
void setDefaultCloseOperation(int operation):
Seleziona cosa deve accadere alla pressione del tasto "close", dopo aver
provveduto alla notifica degli ascoltatori. Sono disponibili le seguenti
scelte:
-
WindowConstants.DO_NOTHING_ON_CLOSE:
nessun effetto.
-
WindowConstants.HIDE_ON_CLOSE:
nasconde la finestra (e' l'impostazione di default)
-
WindowConstants.DISPOSE_ON_CLOSE:
distrugge la finestra, che non potra' piu' essere aperta.
-
JFrame.EXIT_ON_CLOSE:
(introdotto nel JDK1.3) chiude la finestra e termina l'esecuzione del programma.
-
public
void setTitle(String title)
imposta il titolo della finestra.
-
public
void setVisible(boolean b)
Rende la finestra visibile o invisibile, secondo il valore del parametro.
-
public
void setJMenuBar(JMenuBar menubar)
aggiunge una JMenuBar al Frame.
-
public
Container getContentPane()
restituisce il pannello di contenimento del JFrame, al cui interno e' possibile
aggiungere i componenti.
Il
seguente programma di esempio crea un JFrame, gli da un titolo, una posizione,
una dimensione, ne stabilisce il comportamento in chiusura e lo rende visibile.
import
javax.swing.*;
public
class JFrameExample {
public static void main(String argv[]){
JFrame j = new JFrame();
j.setTitle("JFrameExample");
j.setBounds(10,10,300,200);
j.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
j.setVisible(true);
}
}
|
Figura
4 -
Un JFrame vuoto
JDialog
Le
finestre di dialogo vengono usate per l'inserimento di valori, o per segnalare
all'utente una situazione anomala. Ogni finestra di dialogo appartiene
ad un'altra finestra; se definiamo come modale un JDialog, alla sua
comparsa esso blocchera' il frame di appartenenza, in modo da costringere
l'utente a portare a termine l'interazione. Possiamo creare finestre
di dialogo con i seguenti costruttori
-
JDialog(Dialog
owner, String title, boolean modal):
crea un JDialog modale o non modale, con un titolo e con lo specificato
Dialog come proprietario.
-
JDialog(Frame
owner, String title, boolean modal):
crea un JDialog modale o non modale, con un titolo e con lo specificato
Frame come proprietario.
Altri
costruttori permettono di specificare un numero inferiore di parametri.
I metodi presentati su JFrame sono validi anche su JDialog. Ovviamente
non e' possibile selezionare l'opzione EXIT_ON_CLOSE con il metodo
setDefaultCloseOperation().
Conclusione
Questa
veloce panoramica ha permesso di esplorare i contenuti del Package Swing,
e di impadronirsi dell'uso dei principali Top Level Container. Dal prossimo
articolo entreremo nel vivo della progettazione di interfacce grafiche
analizzando il concetto di Gerarchia di Contenimento e di Layout Management.
Appendice: Dove
si trovano i sorgenti delle API del JDK
Uno
studio anche occasionale dei sorgenti delle API permette di capire molte
cose sul linguaggio java, sul suo funzionamento e sullo stile di programmazione.
Soprattutto aiuta a capire che le classi di libreria, per quanto grandi
e complesse, sono pur sempre programmi java, e che con il giusto impegno
e' possibile raggiungere lo stesso livello di efficienza nella scrittura
del codice.
Potete
trovare i sorgenti di tutte le API java nel file src.jar, presente nella
directory principale del JDK. Potete aprirla trascinando l'icona del fine
src.jar dentro WinZip, oppure lanciando dalla directory del JDK il comando
jar
xvf src.jar
che
estrare tutti i sorgenti nella directory src.
|