Dispensa_JavaSwing_v2011

download Dispensa_JavaSwing_v2011

of 46

Transcript of Dispensa_JavaSwing_v2011

  • 7/23/2019 Dispensa_JavaSwing_v2011

    1/46

    SAPIENZA Universita di Roma

    Facolta di Ingegneria dellInformazione,Informatica e Statistica

    Corso di Laurea in Ingegneria Informatica edAutomatica

    Corso di Laurea in Ingegneria dei SistemiInformatici

    Dispensa didattica

    Sviluppo di Interfacce Grafiche inJava. Concetti di Base ed Esempi.

    Versione di Marzo 2011.

    M. de Leoni, M. Mecella, S. Saltarelli

  • 7/23/2019 Dispensa_JavaSwing_v2011

    2/46

    Creative Commons License Deed

    Attribuzione - Non commerciale - Non opere derivate

    2.5 Italia

    Tu sei libero:

    di riprodurre, distribuire, comunicare al pubblico, esporre in pubblico,rappresentare, eseguire e recitare questa opera

    Alle seguenti condizioni:

    Attribuzione. Devi attribuire la paternita dellopera nei modi indicati dallau-tore o da chi ti ha dato lopera in licenza.

    Non commerciale. Non puoi usare questa opera per fini commerciali.

    Non opere derivate. Non puoi alterare o trasformare questopera, n usarla percrearne unaltra.

    Ogni volta che usi o distribuisci questa opera, devi farlo secondo i termini diquesta licenza, che va comunicata con chiarezza.In ogni caso, puoi concordare col titolare dei diritti dautore utilizzi di quest-opera non consentiti da questa licenza.Niente in questa licenza indebolisce o restringe i diritti degli autori.

    Le utilizzazioni consentite dalla legge sul diritto dautore e glialtri diritti non sono in alcun modo limitati da quanto sopra.

    Questo e un riassunto in linguaggio accessibile a tutti del Codice Legale(la licenza integrale) disponibile allindirizzo:

    http://creativecommons.org/licenses/by-nc-nd/2.5/it/legalcode.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    3/46

    2

    Indice

    1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Il package Swing . . . . . . . . . . . . . . . . . . . . . . . . . 33 Top Level Container . . . . . . . . . . . . . . . . . . . . . . . 54 Paranoramica di alcuni widget . . . . . . . . . . . . . . . . . . 85 Lereditarieta per personalizzare i frame . . . . . . . . . . . . 116 Layout Management . . . . . . . . . . . . . . . . . . . . . . . 137 Progettazione della GUI con le gerarchie di contenimento . . . 217.1 Progettazione top down di interfacce grafiche . . . . . . . . . . 22

    7.1.1 Esempio di Progettazione Top-Down . . . . . . . . . . 23

    8 Realizzare finestre di dialogo con JOptionPane . . . . . . . . . 259 La Gestione degli Eventi . . . . . . . . . . . . . . . . . . . . . 279.1 Implementazione dellevent delegation . . . . . . . . . . . . . . 279.2 Un esempio: elaborare gli eventi del mouse . . . . . . . . . . . 299.3 Uso di adapter nella definizione degli ascoltatori . . . . . . . . 3110 La gestione degli eventi Azione . . . . . . . . . . . . . . . . . 3211 Accedere dallascoltatore agli oggetti di una finestra . . . . . . 3312 Condividere gli ascoltatori per piu oggetti . . . . . . . . . . . 3713 Conclusioni e Commenti Finali . . . . . . . . . . . . . . . . . 43

  • 7/23/2019 Dispensa_JavaSwing_v2011

    4/46

    1 Introduzione 3

    1 Introduzione

    Uno dei problemi piu grossi emersi durante la progettazione di Java fu sen-za dubbio la realizzazione di un toolkit grafico capace di funzionare conprestazioni di buon livello su piattaforme molto differenti tra loro. La soluzioneadottata nel 1996 fu AWT(Abstract Window Toolkit), un package graficoche mappa i componenti del sistema ospite con apposite classi dette peer,scritte in gran parte in codice nativo. In pratica, ogni volta che il program-matore crea un componente AWT e lo inserisce in uninterfaccia grafica, ilsistema AWT posiziona sullo schermo un oggetto grafico della piattaforma os-pite, e si occupa di inoltrare ad esso tutte le chiamate a metodo effettuate sul-

    loggetto Java corrispondente, ricorrendo a procedure scritte in buona partein codice nativo; nel contempo, ogni volta che lutente manipola un elementodellinterfaccia grafica, unapposita routine (scritta sempre in codice nativo)crea un apposito oggetto Event e lo inoltra al corrispondente oggetto Java,in modo da permettere al programmatore di gestire il dialogo con il compo-nente e le azioni dellutente con una sintassi completamente Object Orientede indipendente dal sistema sottostante.

    A causa di questa scelta progettuale, il set di componenti grafici AWTcomprende solamente quel limitato insieme di controlli grafici che costituis-cono il minimo comune denominatore tra tutti i sistemi a finestre esistenti:un grosso limite rispetto alle reali esigenze dei programmatori. In secondo lu-ogo, questa architettura presenta un grave inconveniente: i programmi graficiAWT assumono un aspetto ed un comportamento differente a seconda dellaJVM su cui vengono eseguite, a causa delle macroscopiche differenze imple-mentative esistenti tra le versioni di uno stesso componente presenti nellediverse piattaforme. Spesso le interfacce grafiche realizzate su una partico-lare piattaforma mostrano grossi difetti se eseguite su un sistema differente,arrivando in casi estremi a risultare inutilizzabili.

    Il motto della Sun per Java era scrivi (il codice) una volta sola ed eseguiloovunque; nel caso di AWT questo si era trasformato in scrivi una volta solae correggilo ovunque.

    2 Il package Swing

    Nel 1998, con luscita del JDK 1.2, venne introdotto il package Swing, icui componenti erano stati realizzati completamente in Java, ricorrendo uni-camente alle primitive di disegno piu semplici, tipo traccia una linea odisegna un cerchio, accessibili attraverso i metodi delloggetto Graphics,un oggetto AWT utilizzato dai componenti Swing per interfacciarsi con la

  • 7/23/2019 Dispensa_JavaSwing_v2011

    5/46

    2 Il package Swing 4

    Component

    Container

    Window

    JComponent

    Panel

    JAppletJFrame

    JDialog

    java.awt

    javax.swing

    JPanel

    Component

    Container

    Window

    JComponent

    Panel

    JAppletJFrame

    JDialog

    java.awt

    javax.swing

    JPanel

    Fig. 1: Diagramma UML di base del package Swing.

    piattaforma ospite. Le primitive di disegno sono le stesse su tutti i sistemigrafici, e il loro utilizzo non presenta sorprese: il codice java che disegna unpulsante Swing sullo schermo di un PC produrra lo stesso identico risultatosu un Mac o su un sistema Linux. Questa architettura risolve alla radice iproblemi di uniformita visuale, visto che la stessa identica libreria viene orautilizzata, senza alcuna modifca, su qualunque JVM. Liberi dal vincolo delminimo comune denominatore, i progettisti di Swing hanno scelto di per-correre la via opposta, creando un package ricco di componenti e funzionalitaspesso non presenti nella piattaforma ospite. Il procedimento di disegno eovviamente piu lento perche la JVM deve disegnare per proprio conto tuttele linee degli oggetti grafici e gestirne direttamente il comportamento, peroe piu coerente.

    Le classi Swing sono definite nel pacchetto javax.swing, il cui nomejavaxindica estensione standard a Java. Inizialmente Swing venne rilasciato, in-fatti, come estensione per poi divenire un omponente standad di Java 2. Per

    motivi di compatibilita il nome del pacchetto javax non venne corretto injava. Gli oggetti grafici Swing derivano dai corrispettivi AWT; quindi e pos-sibile utilizzare oggetti Swing, ove erano previsti i oggetti antenati. Swingusa ancora alcuni elementi AWT per disegnare; anche la gestione degli eventie fatta per la maggior parte da classi AWT.

    La Figura 1 riassume molto sinteticamente le classi base del packageSwing e come queste derivino da classi AWT. Ogni oggetto grafico (unafinestra, un bottone, un campo di testo, . . . ) e implementato come classedel packagejavax.swing. Ogni classe che identifica un oggetto Swing deriva

  • 7/23/2019 Dispensa_JavaSwing_v2011

    6/46

    3 Top Level Container 5

    per lo piu dalla classe javax.swing.JComponent; si stima che esistono circa 70

    o piu oggetti diversi. Gli oggetti grafici utilizzati per disegnare le interfaccevengono chiamati anche controlli oppure tecnicamente widget. JComponenteredita da java.awt.Container, una sorta di controllo che di default e vuotoe il cui scopo e offrire la possibilita di disporre altri componenti allinterno.Non a caso la classe AWT Windowe le sottoclassi Swing JFramee JDialog, lecui istanze rappresentano finestre, sono sottoclasse di Container. La cosa piusorprendente e che, siccome JComponent deriva da Container, e possibile in-serire allinterno di un qualsiasi widget qualsiasi altro. Ad esempio - sebbenepoco utile - e possibile aggiungere un campo di testo allinterno di un bottoneoppure - molto usato - un Container allinterno di un altro Container. La

    classe Container (e ogni sottoclasse) definisce un metodo per aggiungere uncontrollo ad un Container:

    void add(Component );

    Il metodo prende come parametro un oggetto Componentche e la superclassedi qualsiasi oggetto o container Swing o AWT.

    3 Top Level Container

    I top level container sono i componenti allinterno dei quali si creano le

    interfacce grafiche: ogni programma grafico ne possiede almeno uno, di solitoun JFrame, che rappresenta la finestra principale. Ogni top level containerpossiede un pannello (accessibile tramite il metodo getContentPane()) al-linterno del quale vanno disposti i controlli dellinterfaccia grafca. Esistonotre tipi principali di top level Container: JFrame, JApplet e JDialog. Ilprimo viene solitamente usato come finestra principale per il programma, ilsecondo e utilizzato per costruire Applet da visualizzare nella finestra di unweb browser mentre il terzo serve a creare le finestre di dialogo con lutente.

    In questa dispensa ci si focalizzera solamente sui JFrame. Un oggettodella classe JFrame puo essere creato usando i costruttori:

    JFrame ( ) ;JFrame ( S t r i n g t i t o l o F i n e s t r a ) ;

    Il primo costruisce un JFrame senza titolo; il secondo permette di specificarlo.E sempre possibile impostare il titolo ricorrendo al metodo

    setTitle(String s). Due importanti proprieta delloggetto sono la dimen-sione e la posizione, che possono essere impostate sia specificando le singolecomponenti sia mediante oggetti Dimensione Pointdel package AWT:

    public void s e t S i z e ( D im en si on d ) ;public void s e t S i z e ( i n t width ,i n t h e i g h t ) ;

  • 7/23/2019 Dispensa_JavaSwing_v2011

    7/46

    3 Top Level Container 6

    Fig. 2: Anatomia di un Frame Swing.

    public void s e t L o c a t i o n ( P o i nt p ) ;public void s e t L o c a t i o n ( i n t x ,i n t y ) ;

    Ricorrendo al metodo setResizable(boolean b) e possibile stabilire sesi vuole permettere allutente di ridimensionare la finestra manualmente.Infine, vi sono tre metodi piuttosto importanti:

    public void p ac k ( ) ;public void s e t V i s i b l e ( boolean b ) ;public void s e t D e f a u l t C l o s e O p e r a t i o n ( i n t o p e r a t i o n ) ;

    Il primo ridimensiona la finestra tenendo conto delle dimensioni ottimali diciascuno dei componenti presenti allinterno. Il secondo permette di visualiz-zare o di nascondere la finestra. Il terzo imposta lazione da eseguire alla pres-

    sione del bottone close, con quattro impostazioni disponibili:JFrame.DO NOTHING ON CLOSE (nessun effetto), JFrame.HIDE ON CLOSE(nasconde la finestra),JFrame.DISPOSE ON CLOSE(chiude la finestra e liberale risorse di sistema) e JFrame.EXIT ON CLOSE(chiude la finestra e concludelesecuzione del programma).

    Per impostazione di default, un JFrame viene costruito non visibile e didimensione 0 x 0. Per questa ragione, affinche la finestra sia visibile, e nec-essario chiamare i metodisetSize()opack()per specificare la dimensione emettere atrue la proprieta Visible chiamando il metodo: setVisible(true).

    Per poter lavorare con i Frame Swing, e opportuno conoscere il linea

    generale la struttura della superficie. La superficie di un frame Swing ecoperta da quattro lastre:

    Glass Pane La lastra di vetro e nascosta di default ed ha il compito di cat-turare gli eventi di input sulla finestra. Normalmente e completamentetrasparente a meno che venga implementato il metodopaintComponentdel GlassPane. Poiche e davanti a tutte le altre, qualsiasi oggettodisegnato su questa lastra nasconde qualsiasi altro disegnato sulle altre

  • 7/23/2019 Dispensa_JavaSwing_v2011

    8/46

    3 Top Level Container 7

    import jav ax . swing . ;

    import ja va . awt . ;

    p ub li c c l a s s A p p l i c a t i o n {p ub li c s t a t i c v oid m ai n ( S t r i n g a r g s [ ] ){

    JFrame win ;win = new J Fr ame ( P ri ma f i n e s t r a ) ;C o n t a i n e r c = w in . g e t Co n t en t P a ne ( ) ;c . add (new J L a b e l ( B uona L e z i o n e ) ) ;w in . s e t S i z e ( 2 0 0 , 2 0 0 ) ;win . set De fa ul tC lo se Op er at io n (JFrame .EXIT ON CLOSE ) ;

    w in . s e t V i s i b l e ( true) ;}

    }

    Listato 1: La prima finestra

    Content Pane Lalastra dei contenuti e la piu importante perche e quella cheospita i componenti che volete visualizzare nella finestra e la maggiorparte dei programmatori Java lavora solo su questa

    Layered Pane Contiene la lastra dei contenuti ed eventualmente i menu. Imenu, infatti, non vengono mai aggiunti al Content Pane ma a questalastra.

    Root Pane La lastra radice ospita la lastra di vetro insieme con la lastra deicontenuti e i bordi della finestra.

    Per maggiori dettagli si faccia riferimento a http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html.

    Quindi, un componente, quale un pulsante, unimmagine o altro, nonviene aggiunto direttamente alla finestra ma alla lastra dei contenuti. Di

    conseguenza, occorre per prima cosa procurarsi un riferimento alloggettoContentPane, mediante la chiamata al metodo:

    public C o n t a i n e r g e t Co n t en t P a ne ( ) ;

    Come era da aspettarsi, il ContentPane e un Container perche predispostoa contenere altri componenti. A questo punto, come per ogni altro Container,e possibile aggiungere ad esso un componente con il metodoaddgia descritto.

    A questo punto e possibile disegnare la prima finestra. Il codice descrittonel Listato 1 mostra la finestra in Figura 3.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    9/46

    4 Paranoramica di alcuni widget 8

    Fig. 3: La prima finestra.

    4 Paranoramica di alcuni widget

    I nomi delle classi per la maggior parte dei componenti dellinterfaccia utenteSwing 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 occorrefornirne lampiezza, cioe il numero approssimato di caratteri che vi aspettateverranno inseriti dallutente.

    J T e x tF i e l d x F i e l d=new J T e x tF i e l d ( 5 ) ;

    Gli utenti possono digitare anche un numero maggiore di caratteri ma sempre5 contemporaneamente saranno vicini: i 5 attorno alla posizione del cursorenel campo.

    Sarebbe opportuno etichettare ciascun campo di testo in modo che lu-tente sappia cosa scriverci. Ogni etichetta e un oggetto di tipo JLabelche viene costruito, sfruttando il costruttore con un parametro stringa; taleparametro rappresenta il testo delletichetta:

    J L ab e l x F i e l d=new J L ab e l ( x = ) ;

    Inoltre vorrete dare allutente la possibilita di inserire informazione in tuttii campi di testo prima di elaborarli per cui avete bisogno di un pulsante chelutente possa premere per segnalare che i dati sono pronti per essere elab-orati. Un pulsante e un oggetto JButton che puo essere costruito fornendouna stringa che fungero da etichetta, unimmagine come icona o entrambe

    JButton moveButton=new JButton ( Move ) ;JButton moveButton=

    new JButton(new ImageIcon( hand . g i f ) ) ;

  • 7/23/2019 Dispensa_JavaSwing_v2011

    10/46

    4 Paranoramica di alcuni widget 9

    Fig. 4: Alcuni Bottoni delle Swing.

    JButton moveButton=new JButton(Move ,new ImageIcon( hand . gi f ) ) ;

    JCheckBox e una sottoclasse di JButton che crea caselle di controllo,con un aspetto simile a quello delle caselle di spunta dei questionari. Ilsuo funzionamento e analogo a quello della superclasse, ma di fatto tende aessere utilizzato in contesti in cui si offre allutente la possibilita di scegliereuna o piu opzioni tra un insieme, come avviene per esempio nei pannelli dicontrollo. I costruttori disponibili sono gli stessi della superclasse, quindi nonsara necessario ripetere quanto e stato gia detto.

    JCheckBox che ck1=new JCheckBox ( JCheck ) ;

    JRadioButtone una sottoclasse di JButton, dotata dei medesimi costrut-tori. Questo tipo di controllo, chiamato pulsante di opzione, viene usatotipicamente per fornire allutente la possibilita di operare una scelta traun insieme di possibilita, in contesti nei quali unopzione esclude laltra. Icostruttori disponibili sono gli stessi della superclasse. Per implementare ilcomportamento di mutua esclusione, e necessario registrare i JRadioButtonche costituiscono linsieme presso unistanza della classe ButtonGroup, come

    viene mostrato nelle righe seguenti:J RadioB utton radioB u tton1=new JRadioButton ( R1 ) ;J RadioB utton radioB u tton2=new JRadioButton ( R2 ) ;J RadioB utton radioB u tton2=new JRadioButton ( R3 ) ;ButtonGroup group = new ButtonGroup ();group . add ( rad ioBu tto n1 ) ;group . add ( rad ioBu tto n2 ) ;group . add ( rad ioBu tto n3 ) ;

  • 7/23/2019 Dispensa_JavaSwing_v2011

    11/46

    4 Paranoramica di alcuni widget 10

    import jav ax . swing . ;

    import ja va . awt . ;

    p ub li c c l a s s A p p l i c a t i o n {p ub li c s t a t i c v oid m ai n ( S t r i n g a r g s [ ] ){

    JFrame win ;win = new JFrame ( Esempio di JComboBox ) ;S t ri n g l i s t a [ ]=new S t ri n g [ 1 0 ] ;f o r ( i n t 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 = w in . g e t Co n t en t P a ne ( ) ;c . add( cBox );w in . s e t S i z e ( 2 0 0 , 2 0 0 ) ;win . set De fa ul tC lo se Op er at io n (JFrame .EXIT ON CLOSE ) ;w in . s e t V i s i b l e ( true) ;

    }}

    Listato 2: Esempio di uso dei ComboBox

    Ogni volta che lutente attiva uno dei pulsanti registrati presso ilButtonGroup,gli altri vengono automaticamente messi a riposo.

    I JComboBox offrono allutente la possibilita di effettuare una scelta apartire da un elenco elementi, anche molto lungo. A riposo il componentesi presenta come un pulsante, con letichetta corrispondente al valore at-tualmente selezionato. Un clic del mouse provoca la comparsa di un menuprovvisto di barra laterale di scorrimento, che mostra le opzioni disponibili.Se si imposta la proprieta editable di un JComboBox a true esso si com-portera a riposo come un JTextField, permettendo allutente di inserire valorinon presenti nella lista. E possibile creare un JComboBox usando i seguenticostruttori:

    JComboBox ( ) ;JComboBox( Objec t [ ] ite ms );

    Il secondo costruttore permette di inizializzare il componente con unalista di elementi di qualsiasi tipo (ad esempio String). Se viene aggiuntoal ComboBox un oggetto generico (ad esempio un oggetto Libro), allora ilvalore corrispondente visualizzato nella lista delle opzioni e quello ottenutochiamando sulloggetto il metodo toString(). Quindi se si desidera aggiun-gere oggetti generici (magari definiti allinterno del programma), bisognera

  • 7/23/2019 Dispensa_JavaSwing_v2011

    12/46

    5 Lereditarieta per personalizzare i frame 11

    Fig. 5: Uso di ComboBox.

    avere la cura di ridefinire tale metodo. Un gruppo di metodi permette diaggiungere, togliere o manipolare gli elementi dellelenco, cos come si fa conun Vector:

    public void a dd It em ( O b j e c t a n O b je c t ) ;public void r e mo v eI te m ( O b j e c t a n O b je c t )

    public void removeItemAt( i n t anIndex ) ;public void r e m o v e A l lI t e m s ( ) ;public O b j ec t g e t It e m At ( i n t i n d e x ) ;p ub l ic i n t getItemCount ( ) ;public void i n s e r t I t e m A t ( O b j e c t a n Ob j ec t , i n t ind ex )

    Per ottenere lelemento correntemente selezionato, e disponibile il metodo:

    public O bj ec t g e t S e l e c t e d I t e m ( ) ;

    La Figura 5 mostra un esempio di suo uso. Il Listato 2 rappresenta il codicecorrispondente.

    5 Lereditarieta per personalizzare i frame

    Aggiungendo ad un frame molti componenti dellinterfaccia utente, il framestesso puo diventare abbastanza complesso: per frame che contengono molticomponenti e opportuno utilizzare lereditarieta. Infatti, se il software che sista sviluppando contiene molte finestre ricche di componenti ci si troverebbea dover fronteggiare una soluzione il cui caso limite e di un metodo mainchecontiene la definizione di tutte le finestre del programma. Senza arrivare a

  • 7/23/2019 Dispensa_JavaSwing_v2011

    13/46

    5 Lereditarieta per personalizzare i frame 12

    import jav ax . swing . ;

    import ja va . awt . ;

    c l a s s MyFrame extends JFrame{

    J La b el j l = new J L a b e l ( Buona L e z i o n e ) ;public MyFrame(){

    super ( Prima f i n e s t r a ) ;C o nt a in e r c = t h i s. getContentPane ( ) ;c . add( j l ) ;t h i s. s e t S i z e ( 2 0 0 , 2 0 0 ) ;

    t h i s . s et Def aul tCl os e Ope rat io n (J Frame. EXIT ON CLOSE) ;t h i s. s e t V i s i b l e ( true) ;

    }}

    p ub li c c l a s s A p p l i c a t i o n{

    p ub li c s t a t i c v oid m ai n ( S t r i n g a r g s [ ] ){

    MyFrame = new MyFrame ( ) ;}

    }

    Listato 3: Esempio con lereditarieta

    questa situazione, si otterrebbero moduli sono molto accoppiati e poco co-esi; inoltre, gli stessi moduli sarebbero poco leggibili e non sarebbe facilemanutenerli. In parole povere, non si sfrutterebbe le potenzialita dellOb-ject Orientation: non sarebbe possibile permette linformation hiding deicontenuti dei frame e dei controlli in essi contenuti; non sarebbe nemmenosfruttato lincapsulamento delle implementazione, mettendo insieme concetti

    eterogenei e finestre diverse tra loro.Il Listato 3 produce la stessa finestra in Figura 3 sfruttando lereditarieta.

    La differenza rispetto agli esempi gia visti non e da poco: a questo punto ognifinestra diventa una nuova classe che, ereditando da JFrame, e un modelloper le finestre. E opportuno definire gli oggetti che mappano i widgets comevariabili di instanza (nel lesempio lunico widget e una etichetta (JLabel). Ladefinizione della finestra e dei componenti contenuti viene fatta direttamentenel costruttore (o in metodo chiamati da questo). La prima istruzione chia-ma il costruttore della superclasse che prende come parametro una stringa;

  • 7/23/2019 Dispensa_JavaSwing_v2011

    14/46

    6 Layout Management 13

    in questo modo e possibile impostare il titolo della finestra. Infatti, se non

    fosse stato esplicitamente chiamato il costruttore ad un parametro String,sarebbe stato chiamato implicitamente il costruttore della superclasse di de-fault (quello senza parametri) prima di continuare lesecuzione di quello dellaclasse derivata. Il costruttore senza parametri avrebbe impostato a vuoto iltitolo della finestra.1 Il resto del costruttore e simile alla tecnica di definizionedelle finestre degli esempi precedenti con lunica differenza che i metodi sonochiamati su this (cioe se stesso) perche a questo punto i metodi da chiamaresono quelli ereditati dalla superclasse JFrame.

    6 Layout Management

    Quando si dispongono i componenti allinterno di un Container sorge il prob-lema di come gestire il posizionamento: infatti, sebbene sia possibile specifi-care le coordinate assolute di ogni elemento dellinterfaccia, queste possonocambiare nel corso della vita del programma allorquando la finestra principalevenga ridimensionata. In molti Container i controlli sono inseriti da sinistraverso destra con su una ipotetica riga: puo non essere sempre la politica perla GUI (Graphic User Interface) desiderata. Per semplificare il lavoro di im-paginazione e risolvere questo tipo di problemi possibile ricorrere ai layoutmanager, 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 epossibile assegnare il piu opportuno per quel Container con il metodo:

    public void setL ayo ut ( LayoutManager m) ;

    Il primo layout da essere citato e il gestore a scorrimento (Flow Layout)che sono inseriti da sinistra verso destra con la loro Preferred Size, cioe ladimensione minima necessaria a disegnarlo interamente. Usando il paragonecon un editor di testi, ogni controllo rappresenta una parola che ha una suapropria dimensione. Come le parole in un editor vengono inseriti da sinistraverso destra finche entrano in una riga, cos viene fatto per i controlli inseritida sinistra verso destra. Quando un componente non entra in una rigaviene posizionato in quella successiva. I costruttori piu importanti di oggettiFlowLayout sono i seguenti:

    public FlowLayout ();public FlowLayout( i n t a l l i n ) ;

    1 A dire il vero, sarebbe stato possibile impostare il titolo della finestra in un secondomomento modificando la proprieta Title: setTitle(Prima Finestra);

  • 7/23/2019 Dispensa_JavaSwing_v2011

    15/46

    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 specifica lallineamento dei controlli su una riga; ilparametro puo essere una delle seguenti costanti che rispettivamente allineanoa sinistra, centro o destra:

    FlowLayout .LEFTFlowLayout .CENTERFlo wLa you t . RIGHT

    Il costruttore di default imposta lallineamento centrale. Il Listato 4 mostraun esempio di uso del Flow Layout. Laspetto del frame risultato e mostratoin Figura 6. E opportuno osservare come lallineamento dei componenti delframe si adatti durante lesecuzione quando la stessa finestra viene ridimen-sionata (vedi situazione 6(b)). Ovviamente se non esiste nessun allineamento

    per i componenti del frame tale che tutti siano contemporaneamente visi-bile, allora alcuni di questi risulteranno in parte o del tutto non visibili; peresempio, la finestra e troppo piccola.

    Il gestore a griglia (GridLayout) suddivide il contenitore in una grigliadi celle di uguali dimensioni. Le dimensioni della griglia vengono definitemediante il costruttore:

    public GridLay out( i n t rows , i n t columns )

    in cui i parametri rows e columns specificano rispettivamente le righe e lecolonne della griglia. A differenza di quanto avviene con FlowLayout, i com-ponenti allinterno della griglia assumono automaticamente la stessa dimen-

    sione, dividendo equamente lo spazio disponibile. Lesempio descritto nelListato 5 permette di illustrare il funzionamento di questo pratico layoutmanager; il risultato e in Figura 7.

    Il gestore a bordi (BorderLayout) suddivide il contenitore esattamentein cinque aree, disposte a croce, come nella Figura 8. Ogni zona puo contenereuno ed un solo widget (o Container): un secondo widget inserito in unazona sostituisce il precedente. Se una o piu zone non vengono riempite,allora i componenti nelle altre zone sono estesi a riempire le zone vuote. Il

  • 7/23/2019 Dispensa_JavaSwing_v2011

    16/46

    6 Layout Management 15

    import jav ax . swing . ;import ja va . awt . ;

    p ub li c c l a s s MyFrame extends JFrame{

    JButton uno=new JButton(Uno );JButton due=new JButton ( Due ) ;

    J Bu tt o n t r e =new J B utton( Tre ) ;J Bu tt o n q u a t t r o=new J B utton( Quattro ) ;J Bu tt o n c i n q u e = new J B utton( Cinque ) ;public MyFrame()

    {super (Flow Layout ) ;C o nt a in e r c = t h i s. getContentPane ( ) ;c . setL ayo ut (new FlowLay out ( ) ) ;c . add( uno ) ;c . add( due ) ;c . add ( tr e ) ;

    c . add ( qua tt ro ) ;c . add ( cin que ) ;s e t S i z e ( 3 0 0 , 1 0 0 ) ;s e t V i s i b l e ( true) ;

    }}

    p ub li c c l a s s A p p l i c a t i o n{

    p ub li c s t a t i c v oid m ai n ( S t r i n g a r g s [ ] )

    {

    MyFrame = new MyFrame ( ) ;}

    }

    Listato 4: Uso del Flow Layout

  • 7/23/2019 Dispensa_JavaSwing_v2011

    17/46

    6 Layout Management 16

    p ub li c c l a s s MyFrame extends JFrame{

    public MyFrame(){

    super ( G r id L ay ou t ) ;C o nt a in e r c = t h i s. getContentPane ( ) ;c . setL ayo ut (new G r id L ay o ut ( 4 , 4 ) ) ;f o r ( i n t i = 0 ; i

  • 7/23/2019 Dispensa_JavaSwing_v2011

    18/46

    6 Layout Management 17

    Fig. 8: Le aree di una disposizione a bordi

    BorderLayout e il gestore di layout di default per la Lastra dei Contenuti diun JFrame.

    Il programmatore puo decidere in quale posizione aggiungere un controlloutilizzando la variante presente nei Container:

    public void add( Component c , St ri ng s ) ;

    dove il primo parametro specifica il componente da aggiungere e il secondoindica la posizione. I valori validi per il secondo parametro sono le costanti:

    BorderLayout .NORTHBorderLayout .SOUTH

    BorderLayout .CENTERBor der Lay out .EASTBorderLayout .WEST

    Si osservi lesempio nel Listato 6.In aggiunta ai layout managers descritti in questa dispensa ne esistono

    ulteriori che sono standard Java: 2

    BoxLayout Questo manager pone i componenti in una singola riga o colonna.Esso rispetta le dimensioni preferite e permette al programmatore didecidere lallineamento

    CardLayout Quando viene utilizzato questo layout manager, il container puocontenere componente differenti in momenti diversi. Per esempio epossibile utilizzare un Combo Box per determinare quale pannello/-container interno viualizzare. In alternativa e possibile utilizzare unJTabbedPane (non descritto in questa dispensa), che fornisce una sim-ile funzionalita utilizzando una interfaccia grafica simile ad un cartelladi un archivio con diverse linguette.

    2 Allindirizzo http://java.sun.com/docs/books/tutorial/uiswing/layout e pos-sibile leggere tutti i dettagli sul loro funzionamento

  • 7/23/2019 Dispensa_JavaSwing_v2011

    19/46

    6 Layout Management 18

    p ub li c c l a s s MyFrame extends JFrame

    {J Bu tt o n n o rd = new JButton ( Nord ) ;J Bu tt on c e n t r o = new J B utton( Centro ) ;J Bu tt o n o v e s t =new J B utton( Ov es t ) ;

    public MyFrame(){

    super ( B o r de r L ay ou t ) ;C o nt a in e r c = t h i s. getContentPane ( ) ;c . setL ayo ut (new B o rd e rL a yo u t ( ) ) ;c . add ( nord , Bor de rL ay ou t .NORTH) ;

    c . add ( ce nt r o , Bord er La yo ut .CENTER) ;c . add ( ove st , Bord erL ayo ut .WEST) ;s e t S i z e ( 3 0 0 , 3 0 0 ) ;s e t V i s i b l e ( true) ;

    }}

    Listato 6: Uso del Border Layout

    GridBagLayout GridBagLayout e un layout manager molto sofisticato. Il suo

    funzionamento e simile al GridLayout ma con la possibilita che certiwidget occupino piu celle della griglia.

    SpringLayout SpringLayout e molto flessibile ed e pensato soprattutto per es-sere utilizzato con tool automatici che permettono al programmatore didisegnare finestra come in un programma di grafica e automaticamentegenerano i codice relativo. Esso permette di specificare precisamentela relazione tra i bordi dei componenti. Ad esempio, e possibile speci-ficare che il bordo sinistro di un componente e ad una certa distanzadal bodo destro di un secondo componente.

    Mentre chiunque puo definire un proprio layout semplicemente implemen-tando linterfaccia LayoutManager, e anche possibile disattivare ogni layoutmanager e utilizzare il cosiddetto posizionamento assoluto.

    Sebbene sia possibile posizionare senza un layout manager, questa soluzionedovrebbe essere evitata quanto piu possibile. Un layout manager rende piusemplice modificare laspetto dei componenti, che puo in parte dipendere dal-la piattaforma ospite, tenendo in conto la dimensione dei fonti, delle finestre.Inoltre i layout manager sono in grado di riorganizzare automaticamente ilriposizionamento dei widget quando la finestra cambia di dimensione.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    20/46

    6 Layout Management 19

    Tuttavia ci sono casi in cui e consigliabile luso di un posizionamento senza

    layout manager poiche laspetto che si desidera ottenere non e facilmenterealizzabile come combinazione di altri layout manager.

    Per aggiungere componenti senza un manager occorre seguire i seguentipassi:

    1. Impostare il layout manager a chiamando:

    mioContainer . s etLay ou t ( n u l l) ;

    2. Per ogni componente che si desidera aggiungere, occorre specificare laposizione in pixel dellangolo superiore sinistro, insieme con la larghezza

    e laltezza desiderata. La posizione in pixel e determinata relativamenteallangolo superiore sinistro del container nel quale si desidera aggiun-gere il componente. Il seguente esempio specifica per il componente b1una posizione a partire dalla coordinata (10,10), una larghezza di 30pixel ed unaltezza di 40:

    b 1 . s e t Bo u n ds ( 1 0 , 1 0 , 3 0 , 4 0 ) ;

    3. Aggiungere ogni componente al container come viene fatto solitamente.

    In generale la posizione e la dimensione non e mai data come valore assolu-

    to ma e sempre parametrica rispetto alle dimensione delle finestre/containere degli altri controlli:

    D im en si on b 1 S i z e=b1 . g e t P r e f e r r e d S i z e ( ) ;b1 . s etB ounds (10 , 10 , b1Si ze . width , b1Si ze . hei ght );D im en si on b 2 S i z e=b2 . g e t P r e f e r r e d S i z e ( ) ;b2 . s etB ounds (10+ b1Si ze . width , 10 , b2S ize . width , b2Si ze . hei ght );

    In questo caso si desidera posizionare il widget b1a partire dalla coordinata(10,10) e farlo di una dimensione pari a quella preferibile. Inoltre, si vuole cheilb2sia affiancato ab1. Di conseguenza, la coordinata x della posizione di b2sara pari a quella di b1 cui viene aggiunta una quantita pari alla dimensione

    di b1.Il Listato 7 mostra un esempio completo delluso di questo layout, il cui

    risultato e mostrato in Figura 9.Comunque, e ancora importante sottolineare che il posizionamento asso-

    luto puo creare problemi quando la finestra viene ridimensionata. Per questaragione nel proseguo di questa dispensa ignoreremo sempre questo layout.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    21/46

    6 Layout Management 20

    p ub li c c l a s s MyFrame extends JFrame {

    J B utton b1 = new J B utton( uno ) ;J B utton b2 = new J Bu tt o n ( n e s s u no ) ;J B utton b3 = new J B u tt o n ( c e n t o m i l a ) ;J B utton b4 = new J Bu tt on ( c h e a l t r o ? ? ) ;

    public MyFrame() {super ( N u l l L ay ou t ) ;C o nt a in e r c = t h i s. getContentPane ( ) ;c . setL ayo ut ( n u l l) ;D im en si on b 1 S i z e=b1 . g e t P r e f e r r e d S i z e ( ) ;b1 . s etB ounds (10 , 10 , b1S ize . width , b1Si ze . hei ght );

    D im en si on 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 1S ize . width , 10 , b2 Siz e . width ,

    b 2 S i z e . h e i g h t ) ;D im en si on 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 1S ize . width+b2Si ze . width , 10 ,

    b 3 S i z e . w id th , b 3 S i z e . h e i g h t ) ;D im en si on 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 1S ize . hei ght ,

    b1 Si ze . width+b2 Si ze . width+b3 Si ze . width ,b 4 S i z e . h e i g h t ) ;

    c . add( b1 ) ;c . add( b2 ) ;c . add( b3 ) ;c . add( b4 ) ;s e t S i z e ( 3 0 0 , 3 0 0 ) ;s e t V i s i b l e ( true) ;

    }}

    Listato 7: Uso del Null Layout

    Fig. 9: Aspetto grafico del frame definito nel Listato 7.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    22/46

    7 Progettazione della GUI con le gerarchie di contenimento 21

    7 Progettazione della GUI con le gerarchie di

    contenimento

    I gestori di layout permettono maggiore versatilita nellinserimento dei con-trolli nelle finestre. Tuttavia nella stragrande maggioranza delle situazioniunintera finestra non puo seguire un unico layout. Si prenda, ad esempio,in considerazione il frame in Figura 10. Non e difficile convincersi che laparte in alto contenente una sorta di tastierino numerico segue un Grid-Layout mentre i bottoni in basso seguono un FlowLayout centrato. Poiche

    Fig. 10: Un frame piu complesso

    ogni Container puo seguire uno ed un unico layout, occorre predisporre piuContainer, uno per ogni zona che ha un layout differente. Ovviamente adogni Container possono essere aggiunti direttamente i controlli oppure altriContainer. La lastra dei contenuti e il Container radice ed altri si possonoaggiungere allinterno. I Container (insieme con i componenti contenuti) ag-giunti in un altro Container si comporteranno come ogni altro widget la cuidimensione preferita e quella minima necessaria a visualizzare tutti i com-ponenti allinterno. Per creare nuovi Container conviene utilizzare la classe

    javax.swing.JPanelche eredita da java.awt.Container.La forza di questa soluzione e data dallalta modularita: e possibile usare

    un layout per il pannello interno e un altro layout per il ContentPane. Ilpannello interno verra inserito nella finestra coerentemente con il layout dellalastra dei contenuti. Inoltre allinterno pannelli interni se ne possono inserire

  • 7/23/2019 Dispensa_JavaSwing_v2011

    23/46

    7 Progettazione della GUI con le gerarchie di contenimento 22

    altri con loro layout e cos via, come nel gioco delle scatole cinesi. Il numero

    di soluzioni diverse sono praticamente infinite.Ad esempio per il frame in Figura 10 e possibile creare due contenitori-

    pannelli JPanel: uno per contenere il tastierino numerico organizzato ilGridLayout ed un altro il FlowLayout per i tre bottoni in basso. La lastradei Contenuti viene lasciata in BorderLayout: al centro viene aggiunto ilpannello tastierino ed a sud il pannello con i tre bottoni.

    7.1 Progettazione top down di interfacce grafiche

    Durante la progettazione delle interfacce grafiche, puo essere utile ricorrere

    a un approccio top down, descrivendo linsieme dei componenti a partiredal componente piu esterno per poi procedere a mano a mano verso quellipiu interni. Si puo sviluppare una GUI come quella dellesempio precedenteseguendo questa procedura:

    1. Si definisce il tipo di top level container su cui si vuole lavorare (tipi-camente un JFrame).

    2. Si assegna un layout manager al content pane del JFrame, in modo dasuddividerne la superficie in aree piu piccole.

    3. Per ogni area messa a disposizione dal layout manager e possibiledefinire un nuovo JPanel. Ogni sotto pannello puo utilizzare un layoutmanager differente.

    4. Ogni pannello identificato nel terzo passaggio puo essere sviluppatoulteriormente, creando al suo interno ulteriori pannelli o disponendodei controlli.

    Il risultato della progettazione puo essere rappresentato con un alberodella GUI. Lobiettivo di tale albero e mostrare come i Container (a partiredalla lastra dei contenuti) sono stati suddivisi per inserire i componenti o

    altri Container.Ogni componente (o Container) e rappresentato da un nodo i cui figli sono

    i componenti (o i Container) contenuti allinterno e il padre e il componenteche lo contiene.

    Una volta conclusa la fase progettuale, si puo passare a scrivere il codicerelativo allinterfaccia: in questo secondo momento, e opportuno adottare unapproccio bottom up, realizzando dapprima il codice relativo ai componentiatomici, quindi quello dei contenitori e infine quello del JFrame.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    24/46

    7 Progettazione della GUI con le gerarchie di contenimento 23

    Fig. 11: Un frame desempio

    JFrameBorderLayout

    nordPnlFlowLayout

    centroPnlGridLayout (2,1)

    sudPnlFlowLayout

    infoLbl opz1chk opz2chk okBtn

    cancBtn

    Fig. 12: Un frame piu complesso

    7.1.1 Esempio di Progettazione Top-Down

    Un esempio finale viene mostrato per riassumere quanto e stato finora detto.Si iniziera mostrando la progettazione top-down dellinterfaccia e si conclud-era mostrandone la realizzazione bottom-up. Si consideri la semplice finestrain Figura 11. Lalbero della GUI corrispondente e in Figura 12.

    Il codice per mostrare tale finestra e nel Listato 8. Si osservi linvocazione

    del metodopack()che sostituisce il metodo setSize(x,y)e che imposta ladimensione della finestra alla minima necessaria a visualizzare tutti i con-trolli. Inoltre si osservi come le due istruzioni successive hanno lo scopo dicentrare la finestra sullo schermo. Il metodo getScreenSize() chiamatosulla classeSingleton3 Toolkitdel package java.awtrestituisce un riferimentoad un oggetto java.awt.Dimension. Questo possiede due proprieta Width eHeight che, nel caso specifico, conterranno la dimensione dello schermo inpixel. Listruzione successiva sposta la finestra al centro dello schermo con il

    3 Una classe Singleton e tale che di essa esista sempre al piu una instanza.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    25/46

    7 Progettazione della GUI con le gerarchie di contenimento 24

    p ub li c c l a s s MyFrame extends JFrame

    {J P a ne l n o r dP n l = new J P a ne l ( ) ;J P an e l c e n t r o P n l = new J P a ne l ( ) ;J P a ne l s u dP n l = new J P a ne l ( ) ;J La be l i n f o L b l = new L a b el ( S e l e z i o n a r e : ) ;

    JCheckBox opz1Chk = new JCheckBox(Opz1 );JCheckBox opz2Chk = new JCheckBox(Opz2 );JButton okBtn=new JButto n ( OK ) ;JButton cancBtn=new J B utton( Annulla ) ;public MyFrame() {

    super ( Esempio ) ;cent roPn l . s etLay o ut (new G r id L ay o ut ( 2 , 1 ) ) ;cen tr oPn l . add ( opz1Chk ) ;cen tr oPn l . add ( opz2Chk ) ;nordPnl . add( in fo Lb l ) ;sudPnl . add( okBtn );

    sudPnl . add ( cancBtn ) ;getCo ntent Pane ( ) . add ( nordPnl , BorderL ayout .NORTH) ;getContentPane () . add( centroP nl ,

    Bo rd er La yo ut .CENTER) ;getCo ntent Pane ( ) . add( sudPnl , BorderLa yout .SOUTH) ;p a ck ( ) ;Dimension dim=

    T o o l k i t . g e t D e f a u l t T o o l k i t ( ) . g e t S c r e e n S i z e ( ) ;s et Lo ca ti on (( dim. getWidth() t h i s. getWidth () )/ 2 ,

    ( d im . g e t H e i g h t ( ) t h i s. g et H e ig h t ( ) ) / 2 ) ;s e t V i s i b l e ( true) ;

    }}

    Listato 8: Il codice della figura 11

  • 7/23/2019 Dispensa_JavaSwing_v2011

    26/46

    8 Realizzare finestre di dialogo con JOptionPane 25

    metodosetLocation(int x,int y)dovex,y sono le coordinate dellangolo

    in alto a sinistra.

    8 Realizzare finestre di dialogo con JOptionPane

    La classe JOptionPane del package Swing permette di realizzare facilmentefinestra modali di input, di allarme o di conferma. Le API di JOptionPanemettono a disposizione tre tipi di pannelli: Confirm, Input e Message Dialog.Il primo viene usato quando si deve chiedere allutente di effettuare una sceltatra un gruppo di possibilita, il secondo torna utile quando si deve richiederelinserimento di una stringa di testo mentre il terzo viene usato per informare

    lutente. La classe JOptionPane fornisce un gruppo di metodi statici chepermetto di creare facilmente queste finestre ricorrendo ad una sola riga dicodice. In questo paragrafo ci si concentrera sulluso di un sottoinsieme ditali metodi, nella convinzione che essi permettano di risolvere la stragrandemaggioranza delle situazioni in modo compatto ed elegante.

    Una finestra di conferma personalizzata si costruisce utilizzando il seguentemetodo statico che ammette due forme:

    i n t s howConfirmDialog (Component parent , Object Mess age)i n t showConfirmD ialog (Component parent , Object Message ,

    S tr in g t i t l e ,i n t optionType , i n t messageType)

    Il metodo restituisce uno dei seguenti valori a seconda se il bottone premutoe rispettivamente Si, No, Annulla, Ok:

    JO pt io nP an e . YES OPTIONJOptionPane .NO OPTIONJO pt io nP an e . CANCEL OPTIONJOptionPane .OK OPTION

    Una finestra di messaggio si costruisce con il seguente metodo statico cheammette due forme:

    void s howMess ageDialog( Component parent , Object Mess age)

    void showMessageDialo g (Component parent , Object Message ,S tr in g t i t l e , i n t messageType)

    Una finestra di input si ottiene con il seguente metodo statico che ammettetre forme:

    Object s howInputDialog (Component parent , Object Mess age)Object s howInputDialog (Component parent , Object Mess age ,

    S tr in g t i t l e , i n t messageType)Object s howInputDialog (Component parent , Object Mess age ,

    S tr in g t i t l e , i n t messageType , Ico n icon ,

  • 7/23/2019 Dispensa_JavaSwing_v2011

    27/46

    8 Realizzare finestre di dialogo con JOptionPane 26

    import ja vax . swing . JOptionPane ;

    p ub li c c l a s s A p p l i c a t i o n{

    p ub li c s t a t i c v oid m ai n ( S t r i n g a r g s [ ] ){

    JOptionPane . showMessageDialog ( null, Ci ao ! , F i n e s t r a d i m e ss a gg i o ,JOptio nP ane . INFORMATION MESSAGE ) ;

    i n t yn=JOptionPane . showC onfi rmDi alog ( null, S a l v ar e l e m o di f ic h e ? , S e l e z i o n e ,JOptionPane .YES NO CANCEL OPTION,

    JO pt io nP an e .QUESTION MESSAGE ) ;i f ( yn==JO pt io nP an e . NO OPTION)

    return ;S t r i n g p ro v a ;prov a=(S tr in g ) J OptionPane . s howInputDialog ( null,

    s t a t o d i r e s i d e n z a : , S e l e z i o n e ,JOptionPane .INFORMATION MESSAGE,null, null, I t a l i a ) ;

    S t r i n g x [ ] ={ a , b , c , d , e , f , g } ;prov a=(S tr in g )J OptionPane . s howInputDialog ( null,

    S c e g l i l o p z i o n e : , S e l e z i o n e ,

    JOptionPane .INFORMATION MESSAGE,null, x , x [ 3 ] ) ;}

    }

    Listato 9: Esempi di uso delle finestre di dialogo

    O bj ec t [ ] S e l e ct e d V a lu e s , O bj ec t i n i t i a l V a l u e )

    Il metodo restituisce la stringa (come Object e quindi su cui e necessario fareil cast) inserita nellInputDialog oppure null se e stato premuto il bottoneannulla. I parametri dei metodi appena illustrati sono descritti in Tabella 1.

    La sezione si conclude con il Listato 9 dove vengono illustrati alcuniesempi di uso delle finestre di dialogo.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    28/46

    9 La Gestione degli Eventi 27

    9 La Gestione degli Eventi

    Fig. 13: La gestione adevent delegation

    La gestione degli eventi grafici in Java segue il paradigma event delegation(conosciuto anche come event forwarding). Ogni oggetto grafico e predispos-to ad essere sollecitato in qualche modo dallutente e ad ogni sollecitazione

    genera eventi che vengono inoltrati ad appositi ascoltatori, che reagisconoagli eventi secondo i desideri del programmatore. Levent delegation presen-ta il vantaggio di separare la sorgente degli eventi dal comportamento a essiassociato: un componente non sa (e non e interessato a sapere) cosa avverraal momento della sua sollecitazione: esso si limita a notificare ai propri as-coltatori che levento che essi attendevano e avvenuto, e questi provvederannoa produrre leffetto desiderato.

    Ogni componente puo avere piu ascoltatori per un determinato eventoo per eventi differenti, come anche e possibile installare uno stesso ascolta-tore su piu componenti anche diversi a patto che entrambi possono esseresollecitati per generare levento. Loperazione di installare lo stesso ascolta-tore su piu controlli (che quindi si comporteranno nello stesso modo se sol-lecitati dallo stesso evento) e frequente: si pensi alle voci di un menu che ven-gono replicate su una toolbar per un piu facile accesso ad alcune funzionalitafrequenti

    9.1 Implementazione dellevent delegation

    Il gestore delle finestre puo generare un numero enorme di eventi (sono eventimuovere il mouse nella finestra, spostare o ridimensionare una finestra, scri-

  • 7/23/2019 Dispensa_JavaSwing_v2011

    29/46

    9 La Gestione degli Eventi 28

    vere o abbandonare un campo di testo, . . . ). Molte volte si e interessati a

    pochi di questi eventi. Per fortuna, il programmatore puo considerare solo glieventi di cui ha interesse, gestendoli con un ascoltatore opportuno, ignoran-do completamente tutti gli altri che di default verranno gestiti come eventivuoti.

    Quando accade un evento per il quale esiste un ricevitore, la sorgente del-levento chiama i metodi da voi forniti nell ricevitore, dando, in un oggetto diunaclasse evento, informazioni piu dettagliate sullevento stesso. In generalesono coinvolte tre classi:

    La classe del ricevitore. Implementa una particolare interfaccia del tipo XXXLis-

    tener tipica degli eventi di una certa classe. I metodi dellinterfacciache la classe dellascoltatore implementa contengono il codice eseguitoallo scatenarsi degli eventi di una classe che lascoltatore intercetta.Grazie al fatto che ogni ascoltatore e caratterizzato da una particolareinterfaccia Java, qualsiasi classe puo comportarsi come un ascoltatore,a patto che fornisca unimplementazione per i metodi definiti dallacorrispondente interfaccia listener

    Lorigine dellevento. E il componente che genera levento che si vuole gestiresu cui si vuole installare lascoltatore. Ogni componente dispone perogni evento supportato di due metodi:

    void a dd XX XL is te ne r ( X XX Li st en er a s c o l t a t o r e ) ;void r em ov eX XX Li st en er ( X XX Li st en er a s c o l t a t o r e ) ;

    La classe evento. Contiene le informazioni riguardanti le caratteristiche del-levento generato. Gli oggetti di questa classe sono istanziati diretta-mente dai componenti che notificano eventi agli ascoltatori. Formal-mente sono parametri di input dei metodi dellinterfaccia implementatadallascoltatore. Nel momento in cui il componente viene sollecitato, es-so chiama gli ascoltatori in modalitacallback, passando come parametrodella chiamata unapposita sottoclasse di Event. Queste classi con-

    tengono tutte le informazioni significative per levento stesso e possonoessere utilizzate per modificare il comportamento dellascoltatore inbase alle informazioni sullevento scatenato

    Le classi che permettono di gestire gli eventi generati dai componentiSwing sono in gran parte gli stessi utilizzati dai corrispondenti componentiAWT, e si trovano nel package java.awt.event. Alcuni componenti Swing,tuttavia, non hanno un omologo componente AWT: in questo caso le classinecessarie a gestirne gli eventi sono presenti nel package javax.swing.event.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    30/46

    9 La Gestione degli Eventi 29

    9.2 Un esempio: elaborare gli eventi del mouse

    Per chiarire il funzionamento, a prima vista complesso, della gestione deglieventi Swing, verra fatto un esempio. In particolare, vogliamo realizzare unmeccanismo per spiare gli eventi del mouse su una finestra e stamparli.

    Una classe che desidera catturare gli eventi del mouse deve implementarelinterfacciaMouseListenerdefinita nel package java.awt.eventche e cos definita:

    p ub l ic i n t e r f a c e M o u s e L i s t e n e r{

    void mous eClick ed( MouseEv ent e ) ;

    void mouseEntered ( MouseEvent e ) ;void mous eEx ited (Mous eEvent e ) ;void mous ePress ed ( MouseEv ent e ) ;void mous eReleas ed (MouseEv ent e ) ;

    }

    dove MouseEvent e la corrispondente classe evento il cui scopo e dare in-formazioni aggiuntive sullevento del mouse. Infatti, questa definisce duemetodi che permettono di conoscere le coordinate del mouse allo scatenar-si dellevento (i primi due) e un terzo metodo che permette di determinarequale bottone del mouse e stato premuto:

    i n t getX ( ) ;i n t getY ( ) ;i n t g e t M o d i f i e r s ( )

    Nel codice del Listato 10 viene mostrata limplementazione della spia.Si noti come la classe ascoltatore MouseSpy implementi linterfacciaMouseListener e come la classe definisca due metodi vuoti: mouseEnterede mouseExited. La definizione dei due metodi vuoti ha lo scopo di dichiarareche gli eventi legati allentrata e alluscita del mouse dallarea della finestradevono essere ignorati. In effetti, ignorare gli eventi e gia il comportamentodi default e quindi tale dichiarazione e superflua. La ragione per cui e stata

    comunque dichiarata la gestione di tali eventi e legata al linguaggio Java:affinche una classe implementi una interfaccia, tale classe deve implentaretutti i metodi dellinterfaccia. E questo vale anche in questo caso: la classeMouseSpy deve implementare tutti i metodi dellinterfaccia MouseListenerper poter dichiarare di implementarla.

    Nella Tabella 2 sono riassunti gli ascoltatori piu importanti. Per ulterioridettagli si consiglia di consultare la documentazione Java Swing.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    31/46

    9 La Gestione degli Eventi 30

    import ja va . awt . event . ;import jav ax . swing . ;

    p ub li c c l a s s MouseSpy implements M o u s e L i s t e n e r{

    p u bl i c v oi d mous eClick ed (Mous eEvent e ) {System . out . pr i nt l n

    ( Cli ck s u (+e . getX()+ ,+e . getY()+ ) );}p u bl i c v oi d mous ePres s ed( MouseEv ent e ) {

    System . out . pr i nt l n( Premuto su ( +e . getX()+ , +e . getY()+) ) ;

    }p u bl i c v oi d mous eReleas ed( MouseEv ent e ) {

    System . out . pr i nt l n( R i l a s c i a t o s u ( +e . g et X () + , +e . g et Y () + ) )

    }p u bl i c v oi d mouseEntered( MouseEvent e ) {}

    p u bl i c v oi d mouseExited ( MouseEvent e ) {}}

    p ub li c c l a s s MyFrame extends JFrame{

    public MyFrame(){

    super ( MouseTest ) ;t h i s. addMous eLis tener (new MouseSpy ());s e t S i z e ( 2 0 0 , 2 0 0 ) ;s e t V i s i b l e ( true) ;

    }}

    Listato 10: Primo esempio della gestione degli eventi

  • 7/23/2019 Dispensa_JavaSwing_v2011

    32/46

    9 La Gestione degli Eventi 31

    p ub l ic i n t e r f a c e WindowListener

    {p u bl i c v oi d windowOpened( WindowEvent e ) ;p u bl i c v oi d windowClosing (WindowEvent e ) ;p u bl i c v oi d windowClosed (WindowEvent e ) ;p u bl i c v oi d wi nd ow Ico ni fi ed (WindowEvent e ) ;p u bl i c v oi d win dow Dei con ifi ed (WindowEvent e ) ;p u bl i c v oi d windowActivated (WindowEvent e ) ;p u bl i c v oi d windowDeacti vated (WindowEvent e ) ;

    }

    Listato 11: Linterfaccia MouseListener

    c l a s s WindowClos edLis tener extends WindowAdapter {p u bl i c v oi d windowClosed (WindowEvent e )

    {// c o d ic e da e s eg u ir e a l l a c hi us ur a d e l l a f i n e s t r a

    }}

    Listato 12: Esempio delluso degli Adapter

    9.3 Uso di adapter nella definizione degli ascoltatoriAlcuni componenti grafici generano eventi cos articolati da richiedere, perla loro gestione, ascoltatori caratterizzati da piu di un metodo. Si e gia vis-to che MouseListener, ne definisce tre. Linterfaccia WindowListener (vediListato 11) ne dichiara addirittura sette, ossia uno per ogni possibile cambia-mento di stato della finestra. Si e detto che se si desidera creare un ascoltatoreinteressato a un solo evento (per esempio uno che intervenga quando la fines-tra viene chiusa), esso dovra comunque fornire unimplementazione vuotaanche dei metodi cui non e interessato. Nei casi come questo e possibilericorrere agli adapter: classi di libreria che forniscono unimplementazione

    vuota di un determinato ascoltatore. Per esempio, il package java.awt.eventcontiene la classe WindowAdapter, che fornisce unimplementazione vuota ditutti i metodi previsti dallinterfaccia. Una sottoclasse di WindowAdapter,pertanto, e un valido WindowListener, con in piu il vantaggio di una maggiorconcisione. Si veda lesempio 12

  • 7/23/2019 Dispensa_JavaSwing_v2011

    33/46

    10 La gestione degli eventi Azione 32

    Fig. 14: La finestra ottenuta dal Listato 13

    10 La gestione degli eventi Azione

    La maggior parte dei componenti Swing generano eventi, noti come eventiazione, che possono essere catturati da un ActionListener. Essa definisce ununico metodo:

    p ub l ic i n t e r f a c e A c t i o n L i s t e n e r

    {p u bl i c v oi d a c t i o n P e r f o r m e d ( A c t io n E ve n t a e ) ;

    }

    Loggetto ActionEvent da informazioni aggiuntive sullevento generato. Adesempio, definisce il metodo Object getSource() che restituisce loggettoche ha generato levento.

    La maggior parte dei widget java sono predisposti per generare eventiazione. Ad esempio quando si clicca su un bottone, si preme INVIO in uncampo di testo, si seleziona una voce di un menu oppure si seleziona/de-seleziona una voce di una checkBox o un radioButton, viene generato unevento azione. Si potrebbe obiettare che, la gestione del click di un bottone,potrebbe essere fatta usando un mouseListener. Il vantaggio di utilizzare unevento azione risiede nel fatto che e possibile cliccare su un bottone anche conla tastiera (anche se in quel caso non e un vero click!): lutente con il tastoTAB potrebbe spostarsi sulla schermata, mettere il focus su un bottone equi premere la barra spaziatrice per voler cliccare sul bottone.

    E possibile installare uno stesso ascoltatore, ad esempio, per un bottonedella toolbar e una voce di menu. Il vantaggio risiede nel fatto che sia la vocedel menu che il bottone hanno lo stesso ascoltatore invece che due ascoltatoriseparati che fanno la stessa cosa.

    Un primo esempio di uso degli eventi azione e nel Listato 13. Il com-portamento e quello in Figura 14: quando lutente seleziona uno dei bottonidella finestra MyFrame viene aperta una finestra di dialogo con il testo delbottone premuto. Su ogni bottone e installato lo stesso ascoltatore per glieventi azione. Alla pressione di un bottone viene eseguito il metodo action-

  • 7/23/2019 Dispensa_JavaSwing_v2011

    34/46

    11 Accedere dallascoltatore agli oggetti di una finestra 33

    Fig. 15: La finestra ottenuta dal Listato 14

    Performed, il quale si fa restituire con il metodo getSource() il bottonepremuto (si noti il cast giacche il metodo lo restituisce come riferimento adObject). A partire dal bottone premuto, con il metodogetText() vienerestituito il testo visualizzato nel bottone.

    11 Accedere dallascoltatore agli oggetti di una finestra

    Lapproccio finora descritto funziona abbastanza bene anche se presenta an-cora alcune problematiche. Il primo problema e legato al fatto che la finestrae i suoi ascoltatori sono divisi in classi separate. Supponiamo di avere as-coltatori per gestire gli eventi scatenati da alcuni componenti installati in unadata finestra. Essendo le due classi formalmente indipendenti tra loro, perquanto detto, non e possibile accedere dagli ascoltatori a tutti i componentidella finestra (tranne il componente che ha generato levento).

    Supponiamo di voler realizzare una finestra come quella in Figura 15.Alla pressione del bottone OK il contenuto del campo di testo deve esserevisualizzato in un message dialog box. Si consideri il codice nel Listato 14.Nellascoltatore definiamo un nuovo JTextField text. Questapproccionon funziona perche il campo di testo definito e un nuovo campo di testo enon quello della finestra. Quindi la pressione del bottone mostrera sempreuna finestra dal contenuto vuoto perche di default un campo di testo vieneinizializzato con il contenuto vuoto.

    Un primo approccio e utilizzare una classe interna. Una classe internae definita allinterno di unaltra classe e puo accedere a tutte le variabili ei metodi di istanza della classe esterna (anche a quelli privati). Si consideriil Listato 15 che fa uso della classi interne: listruzione text = txt nel-lascoltatore fa s che il riferimento text punti allo stesso campo di testoriferito da txt. Quindi quando nel codice successivo, lascoltatore chiedetext.getText()ottiene effettivamente il codice richiesto.

    Questa tecnica e accettabile se lascoltatore esegue poche operazioni epochi ascoltatori esistono. Altrimenti la classe MyFrame diventa eccessiva-

  • 7/23/2019 Dispensa_JavaSwing_v2011

    35/46

    11 Accedere dallascoltatore agli oggetti di una finestra 34

    p ub li c c l a s s MyFrame extends JFrame

    {private J B utton uno = new JButton(Uno );private J B utton due = new JButton ( Due ) ;private J Bu tt on t r e = new J B utton( Tre ) ;private J Bu tt on q u a t t r o = new J B utton ( Quattro ) ;

    private J B ut to n c i n q u e = new J B utton( Cinque ) ;A s c ol ta t or e l i s t e n e r = new A s c o l t a t o r e ( ) ;public MyFrame(){

    . . .C o nt a in e r c = t h i s. getContentPane () ;c . add( uno ) ;uno . a d d A c t i o n L i st e n e r ( l i s t e n e r ) ;. . .c . add ( cin que ) ;c i n q u e . a d d A c t i o n L i s t e n e r ( l i s t e n e r ) ;

    }}

    p ub li c c l a s s A s c o l t a t o r e implements A c t i o n L i s t e n e r{

    p u bl i c v oi d a c t i o n P e r f o r m e d ( A c t io n E ve n t e v e n t ){

    J Bu tt o n b = ( J Bu tt o n ) e v e n t . g e t S o u r c e ( ) ;JOptionPane . showMessageDialog ( null,

    E s t a t o p re mu to +b . g e t T e xt ( ) ) ;}

    }

    Listato 13: Esempio uso di ActionPerformed

  • 7/23/2019 Dispensa_JavaSwing_v2011

    36/46

    11 Accedere dallascoltatore agli oggetti di una finestra 35

    p ub li c c l a s s MyFrame extends JFrame {J Pa ne l c e n t r o = new J P a ne l ( ) ;

    J P an e l s ud = new J P a ne l ( ) ;J T ex t Fi e ld t x t = new J T e xt F i e l d ( 2 0 ) ;J Bu tt o n b u t t on = new JButton(Premi );public MyFrame() {

    super ( Esempio ) ;cen tr o . add( tx t ) ;sud . add ( button ) ;getCo ntent Pane ( ) . add ( cent ro , BorderL ayout .CENTER) ;getCo ntent Pane ( ) . add ( sud , BorderLayo ut .SOUTH) ;button . add Acti onL is te ner (new L i s te n ( ) ) ;. . .

    }}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 ( A c t io n E v en t e ) {J T ex t Fi e ld t e x t = new J T e xt F i e l d ( ) ;JOptionPane . showMessageDialog (

    null, t e x t . g e t T e xt ( ) ) ;

    }}

    Listato 14: Un esempio che non funziona

  • 7/23/2019 Dispensa_JavaSwing_v2011

    37/46

    11 Accedere dallascoltatore agli oggetti di una finestra 36

    p ub li c c l a s s MyFrame extends JFrame {J Pa ne l c e n t r o = new J P a ne l ( ) ;

    J P an e l s ud = new J P a ne l ( ) ;J T ex t Fi e ld t x t = new J T e xt F i e l d ( 2 0 ) ;J Bu tt o n b u t t on = new JButton(Premi );public MyFrame() {

    super ( Esempio ) ;cen tr o . add( tx t ) ;. . .button . add Acti onL is te ner (new L i s te n ( ) ) ;. . .

    }

    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 ( A c t io n E ve n t e ) {J T ex t Fi e ld t e x t = t x t ;JOptionPane . showMessageDialog (null, t e x t . g e t T e xt ( ) ) ;

    }}

    }

    Listato 15: Una soluzione che funziona con le classi interne

  • 7/23/2019 Dispensa_JavaSwing_v2011

    38/46

    12 Condividere gli ascoltatori per piu oggetti 37

    mente grande. Inoltre il codice ottenuto diventa poco leggibile perche si

    tende ad accorpare classi che rappresentano concetti diversi.La soluzione preferibile e quella in cui lascoltatore definisce un costrut-

    tore che prende come parametro un riferimento alla finestra con i componentirichiesti. Il costruttore memorizza tale riferimento come variabile di classe.La classe ascoltatore resta comunque esterna: essa accede ai widget dellafinestra tramite tale riferimento e loperatore punto. Ovviamente i widgetnon devono essere memorizzati privati. La soluzione e descritta nel Lista-to 16. Nel codice viene anche mostrato una grande potenzialita degli eventiazione: levento azione del campo di testo e gestito nello stesso modo del-la finestra. Ne risulta, di conseguenza, che la pressione del bottone e la

    pressione del tasto ENTER sul campo di testo vengono gestiti dallo stessoActionListener e quindi gestiti nello stesso modo.

    12 Condividere gli ascoltatori per piu oggetti

    La tecnica piu naive per gestire piu eventi associati ad un controllo e quello dicreare una classe ascoltatore per ogni oggetto e per ogni classe di eventi dagestire per quello oggetto. Cio vorrebbe dire che se dovessimo gestire leventodi pressione di X bottoni, dovrebbe realizzare X classi che implementanoActionListener.

    Ovviamente e nella pratica improponibile prevedere una classe per ognibottone, voce del menu e cos via. Infatti, consideriamo per esempio unap-plicazione con 5 finestre, ognuna con 5 bottoni. Supponiamo che una di talifinestre abbia anche 3 voci del menu di 4 opzioni ciascuno. Cio significherebbeche avremmo 37 classi solo per gestire la pressione dei bottoni o della vocidel menu!

    Lidea piu 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 senzaperdere di generalita. Lo stesso approccio si applica in tutti gli altri casi. I

    componenti della stessa classe, ovviamente, condivideranno lo stesso metodoactionPerformed. A meno che tutti i componenti della stessa classe si devocomportare nello stesso modo allo scatenarsi delleventoazione, occore esserein grado di capire quale oggetto ha generato levento. Questo al fine dicapire quale comportamente adottare.

    Esistono due modi per capire chi ha generato levento:

    1. Attraverso il metodo getSource() della classe ActionEvent che resti-tuisce un riferimento alloggetto che ha scatenato levento. In questo

  • 7/23/2019 Dispensa_JavaSwing_v2011

    39/46

    12 Condividere gli ascoltatori per piu oggetti 38

    p ub li c c l a s s MyFrame extends JFrame {J Pa ne l c e n t r o = new J P a ne l ( ) ;J P an e l s ud = new J P a ne l ( ) ;J T ex t Fi e ld t x t = new J T e xt F i e l d ( 2 0 ) ;J Bu tt o n b u t t on = new JButton(Premi );

    L i st e n a s c o l t=new L i s t e n ( t h i s) ;public MyFrame() {

    super ( Esempio ) ;cen tr o . add( tx t ) ;. . .b u t t on . a d d A c t i o n L i s t e n e r ( a s c o l t ) ;t x t . a d d A c t i o n L i s t e n e r ( a s c o l t ) ;. . .

    }}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 {

    MyFrame fr am e ;

    public Li st e n (MyFrame aFrame){ frame = aFrame; }

    p u bl i c v oi d a c t i o n P e r f o r m e d ( A c t io n E ve n t e ) {J T e xt F i e l d t e x t = f r am e . t x t ;JOptionPane . showMessageDialog (null, t e x t . g e t T e xt ( ) ) ;

    }}

    Listato 16: La soluzione migliore

  • 7/23/2019 Dispensa_JavaSwing_v2011

    40/46

    12 Condividere gli ascoltatori per piu oggetti 39

    modo e possibile utilizzare un approccio di tipo switch/case: se il rifer-

    imento punta a X, allora chiama un metodo privato che corrispondealla 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 ques-ta approccio e fattibile se e possibile confrontare i riferimenti ottenuticon il metodogetSource()con i riferimenti memorizzati internamentealla classe che estende JFrame e che disegna la finestra con i bottoniX, Y e gli altri. Questo approccio e generalmente fattibile, quindi, conle classi interne.

    2. Utilizzando la proprietaactionCommand, implementata per ogni com-ponente, che permette di associare una stringa identificativa univocaad ogni componente che scatena un evento azione. A questo punto epossibile definire allinterno del metodo actionPerformed un approc-cio di tipo switch/case sugli actionCommand. Se lo actionCommanddelloggetto e ACTX (che e stato associato ad X) allora lascoltatoreesegue una certa porzione di codice, se lo actionCommand e ACTY faunaltra cosa. E cos via. In questo nuovo contesto non e piu necessarioper lascoltatore di avere accesso ai riferimenti.

    Si consideri, ad esempio, la porzione di condice nel Listato 17 dove cisono 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 com-portare in funzione del metodo invocato e fatto analizzando i riferimenti.Listruzione src=e.getSource() restituisce un riferimento alloggetto cheha generato levento. Se tale riferimento e uguale a UpOpt (entrambi pun-tano allo stesso oggetto corrispondente alla voce del menu Up, allora lavoce del menu scelta e Up. Quindi viene eseguita la porzione di codice rela-tiva a tale voce. Lo stesso per le altre voci. Lascoltatore e realizzato comeclasse interna in modo tale da poter realizzare luguaglianza tra i puntato everificare se coincidono.

    Come si e detto, lapproccio con le classi interne ha molti svantaggi. lametodologia che vogliamo qui introdurre per capire chi ha generato leventonon deve assumere classi interne e, quindi, non puo basarsi sulluguaglianzatra puntatori.

    Quando si usano classi esterne, e possibile capire il componente che hanotificato levento associando ai diversi componenti un diverso valore dellaproprietaactionCommand.

    Nellesempio nel Listato 18 i possibili valori per le proprieta actionCom-mandsono memorizzate come costanti stringa, cioe public final static,della classe ascoltatoreListener. Ad ogni oggetto da predisporre per gestire

  • 7/23/2019 Dispensa_JavaSwing_v2011

    41/46

    12 Condividere gli ascoltatori per piu oggetti 40

    p ub li c c l a s s MyFrame extends JFrame{

    . . .JMenuItem UpOpt = new JMenuItem(Up );JMenuItem DownOpt = new JMenuItem ( Down ) ;JMenuItem RandomOpt = new JMenuItem ( Random ) ;

    L i st e ne r a s c o lt a t o r e = new L i s t e n e r ( ) ;public MyFrame(){

    . . .UpOpt . a d d A c t i o n L i s t e n e r ( a s c o l t a t o r e ) ;DownOpt . a d d A c t i o n L i s t e n e r ( a s c o l t a t o r e ) ;RandomOpt . add Acti onL is te ner ( as co lt at or e );. . .

    }

    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

    {p u b li c v oi d a c t i o n P e r f o r m e d ( A c t io n E ve n t e ){

    O b je c t 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 v oc e d e l menu Up }e l se i f ( s r c == DownOpt){ c o d i c e d e l l a v oc e d e l menu Down }e l se i f ( s r c == RandomOpt){ c o d i c e d e l l a v o ce d e l menu Random }

    }

    }}

    Listato 17: Ascoltatore condiviso come classe Interna

  • 7/23/2019 Dispensa_JavaSwing_v2011

    42/46

    12 Condividere gli ascoltatori per piu oggetti 41

    p ub li c c l a s s MyFrame extends JFrame {

    . . .JMenuItem UpOpt = new JMenuItem(Up );JMenuItem DownOpt = new JMenuItem ( Down ) ;JMenuItem RandomOpt = new JMenuItem ( Random ) ;L i st e ne r a s c o lt = new L i s t e n e r ( ) ;public MyFrame() {

    . . .UpOpt. addA cti onLi s ten er ( as co lt ) ;UpOpt . setActionCommand ( L i s t e n e r .UPOPT) ;DownOpt. ad dAct ion Lis t ener ( a s c ol t ) ;DownOpt . setA ctio nCom mand ( L i s t e n e r .DOWNOPT) ;

    RandomOpt . add Acti onL is te ner ( as co lt ) ;RandomOpt . setAct ion Com man d ( L i s t e n e r .RANDOMOPT). . .

    }}

    Listato 18: Il JFrame per usare ascoltatori esterni

    gli eventi azione viene associato un valore per la actionCommand presi tratali costanti stringa. Questo viene fatto grazie al metodo

    void setActionCommand ( St ri ng ) ;

    Il metodoactionPerformeddellactionListener legge il valore della propri-etaactionCommanddel componente che ha notificato levento e, in funzionedel valore letto, sceglie la porzione di codice da eseguire. Eventualmente epossibile associare lo stesso actionCommand a componenti gestiti dallo stes-so ascoltatore se si desidera che questi gestiscano levento azione nello stessomodo. Questo cosa e molto utile quando si desidera replicare la voce di undato menu con un bottone da inserire nella toolbar della finestra: per fare sche sia la voce del menu che il bottone nella toolbar gestiscano levento nellostesso modo e sufficiente associare ad entrambi lo stesso actionCommand.

    Torniamo indietro a considerare la finestra descritta nel Listato 18. Il suoscheletro e nel Listato 19. Si possono osservare sempre tre parti in questotipo di ascoltatori:

    La parte che definisce le costanti stringa (le tre dichiarazioni di oggettipubblici, costanti4 e statici)

    4 In Java e possibile definire che il valore di un riferimento non puo cambiare dichiaran-dolofinal. Questo ovviamente non e sufficiente per dichiarare un oggetto costante. Tut-tavia nel caso di oggetti String le due cose coincidono dato che gli oggetti stringa sono

  • 7/23/2019 Dispensa_JavaSwing_v2011

    43/46

    12 Condividere gli ascoltatori per piu oggetti 42

    p ub li c 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

    {p ub li c f i n a l s t a t i c S t r i n g UPOPT = up ;p ub li c f i n a l s t a t i c S t r i n g DOWNOPT = down ;p ub li c 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 ( A c t io n E ve n t e ){

    St ri ng com = e . getActionCommand ( ) ;i f ( com == UPOPT)

    upOpt () ;e ls e i f ( sr c == DOWNOPT)

    downOpt ( ) ;e ls e i f ( sr c == RANDOMOPT)

    randomOpt ( ) ;}

    p r i va t e v oi d upOpt(){ . . . }

    p r i va t e v oi d randomOpt(){ . . . }

    p r i va t e v oi d downOpt(){ . . . }

    }

    Listato 19: Ascoltatore condiviso come classe Interna

    Il metodo actionPerformed che gestisce levento. Questo metodo inquesti casi non fa nientaltro che leggere il valore della proprieta ac-tionCommand delloggetto che ha generato levento. In funzione delvalore della proprieta (e quindi delloggetto scatenante), viene attivata

    una gestione separata che consiste nellinvocare metodi diversi.

    I diversi metodi privati che eseguono effettivamente le operazioni asso-ciate allattivazione dei diversi controlli/widget.

    immutabili: non puo cambiare il riferimento, ne puo cambiare il valore delloggetto puntato

  • 7/23/2019 Dispensa_JavaSwing_v2011

    44/46

    13 Conclusioni e Commenti Finali 43

    13 Conclusioni e Commenti Finali

    Questa dispensa ha descritto le funzionalita piu comuni del pacchetto JavaSwing.JavaSwing e un pacchetto estremamente vasto, che va dalla definizione delleinterfacce e del disegno 2D, fino alla gestione dellinterazione nei piu min-imi dettagli. Di conseguenza, e praticamente impossibile toccare tutti gliargomenti in questa dispensa.

    E opportuno concludere la trattazione con alcune osservazioni su una cor-retta interazione tra le interfacce grafiche e la logica applicativa (ad es., larealizzazione del diagramma delle classi). Una buon approccio metodologicosi basa su un concetto cardine: la logica applicativa non deve essere stretta-

    mente accoppiata con il codice delle classi delle interfacce grafiche. Quindi,allinterno delle classi della logica applicativa non si devono avere riferimenti,ne avere accesso alle classi che descrivono le interfacce grafiche.

    Daltronde, non e possibile specificare una modalita di accesso privateper le variabili di istanza delle classi che ereditano da JFrame. Infatti, secos fosse, gli ascoltatori non avrebbero accesso ai componenti delle finestre,a meno di definire complessi e numerosi metodi getter/setter.

    Un buon tradeoff consiste nel mettere le classi delle interfacce e i relativiascoltatori in un package diverso dalla logica applicativa (ad esempio gui),specificando un modalita di accesso package alle variabili di istanza delleclassi che ereditano da JFrame.5 In questo modo le classi della logica applica-tiva non hanno alcun accesso ai campi delle classi JFrame, dato che si trovanoi package diversi. Viceversa gli ascoltatori possono, poiche si trovano nellostesso package. Infatti, gli ascoltatori sono gli unici che, da un lato, possonoaccedere alla logica applicative e, dallaltro, possono aggiornare opportuna-mente laspetto e i contenuti delle finestre grafiche. In aggiunta e possibiledefinire per ogni finestra e tutti i listener associati ai widget della finestreun opportuno sotto package (ad esempio gui.nomeFinestra) in modo dalimitare il raggio di azione dei diversi ascoltatori alla sola finestra.

    5 Si ottiene la modalita di accesso package quando la descrizione del tipo delle variabilidistanza non e preceduta da nessuna modalita di accesso: public, private o protected.

  • 7/23/2019 Dispensa_JavaSwing_v2011

    45/46

    13 Conclusioni e Commenti Finali 44

    parent Questo parametro serve a specificare il frame principale; esso

    verra bloccato fino al termine dellinterazione. Ponendo a nullquesto parametro la finestra verra visualizzata al centro delloschermo e risultera indipendente dal resto dellapplicazione.

    Message Questo campo permette di specificare una stringa da visual-izzare come messaggio oppure, in alternativa, una qualunquesottoclasse di Component

    title Questo parametro e utilizzato per specificare il titolo dellafinestra modale.

    messageType Attraverso questo parametro e possibile influenzare laspettocomplessivo della finestra, per quanto riguarda il tipo di icona

    e il layout. Il parametro puo assumere uno dei seguenti valori:

    JOptionPane.ERROR MESSAGE

    JOptionPane.INFORMATION MESSAGE

    JOptionPane.WARNING MESSAGE

    JOptionPane.QUESTION MESSAGE

    JOptionPane.PLAIN MESSAGE

    optionType I Confirm Dialog possono presentare diversi gruppi di opzioniper scegliere i bottoni da visualizzare nella finestra modale:

    JOptionPane.YES NO OPTION

    JOptionPane.YES NO CANCEL OPTION

    JOptionPane.OK CANCEL OPTION

    icon Ogni istanza della classe Icon rappresenta unicona. In questocaso loggetto passato sara visualizzato come icona di un In-

    put Dialog. Nella maggior parte dei casi questo parametropuo essere messo a null in modo tale che sia scelta licona didefault.

    SelectedValues Questa parametro permette di impostare i possibili valori,tipicamente stringhe, che possono selezionati attraverso lIn-put Dialog. I valori selezionabili sono inseriti in un ComboBoxin modo tale che nessun altro valore e ammissibile. Se questoparametro viene messo a null allora il ComboBox e sostituitoda un campo di testo e qualsiasi valore e ammesso.

    initialValue Questo parametro permette di stabilire il valore di default,

    tipicamente una stringa.

    Tab. 1: Spiegazione dei parametri dei metodi di JOptionPane

  • 7/23/2019 Dispensa_JavaSwing_v2011

    46/46

    13 Conclusioni e Commenti Finali 45

    ActionListener Definisce 1 metodo per ricevere eventi-azioneComponentListener Definisce 4 metodi per riconoscere quando un

    componente viene nascosto, spostato, mostrato oridimensionato

    FocusListener Definisce 2 metodi per riconoscere quando uncomponente ottiene o perde il focus

    KeyListener Definisce 3 metodi per riconoscere quando vienepremuto, rilasciato o battuto un tasto

    MouseMotionListener Definisce 2 metodi per riconoscere quando il mousee trascinato o spostato

    MouseListener Se ne e gia parlato. . .TextListener Definisce 1 metodo per riconoscere quando cambia

    il valore di un campo testoWindowListener Definisce 7 metodi per riconoscere quando un fines-

    tra viene attivata, chiusa, disattivata, ripristinata,ridotta a icona, ecc.

    Tab. 2: Gli ascoltatori piu importanti