Dispensa Swing - Sviluppo di Interfacce Grafiche in Java (PDF)

Document Details

StimulativeLeibniz1378

Uploaded by StimulativeLeibniz1378

Sapienza Università di Roma

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

Tags

Java programming GUI programming software development computer science

Summary

This document is a didactic handout about the development of graphical interfaces in Java. It covers basic concepts and examples, focusing on the Swing package. The handout is for a course in computer science at Sapienza University of Rome.

Full Transcript

SAPIENZA – Università di Roma Facoltà di Ingegneria Corso di Laurea in Ingegneria Informatica Dispensa didattica Sviluppo di Interfacce Grafiche in Java. Concetti di Base ed Esempi. M. de Leoni, M. Mecella, S. Saltarelli Creative Commons License Deed Attribuzione...

SAPIENZA – Università di Roma Facoltà di Ingegneria Corso di Laurea in Ingegneria Informatica Dispensa didattica Sviluppo di Interfacce Grafiche in Java. Concetti di Base ed Esempi. M. de Leoni, M. Mecella, S. Saltarelli 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 paternità dell’opera nei modi indicati dall’au- tore o da chi ti ha dato l’opera in licenza. Non commerciale. Non puoi usare questa opera per fini commerciali. Non opere derivate. Non puoi alterare o trasformare quest’opera, nè usarla per crearne un’altra. Ogni volta che usi o distribuisci questa opera, devi farlo secondo i termini di questa licenza, che va comunicata con chiarezza. In ogni caso, puoi concordare col titolare dei diritti d’autore 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 d’autore e gli altri diritti non sono in alcun modo limitati da quanto sopra. Questo è un riassunto in linguaggio accessibile a tutti del Codice Legale (la licenza integrale) disponibile all’indirizzo: http://creativecommons.org/licenses/by-nc-nd/2.5/it/legalcode. Indice 2 Indice 1 Introduzione............................ 3 2 Il package Swing......................... 3 3 Top Level Container....................... 5 3.1 Uso di JFrame........................... 5 4 Paranoramica di alcuni widget.................. 8 5 L’ereditarietà per personalizzare i frame............ 10 6 I Layout Manager e la gerarchia di contenimento........ 13 6.1 Layout Management....................... 13 6.2 Progettazione della GUI con le gerarchie di contenimento... 17 6.3 Progettazione top down di interfacce grafiche.......... 19 6.3.1 Esempio di Progettazione Top-Down.......... 20 7 La Gestione degli Eventi..................... 23 7.1 Implementazione dell’event delegation.............. 23 7.2 Un esempio: elaborare gli eventi del mouse........... 25 7.3 Uso di adapter nella definizione degli ascoltatori........ 27 8 La gestione degli eventi Azione................. 27 9 Accedere dall’ascoltatore agli oggetti di una finestra...... 29 10 Condividere gli ascoltatori per più oggetti........... 33 1 Introduzione 3 1 Introduzione Uno dei problemi più grossi emersi durante la progettazione di Java fu sen- za dubbio la realizzazione di un toolkit grafico capace di funzionare con prestazioni di buon livello su piattaforme molto differenti tra loro. La soluzione adottata nel 1996 fu AWT(Abstract Window Toolkit), un package grafico che 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 un’interfaccia grafica, il sistema 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- l’oggetto Java corrispondente, ricorrendo a procedure scritte in buona parte in codice nativo; nel contempo, ogni volta che l’utente manipola un elemento dell’interfaccia grafica, un’apposita 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 dell’utente con una sintassi completamente Object Oriented e indipendente dal sistema sottostante. A causa di questa scelta progettuale, il set di componenti grafici AWT comprende 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 grafici AWT assumono un aspetto ed un comportamento differente a seconda della JVM su cui vengono eseguite, a causa delle macroscopiche differenze imple- mentative esistenti tra le versioni di uno stesso componente presenti nelle diverse 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 eseguilo ovunque”; nel caso di AWT questo si era trasformato in “scrivi una volta sola e correggilo ovunque”. 2 Il package Swing Nel 1998, con l’uscita del JDK 1.2, venne introdotto il package Swing, i cui componenti erano stati realizzati completamente in Java, ricorrendo uni- camente alle primitive di disegno più semplici, tipo “traccia una linea” o “disegna un cerchio”, accessibili attraverso i metodi dell’oggetto Graphics, un oggetto AWT utilizzato dai componenti Swing per interfacciarsi con la 2 Il package Swing 4 Component Container JComponent Window Panel JFrame JApplet JPanel java.awt JDialog javax.swing Fig. 1: Diagramma UML di base del package Swing. piattaforma ospite. Le primitive di disegno sono le stesse su tutti i sistemi grafici, e il loro utilizzo non presenta sorprese: il codice java che disegna un pulsante Swing sullo schermo di un PC produrrà lo stesso identico risultato su un Mac o su un sistema Linux. Questa architettura risolve alla radice i problemi di uniformità visuale, visto che la stessa identica libreria viene ora utilizzata, senza alcuna modifca, su qualunque JVM. Liberi dal vincolo del “minimo comune denominatore”, i progettisti di Swing hanno scelto di per- correre la via opposta, creando un package ricco di componenti e funzionalità spesso non presenti nella piattaforma ospite. Il procedimento di disegno è ovviamente più lento perché la JVM deve disegnare per proprio conto tutte le linee degli oggetti grafici e gestirne direttamente il comportamento, però è più coerente. Le classi Swing sono definite nel pacchetto javax.swing, il cui nome javax indica 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 in java. Gli oggetti grafici Swing derivano dai corrispettivi AWT; quindi è pos- sibile utilizzare oggetti Swing, ove erano previsti i oggetti antenati. Swing usa ancora alcuni elementi AWT per disegnare; anche la gestione degli eventi è fatta per la maggior parte da classi AWT. La Figura 1 riassume molto sinteticamente le classi base del package Swing e come queste derivino da classi AWT. Ogni oggetto grafico (una finestra, un bottone, un campo di testo,... ) è implementato come classe del package javax.swing. Ogni classe che identifica un oggetto Swing deriva 3 Top Level Container 5 per lo più dalla classe javax.swing.JComponent; si stima che esistono circa 70 o più oggetti diversi. Gli oggetti grafici 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 è vuoto e il cui scopo è offrire la possibilità di disporre altri componenti all’interno. Non a caso la classe AWT Window e le sottoclassi Swing JFrame e JDialog, le cui istanze rappresentano finestre, sono sottoclasse di Container. La cosa più sorprendente è che, siccome JComponent deriva da Container, è possibile in- serire all’interno di un qualsiasi widget qualsiasi altro. Ad esempio - sebbene poco utile - è possibile aggiungere un campo di testo all’interno di un bottone oppure - molto usato - un Container all’interno di un altro Container. La classe Container (e ogni sottoclasse) definisce un metodo per aggiungere un controllo ad un Container: void add(Component); Il metodo prende come parametro un oggetto Component che è la superclasse di qualsiasi oggetto o container Swing o AWT. 3 Top Level Container I top level container sono i componenti all’interno dei quali si creano le interfacce grafiche: ogni programma grafico ne possiede almeno uno, di solito un JFrame, che rappresenta la finestra principale. Ogni top level container possiede un pannello (accessibile tramite il metodo getContentPane()) al- l’interno del quale vanno disposti i controlli dell’interfaccia grafca. Esistono tre tipi principali di top level Container: JFrame, JApplet e JDialog. Il primo viene solitamente usato come finestra principale per il programma, il secondo è utilizzato per costruire Applet da visualizzare nella finestra di un web browser mentre il terzo serve a creare le finestre di dialogo con l’utente. 3.1 Uso di JFrame Un oggetto della classe JFrame può essere creato usando i costruttori: JFrame(); JFrame(String titoloFinestra); Il primo costruisce un JFrame senza titolo; il secondo permette di specificarlo. È sempre possibile impostare il titolo ricorrendo al metodo setTitle(String s). Due importanti proprietà dell’oggetto sono la dimen- sione e la posizione, che possono essere impostate sia specificando le singole componenti sia mediante oggetti Dimension e Point del package AWT: 3.1 Uso di JFrame 6 Fig. 2: Anatomia di un Frame Swing. public void setSize(Dimension d); public void setSize(int width,int height); public void setLocation(Point p); public void setLocation(int x,int y); Ricorrendo al metodo setResizable(boolean b) è possibile stabilire se si vuole permettere all’utente di ridimensionare la finestra manualmente. Infine, vi sono tre metodi piuttosto importanti: public void pack(); public void setVisible(boolean b); public void setDefaultCloseOperation(int operation); Il primo ridimensiona la finestra tenendo conto delle dimensioni ottimali di ciascuno dei componenti presenti all’interno. Il secondo permette di visualiz- zare o di nascondere la finestra. Il terzo imposta l’azione 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 libera le risorse di sistema) e JFrame.EXIT ON CLOSE (chiude la finestra e conclude l’esecuzione del programma). Per impostazione di default, un JFrame viene costruito non visibile e di dimensione 0 x 0. Per questa ragione, affinchè la finestra sia visibile, è nec- essario chiamare i metodi setSize() o pack() per specificare la dimensione e mettere a true la proprietà Visible chiamando il metodo: setVisible(true). Per poter lavorare con i Frame Swing, è opportuno conoscere il linea generale la struttura della superficie. La superficie di un frame Swing è coperta da quattro lastre: Glass Pane La lastra di vetro è nascosta di default ed ha il compito di cat- turare gli eventi di input sulla finestra. Normalmente è completamente trasparente a meno che venga implementato il metodo paintComponent del GlassPane. Poichè è davanti a tutte le altre, qualsiasi oggetto disegnato su questa lastra nasconde qualsiasi altro disegnato sulle altre 3.1 Uso di JFrame 7 import javax.swing.*; import java.awt.*; public class Application { public static void main(String args[]) { JFrame win; win = new JFrame("PrimaÃfinestra"); Container c = win.getContentPane(); c.add(new JLabel("BuonaÃLezione")); win.setSize(200,200); win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); win.setVisible(true); } } Listato 1: La prima finestra Content Pane La lastra dei contenuti è la più importante perchè è quella che ospita i componenti che volete visualizzare nella finestra e la maggior parte dei programmatori Java lavora solo su questa Layered Pane Contiene la lastra dei contenuti ed eventualmente i menu. I menu, infatti, non vengono mai aggiunti al Content Pane ma a questa lastra. Root Pane La lastra radice ospita la lastra di vetro insieme con la lastra dei contenuti e i bordi della finestra. Per maggiori dettagli si faccia riferimento a [?]. Quindi, un componente, quale un pulsante, un’immagine o altro, non viene aggiunto direttamente alla finestra ma alla lastra dei contenuti. Di conseguenza, occorre per prima cosa procurarsi un riferimento all’oggetto ContentPane, mediante la chiamata al metodo: public Container getContentPane(); Come era da aspettarsi, il ContentPane “è un” Container perchè predisposto a contenere altri componenti. A questo punto, come per ogni altro Container, è possibile aggiungere ad esso un componente con il metodo add già descritto. A questo punto è possibile disegnare la prima finestra. Il codice descritto nel Listato 1 mostra la finestra in Figura 3. 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 dell’interfaccia utente Swing iniziano con la J. JTextField è un campo di testo Swing. Tale classe eredita da TextField, l’obsoleto analogo del package AWT. Per costruire un campo di testo occorre fornirne l’ampiezza, cioè il numero approssimato di caratteri che vi aspettate verranno inseriti dall’utente. JTextField xField=new JTextField(5); Gli utenti possono digitare anche un numero maggiore di caratteri ma sempre 5 contemporaneamente saranno vicini: i 5 attorno alla posizione del cursore nel campo. Sarebbe opportuno etichettare ciascun campo di testo in modo che l’u- tente sappia cosa scriverci. Ogni etichetta è un oggetto di tipo JLabel che viene costruito, sfruttando il costruttore con un parametro stringa; tale parametro rappresenta il testo dell’etichetta: JLabel xField=new JLabel("xÃ=Ã"); Inoltre vorrete dare all’utente la possibilità di inserire informazione in tutti i campi di testo prima di elaborarli per cui avete bisogno di un pul- sante che l’utente possa premere per segnalare che i dati sono pronti per essere elaborati. Un pulsante è un oggetto JButton che può essere costruito fornendo una stringa che fungerò da etichetta, un’immagine come icona o entrambe JButton moveButton=new JButton("Move"); JButton moveButton=new JButton(new ImageIcon("hand.gif")); 4 Paranoramica di alcuni widget 9 Fig. 4: Alcuni Bottoni delle Swing. JButton moveButton=new JButton("Move",new ImageIcon("hand.gif")); JCheckBox è una sottoclasse di JButton che crea caselle di controllo, con un aspetto simile a quello delle caselle di spunta dei questionari. Il suo funzionamento è analogo a quello della superclasse, ma di fatto tende a essere utilizzato in contesti in cui si offre all’utente la possibilità di scegliere una o più opzioni tra un insieme, come avviene per esempio nei pannelli di controllo. I costruttori disponibili sono gli stessi della superclasse, quindi non sarà necessario ripetere quanto è stato già detto. JCheckBox check1=new JCheckBox("JCheck"); JRadioButton è una sottoclasse di JButton, dotata dei medesimi costrut- tori. Questo tipo di controllo, chiamato pulsante di opzione, viene usato tipicamente per fornire all’utente la possibilità di operare una scelta tra un insieme di possibilità, in contesti nei quali un’opzione esclude l’altra. I costruttori disponibili sono gli stessi della superclasse. Per implementare il comportamento di mutua esclusione, è necessario registrare i JRadioButton che costituiscono l’insieme presso un’istanza della classe ButtonGroup, come viene mostrato nelle righe seguenti: JRadioButton radioButton1=new JRadioButton("R1"); JRadioButton radioButton2=new JRadioButton("R2"); JRadioButton radioButton2=new JRadioButton("R3"); ButtonGroup group = new ButtonGroup(); group.add(radioButton1); group.add(radioButton2); group.add(radioButton3); Ogni volta che l’utente attiva uno dei pulsanti registrati presso il Button- Group, gli altri vengono automaticamente messi a riposo. 5 L’ereditarietà per personalizzare i frame 10 I JComboBox offrono all’utente la possibilità di effettuare una scelta a partire da un elenco elementi, anche molto lungo. A riposo il componente si presenta come un pulsante, con l’etichetta corrispondente al valore at- tualmente 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à editable di un JComboBox a true esso si com- porterà a riposo come un JTextField, permettendo all’utente di inserire valori non presenti nella lista. È possibile creare un JComboBox usando i seguenti costruttori: JComboBox(); JComboBox(Object[] items); Il secondo costruttore permette di inizializzare il componente con una lista di elementi di qualsiasi tipo (ad esempio String). Se viene aggiunto al ComboBox un oggetto generico (ad esempio un oggetto Libro), allora il valore corrispondente visualizzato nella lista delle opzioni è quello ottenuto chiamando sull’oggetto il metodo toString(). Quindi se si desidera aggiun- gere oggetti generici (magari definiti all’interno del programma), bisognerà avere la cura di ridefinire tale metodo. Un gruppo di metodi permette di aggiungere, togliere o manipolare gli elementi dell’elenco, cosı̀ come si fa con un Vector: public void addItem(Object anObject); public void removeItem(Object anObject) public void removeItemAt(int anIndex); public void removeAllItems(); public Object getItemAt(int index); public int getItemCount(); public void insertItemAt(Object anObject, int index) Per ottenere l’elemento correntemente selezionato, è disponibile il metodo: public Object getSelectedItem(); La Figura 5 mostra un esempio di suo uso. Il Listato 2 rappresenta il codice corrispondente: 5 L’ereditarietà per personalizzare i frame Aggiungendo ad un frame molti componenti dell’interfaccia utente, il frame stesso può diventare abbastanza complesso: per frame che contengono molti componenti è opportuno utilizzare l’ereditarietà. Infatti, se il software che si sta sviluppando contiene molte finestre ricche di componenti ci si troverebbe 5 L’ereditarietà per personalizzare i frame 11 import javax.swing.*; import java.awt.*; public class Application { public static void main(String args[]) { JFrame win; win = new JFrame("EsempioÃdiÃJComboBox"); String lista[]=new String; for(int i=0;i

Use Quizgecko on...
Browser
Browser