Académique Documents
Professionnel Documents
Culture Documents
SAPIENZA Universita
` di Ingegneria dellInformazione,
Facolta
Informatica e Statistica
Corso di Laurea in Ingegneria Informatica ed
Automatica
Corso di Laurea in Ingegneria dei Sistemi
Informatici
Dispensa didattica
Indice
1
2
3
4
5
6
7
7.1
8
9
9.1
9.2
9.3
10
11
12
13
Introduzione . . . . . . . . . . . . . . . . . . . . . . . . .
Il package Swing . . . . . . . . . . . . . . . . . . . . . .
Top Level Container . . . . . . . . . . . . . . . . . . . .
Paranoramica di alcuni widget . . . . . . . . . . . . . . .
Lereditariet`a per personalizzare i frame . . . . . . . . .
Layout Management . . . . . . . . . . . . . . . . . . . .
Progettazione della GUI con le gerarchie di contenimento
Progettazione top down di interfacce grache . . . . . . .
7.1.1 Esempio di Progettazione Top-Down . . . . . . .
Realizzare nestre di dialogo con JOptionPane . . . . . .
La Gestione degli Eventi . . . . . . . . . . . . . . . . . .
Implementazione dellevent delegation . . . . . . . . . . .
Un esempio: elaborare gli eventi del mouse . . . . . . . .
Uso di adapter nella denizione degli ascoltatori . . . . .
La gestione degli eventi Azione . . . . . . . . . . . . . .
Accedere dallascoltatore agli oggetti di una nestra . . .
Condividere gli ascoltatori per pi`
u oggetti . . . . . . . .
Conclusioni e Commenti Finali . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
5
8
11
13
21
22
23
25
27
27
29
31
32
33
37
43
1 Introduzione
Introduzione
Il package Swing
Nel 1998, con luscita del JDK 1.2, venne introdotto il package Swing, i
cui componenti erano stati realizzati completamente in Java, ricorrendo unicamente alle primitive di disegno pi`
u semplici, tipo traccia una linea o
disegna un cerchio, accessibili attraverso i metodi delloggetto Graphics,
un oggetto AWT utilizzato dai componenti Swing per interfacciarsi con la
2 Il package Swing
Component
Container
JComponent
Panel
Window
JFrame
JDialog
JPanel
JApplet
java.awt
javax.swing
per lo pi`
u dalla classe javax.swing.JComponent; si stima che esistono circa 70
o pi`
u oggetti diversi. Gli oggetti graci utilizzati per disegnare le interfacce
vengono chiamati anche controlli oppure tecnicamente widget. JComponent
eredita da java.awt.Container, una sorta di controllo che di default `e vuoto
e il cui scopo `e orire la possibilit`a di disporre altri componenti allinterno.
Non a caso la classe AWT Window e le sottoclassi Swing JFrame e JDialog, le
cui istanze rappresentano nestre, sono sottoclasse di Container. La cosa pi`
u
sorprendente `e che, siccome JComponent deriva da Container, `e possibile inserire allinterno di un qualsiasi widget qualsiasi altro. Ad esempio - sebbene
poco utile - `e possibile aggiungere un campo di testo allinterno di un bottone
oppure - molto usato - un Container allinterno di un altro Container. La
classe Container (e ogni sottoclasse) denisce un metodo per aggiungere un
controllo ad un Container:
void add ( Component ) ;
import j a v a x . swing . ;
import j a v a . awt . ;
public c l a s s A p p l i c a t i o n {
public s t a t i c void main ( S t r i n g a r g s [ ] )
{
JFrame win ;
win = new JFrame ( Prima f i n e s t r a ) ;
C o n t a i n e r c = win . getContentPane ( ) ;
c . add (new JLabel ( Buona L e z i o n e ) ) ;
win . s e t S i z e ( 2 0 0 , 2 0 0 ) ;
win . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ;
win . s e t V i s i b l e ( true ) ;
}
}
I nomi delle classi per la maggior parte dei componenti dellinterfaccia utente
Swing iniziano con la J.
JTextField `e un campo di testo Swing. Tale classe eredita da TextField,
lobsoleto analogo del package AWT. Per costruire un campo di testo occorre
fornirne lampiezza, cio`e il numero approssimato di caratteri che vi aspettate
verranno inseriti dallutente.
J T e x t F i e l d x F i e l d=new J T e x t F i e l d ( 5 ) ;
JRadioButton `e una sottoclasse di JButton, dotata dei medesimi costruttori. Questo tipo di controllo, chiamato pulsante di opzione, viene usato
tipicamente per fornire allutente la possibilit`a di operare una scelta tra
un insieme di possibilit`a, in contesti nei quali unopzione esclude laltra. I
costruttori disponibili sono gli stessi della superclasse. Per implementare il
comportamento di mutua esclusione, `e necessario registrare i JRadioButton
che costituiscono linsieme presso unistanza della classe ButtonGroup, come
viene mostrato nelle righe seguenti:
JRadioButton r a d i o B u t t o n 1=new JRadioButton ( R1 ) ;
JRadioButton r a d i o B u t t o n 2=new JRadioButton ( R2 ) ;
JRadioButton r a d i o B u t t o n 2=new JRadioButton ( R3 ) ;
ButtonGroup group = new ButtonGroup ( ) ;
group . add ( r a d i o B u t t o n 1 ) ;
group . add ( r a d i o B u t t o n 2 ) ;
group . add ( r a d i o B u t t o n 3 ) ;
10
import j a v a x . swing . ;
import j a v a . awt . ;
public c l a s s A p p l i c a t i o n {
public s t a t i c void main ( S t r i n g a r g s [ ] )
{
JFrame win ;
win = new JFrame ( Esempio d i JComboBox ) ;
S t r i n g l i s t a [ ] =new S t r i n g [ 1 0 ] ;
fo r ( int i =0; i < l i s t a . l e n g t h ; i ++)
l i s t a [ i ]= Elemento numero +i ;
JComboBox cBox=new JComboBox ( l i s t a ) ;
C o n t a i n e r c = win . getContentPane ( ) ;
c . add ( cBox ) ;
win . s e t S i z e ( 2 0 0 , 2 0 0 ) ;
win . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ;
win . s e t V i s i b l e ( true ) ;
}
}
Ogni volta che lutente attiva uno dei pulsanti registrati presso il ButtonGroup,
gli altri vengono automaticamente messi a riposo.
I JComboBox orono allutente la possibilit`a di eettuare una scelta a
partire da un elenco elementi, anche molto lungo. A riposo il componente
si presenta come un pulsante, con letichetta corrispondente al valore attualmente selezionato. Un clic del mouse provoca la comparsa di un menu
provvisto di barra laterale di scorrimento, che mostra le opzioni disponibili.
Se si imposta la propriet`a editable di un JComboBox a true esso si comporter`a a riposo come un JTextField, permettendo allutente di inserire valori
` possibile creare un JComboBox usando i seguenti
non presenti nella lista. E
costruttori:
JComboBox ( ) ;
JComboBox ( Object [ ] i t e m s ) ;
11
Lereditariet`
a per personalizzare i frame
12
import j a v a x . swing . ;
import j a v a . awt . ;
c l a s s MyFrame extends JFrame
{
JLabel j l = new JLabel ( Buona L e z i o n e ) ;
public MyFrame ( )
{
super ( Prima f i n e s t r a ) ;
C o n t a i n e r c = t h i s . getContentPane ( ) ;
c . add ( j l ) ;
this . s e t S i z e (200 ,200);
t h i s . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ;
t h i s . s e t V i s i b l e ( true ) ;
}
}
public c l a s s A p p l i c a t i o n
{
public s t a t i c void main ( S t r i n g a r g s [ ] )
{
MyFrame = new MyFrame ( ) ;
}
}
questa situazione, si otterrebbero moduli sono molto accoppiati e poco coesi; inoltre, gli stessi moduli sarebbero poco leggibili e non sarebbe facile
manutenerli. In parole povere, non si sfrutterebbe le potenzialit`a dellObject Orientation: non sarebbe possibile permette linformation hiding dei
contenuti dei frame e dei controlli in essi contenuti; non sarebbe nemmeno
sfruttato lincapsulamento delle implementazione, mettendo insieme concetti
eterogenei e nestre diverse tra loro.
Il Listato 3 produce la stessa nestra in Figura 3 sfruttando lereditariet`a.
La dierenza rispetto agli esempi gi`a visti non `e da poco: a questo punto ogni
nestra diventa una nuova classe che, ereditando da JFrame, `e un modello
opportuno denire gli oggetti che mappano i widgets come
per le nestre. E
variabili di instanza (nel lesempio lunico widget `e una etichetta (JLabel). La
denizione della nestra e dei componenti contenuti viene fatta direttamente
nel costruttore (o in metodo chiamati da questo). La prima istruzione chiama il costruttore della superclasse che prende come parametro una stringa;
6 Layout Management
13
Layout Management
Quando si dispongono i componenti allinterno di un Container sorge il problema di come gestire il posizionamento: infatti, sebbene sia possibile specicare le coordinate assolute di ogni elemento dellinterfaccia, queste possono
cambiare nel corso della vita del programma allorquando la nestra principale
venga ridimensionata. In molti Container i controlli sono inseriti da sinistra
verso destra con su una ipotetica riga: pu`o non essere sempre la politica per
la GUI (Graphic User Interface) desiderata. Per semplicare il lavoro di impaginazione e risolvere questo tipo di problemi possibile ricorrere ai layout
manager, oggetti che si occupano di gestire la strategia di posizionamento
dei componenti allinterno di un contenitore.
Un gestore di layout `e una qualsiasi classe che implementa linterfaccia
LayoutManager; ogni container nasce con un certo Layout Manager ma `e
possibile assegnare il pi`
u opportuno per quel Container con il metodo:
public void s e t L a y o u t ( LayoutManager m) ;
6 Layout Management
14
(a)
(b)
Fig. 6: Aspetto grafico del frame definito nel Listato 4 e comportamento del
Flow Layout rispetto al ridimensionamento
Il secondo costruttore specica lallineamento dei controlli su una riga; il
parametro pu`o essere una delle seguenti costanti che rispettivamente allineano
a sinistra, centro o destra:
FlowLayout . LEFT
FlowLayout .CENTER
FlowLayout . RIGHT
6 Layout Management
15
import j a v a x . swing . ;
import j a v a . awt . ;
public c l a s s MyFrame extends JFrame
{
JButton uno=new JButton ( Uno ) ;
JButton due=new JButton ( Due ) ;
JButton t r e=new JButton ( Tre ) ;
JButton q u a t t r o=new JButton ( Quattro ) ;
JButton c i n q u e = new JButton ( Cinque ) ;
public MyFrame ( )
{
super ( Flow Layout ) ;
C o n t a i n e r c = t h i s . getContentPane ( ) ;
c . s e t L a y o u t (new FlowLayout ( ) ) ;
c . add ( uno ) ;
c . add ( due ) ;
c . add ( t r e ) ;
c . add ( q u a t t r o ) ;
c . add ( c i n q u e ) ;
setSize (300 ,100);
s e t V i s i b l e ( true ) ;
}
}
public c l a s s A p p l i c a t i o n
{
public s t a t i c void main ( S t r i n g a r g s [ ] )
{
MyFrame = new MyFrame ( ) ;
}
}
6 Layout Management
16
6 Layout Management
17
6 Layout Management
18
public MyFrame ( )
{
super ( Border Layout ) ;
C o n t a i n e r c = t h i s . getContentPane ( ) ;
c . s e t L a y o u t (new BorderLayout ( ) ) ;
c . add ( nord , BorderLayout .NORTH) ;
c . add ( c e n t r o , BorderLayout .CENTER) ;
c . add ( o v e s t , BorderLayout .WEST) ;
setSize (300 ,300);
s e t V i s i b l e ( true ) ;
}
6 Layout Management
19
6 Layout Management
20
public c l a s s MyFrame
JButton b1 = new
JButton b2 = new
JButton b3 = new
JButton b4 = new
extends JFrame {
JButton ( uno ) ;
JButton ( n e ssuno ) ;
JButton ( c e n t o m i l a ) ;
JButton ( che a l t r o ?? ) ;
public MyFrame ( ) {
super ( N u l l Layout ) ;
C o n t a i n e r c = t h i s . getContentPane ( ) ;
c . s e t L a y o u t ( null ) ;
Dimension b 1 S i z e=b1 . g e t P r e f e r r e d S i z e ( ) ;
b1 . setBounds ( 1 0 , 1 0 , b 1 S i z e . width , b 1 S i z e . h e i g h t ) ;
Dimension b 2 S i z e=b2 . g e t P r e f e r r e d S i z e ( ) ;
b2 . setBounds (10+ b 1 S i z e . width , 1 0 , b 2 S i z e . width ,
b2Size . height ) ;
Dimension b 3 S i z e=b3 . g e t P r e f e r r e d S i z e ( ) ;
b3 . setBounds (10+ b 1 S i z e . width+b 2 S i z e . width , 1 0 ,
b 3 S i z e . width , b 3 S i z e . h e i g h t ) ;
Dimension b 4 S i z e=b4 . g e t P r e f e r r e d S i z e ( ) ;
b4 . setBounds ( 1 0 , 10+ b 1 S i z e . h e i g h t ,
b 1 S i z e . width+b 2 S i z e . width+b 3 S i z e . width ,
b4Size . height ) ;
c . add ( b1 ) ;
c . add ( b2 ) ;
c . add ( b3 ) ;
c . add ( b4 ) ;
setSize (300 ,300);
s e t V i s i b l e ( true ) ;
}
21
I gestori di layout permettono maggiore versatilit`a nellinserimento dei controlli nelle nestre. Tuttavia nella stragrande maggioranza delle situazioni
unintera nestra non pu`o seguire un unico layout. Si prenda, ad esempio,
in considerazione il frame in Figura 10. Non `e dicile convincersi che la
parte in alto contenente una sorta di tastierino numerico segue un GridLayout mentre i bottoni in basso seguono un FlowLayout centrato. Poich`e
22
altri con loro layout e cos` via, come nel gioco delle scatole cinesi. Il numero
di soluzioni diverse sono praticamente innite.
Ad esempio per il frame in Figura 10 `e possibile creare due contenitoripannelli JPanel: uno per contenere il tastierino numerico organizzato il
GridLayout ed un altro il FlowLayout per i tre bottoni in basso. La lastra
dei Contenuti viene lasciata in BorderLayout: al centro viene aggiunto il
pannello tastierino ed a sud il pannello con i tre bottoni.
7.1
23
JFrame
BorderLayout
nordPnl
FlowLayout
infoLbl
centroPnl
GridLayout (2,1)
sudPnl
FlowLayout
opz1chk opz2chk
okBtn
cancBtn
Un esempio nale viene mostrato per riassumere quanto `e stato nora detto.
Si inizier`a mostrando la progettazione top-down dellinterfaccia e si concludera mostrandone la realizzazione bottom-up. Si consideri la semplice nestra
in Figura 11. Lalbero della GUI corrispondente `e in Figura 12.
Il codice per mostrare tale nestra `e nel Listato 8. Si osservi linvocazione
del metodo pack() che sostituisce il metodo setSize(x,y) e che imposta la
dimensione della nestra alla minima necessaria a visualizzare tutti i controlli. Inoltre si osservi come le due istruzioni successive hanno lo scopo di
centrare la nestra sullo schermo. Il metodo getScreenSize() chiamato
sulla classe Singleton 3 Toolkit del package java.awt restituisce un riferimento
ad un oggetto java.awt.Dimension. Questo possiede due propriet`a Width e
Height che, nel caso specico, conterranno la dimensione dello schermo in
pixel. Listruzione successiva sposta la nestra al centro dello schermo con il
3
24
25
Una nestra di input si ottiene con il seguente metodo statico che ammette
tre forme:
Object show In pu tD ia lo g ( Component parent , Object Message )
Object show In pu tD ia lo g ( Component parent , Object Message ,
S t r i n g t i t l e , int messageType )
Object sh ow Inpu tD ia lo g ( Component parent , Object Message ,
S t r i n g t i t l e , int messageType , I c o n i c o n ,
26
Object [ ] S e l e c t e d V a l u e s , Object i n i t i a l V a l u e )
27
9.1
Il gestore delle nestre pu`o generare un numero enorme di eventi (sono eventi
muovere il mouse nella nestra, spostare o ridimensionare una nestra, scri-
28
La classe evento. Contiene le informazioni riguardanti le caratteristiche dellevento generato. Gli oggetti di questa classe sono istanziati direttamente dai componenti che noticano eventi agli ascoltatori. Formalmente sono parametri di input dei metodi dellinterfaccia implementata
dallascoltatore. Nel momento in cui il componente viene sollecitato, esso chiama gli ascoltatori in modalit`a callback, passando come parametro
della chiamata unapposita sottoclasse di Event. Queste classi contengono tutte le informazioni signicative per levento stesso e possono
essere utilizzate per modicare il comportamento dellascoltatore in
base alle informazioni sullevento scatenato
Le classi che permettono di gestire gli eventi generati dai componenti
Swing sono in gran parte gli stessi utilizzati dai corrispondenti componenti
AWT, e si trovano nel package java.awt.event. Alcuni componenti Swing,
tuttavia, non hanno un omologo componente AWT: in questo caso le classi
necessarie a gestirne gli eventi sono presenti nel package javax.swing.event.
9.2
29
dove MouseEvent `e la corrispondente classe evento il cui scopo `e dare informazioni aggiuntive sullevento del mouse. Infatti, questa denisce due
metodi che permettono di conoscere le coordinate del mouse allo scatenarsi dellevento (i primi due) e un terzo metodo che permette di determinare
quale bottone del mouse `e stato premuto:
int getX ( ) ;
int getY ( ) ;
int g e t M o d i f i e r s ( )
30
import j a v a . awt . e v e n t . ;
import j a v a x . swing . ;
public c l a s s MouseSpy implements M o u s e L i s t e n e r
{
public void mouseClicked ( MouseEvent e ) {
System . out . p r i n t l n
( C l i c k su ( +e . getX ()+ , +e . getY ()+ ) ) ;
}
public void mousePressed ( MouseEvent e ) {
System . out . p r i n t l n
( Premuto su ( +e . getX ()+ , +e . getY ()+ ) ) ;
}
public void mouseReleased ( MouseEvent e ) {
System . out . p r i n t l n
( R i l a s c i a t o su ( +e . getX ()+ , +e . getY ()+ ) )
}
public void mouseEntered ( MouseEvent e ) {}
public void mouseExited ( MouseEvent e ) {}
}
public c l a s s MyFrame extends JFrame
{
public MyFrame ( )
{
super ( MouseTest ) ;
t h i s . addMouseListener (new MouseSpy ( ) ) ;
setSize (200 ,200);
s e t V i s i b l e ( true ) ;
}
}
31
public i n t e r f a c e WindowListener
{
public void windowOpened ( WindowEvent e ) ;
public void windowClosing ( WindowEvent e ) ;
public void windowClosed ( WindowEvent e ) ;
public void w i n d o w I c o n i f i e d ( WindowEvent e ) ;
public void w i n d o w D e i c o n i f i e d ( WindowEvent e ) ;
public void windowActivated ( WindowEvent e ) ;
public void windowDeactivated ( WindowEvent e ) ;
}
9.3
32
10
La maggior parte dei componenti Swing generano eventi, noti come eventi
azione, che possono essere catturati da un ActionListener. Essa denisce un
unico metodo:
public i n t e r f a c e A c t i o n L i s t e n e r
{
public void a c t i o n P e r f o r m e d ( ActionEvent ae ) ;
}
33
11
Lapproccio nora descritto funziona abbastanza bene anche se presenta ancora alcune problematiche. Il primo problema `e legato al fatto che la nestra
e i suoi ascoltatori sono divisi in classi separate. Supponiamo di avere ascoltatori per gestire gli eventi scatenati da alcuni componenti installati in una
data nestra. Essendo le due classi formalmente indipendenti tra loro, per
quanto detto, non `e possibile accedere dagli ascoltatori a tutti i componenti
della nestra (tranne il componente che ha generato levento).
Supponiamo di voler realizzare una nestra come quella in Figura 15.
Alla pressione del bottone OK il contenuto del campo di testo deve essere
visualizzato in un message dialog box. Si consideri il codice nel Listato 14.
Nellascoltatore deniamo un nuovo JTextField text. Questapproccio
non funziona perch`e il campo di testo denito `e un nuovo campo di testo e
non quello della nestra. Quindi la pressione del bottone mostrer`a sempre
una nestra dal contenuto vuoto perch`e di default un campo di testo viene
inizializzato con il contenuto vuoto.
Un primo approccio `e utilizzare una classe interna. Una classe interna
`e denita allinterno di unaltra classe e pu`o accedere a tutte le variabili e
i metodi di istanza della classe esterna (anche a quelli privati). Si consideri
il Listato 15 che fa uso della classi interne: listruzione text = txt nellascoltatore fa s` che il riferimento text punti allo stesso campo di testo
riferito da txt. Quindi quando nel codice successivo, lascoltatore chiede
text.getText() ottiene eettivamente il codice richiesto.
Questa tecnica `e accettabile se lascoltatore esegue poche operazioni e
pochi ascoltatori esistono. Altrimenti la classe MyFrame diventa eccessiva-
34
35
c l a s s L i s t e n implements A c t i o n L i s t e n e r
{
public void a c t i o n P e r f o r m e d ( ActionEvent e ) {
JTextField text = txt ;
JOptionPane . showMessageDialog (
null , t e x t . getText ( ) ) ;
}
}
36
37
12
La tecnica pi`
u naive per gestire pi`
u eventi associati ad un controllo `e quello di
creare una classe ascoltatore per ogni oggetto e per ogni classe di eventi da
gestire per quello oggetto. Ci`o vorrebbe dire che se dovessimo gestire levento
di pressione di X bottoni, dovrebbe realizzare X classi che implementano
ActionListener.
Ovviamente `e nella pratica improponibile prevedere una classe per ogni
bottone, voce del menu e cos` via. Infatti, consideriamo per esempio unapplicazione con 5 nestre, ognuna con 5 bottoni. Supponiamo che una di tali
nestre abbia anche 3 voci del menu di 4 opzioni ciascuno. Ci`o signicherebbe
che avremmo 37 classi solo per gestire la pressione dei bottoni o della voci
del menu!
Lidea pi`
u elegante `e raggruppare gli oggetti su cui ascoltare in classi,
prevedendo un ascoltatore condiviso per tutti gli oggetti della stessa classe.
Da questo punto in poi consideriamo solo gli eventi actionListener senza
perdere di generalit`a. Lo stesso approccio si applica in tutti gli altri casi. I
componenti della stessa classe, ovviamente, condivideranno lo stesso metodo
actionPerformed. A meno che tutti i componenti della stessa classe si devo
comportare nello stesso modo allo scatenarsi dellevento azione, occore essere
in grado di capire quale oggetto ha generato levento. Questo al ne di
capire quale comportamente adottare.
Esistono due modi per capire chi ha generato levento:
1. Attraverso il metodo getSource() della classe ActionEvent che restituisce un riferimento alloggetto che ha scatenato levento. In questo
38
39
modo `e possibile utilizzare un approccio di tipo switch/case: se il riferimento punta a X, allora chiama un metodo privato che corrisponde
alla gestione di pressione del bottone X; se il riferimento punta a Y,
allora chiama il metodo per Y. E cosi via. E ovviamente chiaro se questa approccio `e fattibile se `e possibile confrontare i riferimenti ottenuti
con il metodo getSource() con i riferimenti memorizzati internamente
alla classe che estende JFrame e che disegna la nestra con i bottoni
X, Y e gli altri. Questo approccio `e generalmente fattibile, quindi, con
le classi interne.
2. Utilizzando la propriet`a actionCommand, implementata per ogni componente, che permette di associare una stringa identicativa univoca
ad ogni componente che scatena un evento azione. A questo punto `e
possibile denire allinterno del metodo actionPerformed un approccio di tipo switch/case sugli actionCommand. Se lo actionCommand
delloggetto `e ACTX (che `e stato associato ad X) allora lascoltatore
esegue una certa porzione di codice, se lo actionCommand `e ACTY fa
unaltra cosa. E cos` via. In questo nuovo contesto non `e pi`
u necessario
per lascoltatore di avere accesso ai riferimenti.
Si consideri, ad esempio, la porzione di condice nel Listato 17 dove ci
sono tre voci di menu UpOpt, DownOpt, RandomOpt. Le tre voci del menu
hanno associati lo stesso ascoltatore con lo stesso metodo actionPerformed.
Allinterno del metodo la discriminazione su come lascoltatore si deve comportare in funzione del metodo invocato `e fatto analizzando i riferimenti.
Listruzione src=e.getSource() restituisce un riferimento alloggetto che
ha generato levento. Se tale riferimento `e uguale a UpOpt (entrambi puntano allo stesso oggetto corrispondente alla voce del menu Up, allora la
voce del menu scelta `e Up. Quindi viene eseguita la porzione di codice relativa a tale voce. Lo stesso per le altre voci. Lascoltatore `e realizzato come
classe interna in modo tale da poter realizzare luguaglianza tra i puntato e
vericare se coincidono.
Come si `e detto, lapproccio con le classi interne ha molti svantaggi. la
metodologia che vogliamo qui introdurre per capire chi ha generato levento
non deve assumere classi interne e, quindi, non pu`o basarsi sulluguaglianza
tra puntatori.
Quando si usano classi esterne, `e possibile capire il componente che ha
noticato levento associando ai diversi componenti un diverso valore della
propriet`a actionCommand.
Nellesempio nel Listato 18 i possibili valori per le propriet`a actionCommand sono memorizzate come costanti stringa, cio`e public final static,
della classe ascoltatore Listener. Ad ogni oggetto da predisporre per gestire
c l a s s L i s t e n e r implements A c t i o n L i s t e n e r
{
public void a c t i o n P e r f o r m e d ( ActionEvent e )
{
Object s r c = e . g e t S o u r c e ( ) ;
i f ( s r c == UpOpt)
{ c o d i c e d e l l a voce d e l menu Up }
e l s e i f ( s r c == DownOpt)
{ c o d i c e d e l l a voce d e l menu Down }
e l s e i f ( s r c == RandomOpt )
{ c o d i c e d e l l a voce d e l menu Random }
}
}
40
41
gli eventi azione viene associato un valore per la actionCommand presi tra
tali costanti stringa. Questo viene fatto grazie al metodo
void setActionCommand ( S t r i n g ) ;
Il metodo actionPerformed dellactionListener legge il valore della propriet`a actionCommand del componente che ha noticato levento e, in funzione
del valore letto, sceglie la porzione di codice da eseguire. Eventualmente `e
possibile associare lo stesso actionCommand a componenti gestiti dallo stesso ascoltatore se si desidera che questi gestiscano levento azione nello stesso
modo. Questo cosa `e molto utile quando si desidera replicare la voce di un
dato menu con un bottone da inserire nella toolbar della nestra: per fare s`
che sia la voce del menu che il bottone nella toolbar gestiscano levento nello
stesso modo `e suciente associare ad entrambi lo stesso actionCommand.
Torniamo indietro a considerare la nestra descritta nel Listato 18. Il suo
scheletro `e nel Listato 19. Si possono osservare sempre tre parti in questo
tipo di ascoltatori:
La parte che denisce le costanti stringa (le tre dichiarazioni di oggetti
pubblici, costanti4 e statici)
4
In Java `e possibile denire che il valore di un riferimento non pu`o cambiare dichiarandolo final. Questo ovviamente non `e suciente per dichiarare un oggetto costante. Tuttavia nel caso di oggetti String le due cose coincidono dato che gli oggetti stringa sono
42
public c l a s s L i s t e n e r implements A c t i o n L i s t e n e r
{
public f i n a l s t a t i c S t r i n g UPOPT = up ;
public f i n a l s t a t i c S t r i n g DOWNOPT = down ;
public f i n a l s t a t i c S t r i n g RANDOMOPT = random ;
public void a c t i o n P e r f o r m e d ( ActionEvent e )
{
S t r i n g com = e . getActionCommand ( ) ;
i f ( com == UPOPT)
upOpt ( ) ;
e l s e i f ( s r c == DOWNOPT)
downOpt ( ) ;
e l s e i f ( s r c == RANDOMOPT)
randomOpt ( ) ;
}
private void upOpt ( )
{ ... }
private void randomOpt ( )
{ ... }
13
43
Si ottiene la modalit`a di accesso package quando la descrizione del tipo delle variabili
distanza non `e preceduta da nessuna modalit`a di accesso: public, private o protected.
parent
Message
title
messageType
44
optionType
icon
SelectedValues
initialValue
45