Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
di un componente dell’interfaccia utente, per esempio un pulsante, una casella di controllo, una
casella di testo. Ogni componente ha tre caratteristiche che lo distinguono:
Il suo contenuto, per esempio lo stato di un pulsante (premuto o rilasciato) oppure il testo
di una casella di testo.
Il pattern definisce con precisione l’interazione tra questi tre oggetti. Uno dei vantaggi di questo
pattern è che un modello può avere viste multiple, ciascuna delle quali mostra una parte o un
aspetto del contenuto completo. Per esempio, un editor HTML può offrire due viste simultanee
dello stesso contenuto. Quando il modello viene aggiornato mediante il controllore di una delle
viste, informa entrambe le viste collegate delle modifiche avvenute. Il controllore gestisce gli
eventi dell’input dell’utente, per esempio i click del mouse e le combinazioni di tasti. Il controllore
stesso decide allora di tradurre questi eventi in modifiche del modello o della vista.
Per esempio, se l’utente preme il tasto di un carattere in una casella di testo, il controllore chiama
il comando “inserisci carattere” del modello. Il modello dice allora alla vista di aggiornarsi. La vista
non sa mai perché il testo è cambiato. Lo scorrimento della vista non ha effetto sul testo
sottostante, e il modello non sa che questo evento si è verificato.
Gestione del Layout
FlowLayout
Il gestore di layout a flusso (flow layout), è il gestore di layout predefinito per un pannello. I
componenti vengono allineati in senso orizzontale fino a quando c’è spazio sufficiente, poi si inizia
una nuova riga di componenti. Quando l’utente ridimensiona il contenitore, il gestione di layout
ridistribuisce automaticamente i componenti per riempire lo spazio disponibile. E’ anche possibile
scegliere come collocare i componenti su ciascuna riga. L’impostazione predefinita prevede di
centrarli nel contenitore, mentre le altre opzioni riguardano la possibilità di allineare i componenti
nel contenitore lungo il lato sinistro o destro.
Per impostare uno di questo allineamenti, si deve specificare la costante LEFT o RIGHT nel
costruttore dell’oggetto FlowLayout:
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
BorderLayout
Il gestore di layout a bordo (border layout) è il gestore predefinito del pannello dei contenuti di
ogni JFrame. Permette di scegliere dove si vuole collegare ogni componente. Si può scegliere di
collocare il componente al centro, a nord, a sud, a est oppure a ovest del pannello dei contenuti.
Prima si collocano i componenti lungo il bordo, poi lo spazio che rimane è occupato da quelli che
devono risultare centrati. Quando si ridimensiona il contenitore, le dimensione dei componenti sul
bordo non vengono modificare, mentre il componente al centro modifica la sua dimensione.
Per impostare uno di questi collocamenti, si deve specificare un delle costanti della classe
BorderLayout: CENTER, NORTH, SOUTH, EAST o WEST:
panel.setLayout(new BorderLayout());
panel.add(button, BorderLayout.NORTH);
In alternative è possibile indicare le distanze in pixel tra le varie aree, impostando il
parametro corrispondente nel costruttore di BorderLayout:
GridLayout
Il layout a griglia (grid layout) colloca i componenti in righe e colonne, come in un foglio di calcolo.
Inoltre prevede che le celle abbiano tutte la stessa dimensione. Quando si ridimensiona la finestra,
i pulsanti si allargano e si restringono, ma tutti i pulsanti hanno la medesima dimensione.
A questo punto si può iniziare a parlare dei componenti Swing dell’interfaccia utente. In
particolare inizieremo a trattare i componenti che permettono a un utente di inserire e modificare
un testo in input. A tal proposito si possono utilizzare i componenti JTextField e JTextArea per
raccogliere il testo in input. Una casella di testo può accettare solo una riga di testo, mentre un’are
di testo può accettare più righe di testo. Entrambe le classi ereditano una classe astratta di nome
JTextComponent.
Casella di testo
Di solito si aggiunge una casella di testo in una finestra inserendola in un pannello o in un altro
contenitore, come si farebbe con un pulsante:
Questo codice aggiunge una casella di testo e la inizializza collocando la stringa “Default Input” al
suo interno (se si omette il primo parametro si costruire una casella di testo vuota). Il secondo
parametro imposta la larghezza in colonne. Quest’ultima misura è poco attendibile poiché la
misura di una colonna è alquanto imprecisa. Per questo conviene sempre aggiungere 1 o 2 alla
lunghezza massima dell’input. Inoltre la larghezza in colonne non è un limite sul numero di
caratteri che l’utente può inserire. L’utente può sempre digitare una stringa più lunga e quando il
testo supera la lunghezza della casella, l’input scorre.
textField.setColumns(10);
panel.revalidate();
textField.setText(“Hello!”);
Per scoprire ciò che l’utente ha digitato si richiama il metodo getText. Questo metodo
restituisce il testo esatto che l’utente ha digitato:
Per rimuovere eventuali interlinee e spaziature dei dati presenti n una casella di testo, si
applica il metodo trim al valore restituito da getText:
Per modificare il font con il quale appare il testo dell’utente, si utilizza il metodo setFont:
Aree di testo
A volte è necessario che l’input dell’utente occupi più di una riga di testo. SI è già visto che, in
questi casi, si utilizza un’area di testo implementata dal componente JTextArea. L’utente può
digitare una quantità qualsiasi di righe di testo, utilizzando il tasto INVIO per separarle.
Nel costruttore del componente JTextArea si specifica il numero di righe e di colonne dell’area di
testo, come nel seguente esempio:
Il parametro columns ha il significato visto in precedenza: se c’è più testo di quello che l’area di
testo può visualizzare, il testo che rimane escluso viene semplicemente tagliato. Si può evitare il
taglio delle righe lunghe impostando un wrapper delle righe:
Ogni wrapper ha solo un effetto visuale; il testo del documento non viene modificato e nessun
carattere ‘\n’ viene inserito nel testo.
In Swing un area di testo non prevede barre di scorrimento. Se le si vogliono, si deve inserire l’area
di testo in un pannello di scorrimento:
Caselle password
Le caselle password sono un genere speciale di casella di testo. I caratteri digitati dall’utente non
vengono effettivamente visualizzati. In questo caso, ogni carattere digitato è rappresentato da un
carattere di ripetizione (o echo), di solito un asterisco (*). Per implementare una casella di testo di
questo genere, Swing mette a disposizione una classe JPasswordField con i seguenti metodi:
Si verificano spesso situazioni nelle quali si preferisce offrire agli utenti una serie finita di opzioni
tra le quali scegliere piuttosto che obbligarli a inserire dei dati in una casella di testo. Si vedrà,
quindi, come si programmano le caselle di controllo (checkbox), i pulsanti di opzione (radio
button), le liste di selezione (combo box) e gli slider.
Caselle di controllo
Se si vuole ottenere solo un input del genere “sì” o “no”, si utilizza un componente casella di
controllo. L’utente di solito seleziona la casella facendo click al suo interno e rimuove il segno di
spunta facendo nuovamente click nella casella.
bold.setSelected(true);
ActionListener listener = . . . ;
bold.addActionListener(listener);
Pulsanti di opzione
In molti casi si richiede che l’utente attivi solo una tra le caselle a disposizione. Quando si attiva
una casella, le altre vengono automaticamente disattivate. Un gruppo di caselle di questo tipo
prende il nome di gruppo di pulsanti di opzione (radio button group):
Si costruisce un oggetto di tipo ButtonGroup per ogni gruppo di pulsanti, poi si aggiungono
al gruppo di pulsanti oggetti di tipo JRadioButton:
firstButton.isSelected();
Bordi
Se si dispongono diversi gruppi di pulsanti di opzione in una finestra di solito si vuole distinguere
visivamente di quale gruppo fa parte ciascuno di essi. Swing offre un set di bordi da utilizzare per
questo scopo. E’ possibile applicare un bordo a un qualsiasi componente che estenda
JComponent. L’utilizzo più comune consiste nel definire un bordo attorno al pannello e riempire il
pannello con altri elementi dell’interfaccia utente.
1. Si chiama il metodo statico di BorderFactory per creare un bordo. Si può scegliere uno dei
seguenti stili:
3. Se si vogliono utilizzare tutte le possibilità, si possono combinare due diversi bordi con una
chiamata BorderFactory.createCompoundBorder(border1, border2). Il primo argomento
specifica l’outer border, il secondo l’inner.
Si possono aggiungere nuove voci in una posizione qualsiasi dell’elenco con il metodo
insertItemAt.
Si possono aggiungere voci di ogni tipo; la casella combinata richiama il metodo toString di
ciascuna voce per visualizzarla.
Slider
Le caselle combinate permettono agli utenti di scegliere in un set discreto di valori. Gli slider
permettono invece di scegliere in un set continuo di valori per esempio un numero compreso tra 1
e 100.
Il metodo più comune per costruire uno slider è indicato di seguito:
Se l’utente fa scorrere la barra dello slider, il valore dello slider passa dal valore minimo a quello
Massimo con continuità. Quando si cambia il valore si invia un ChangeEvent a tutti i listener di
modifica.
Per essere avvisati quando avviene un cambiamento si deve aggiungere un oggetto che
implementi l’interfaccia ChangeListener mediale il metodo addChangeListener. Questa
interfaccia ha un solo metodo, stateChanged, che rileva il valore dello slider:
Si può migliorare l’aspetto dello slider aggiungendo una serie di tacche. Per esempio:
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(5);
Lo slider viene decorato con tacche più grandi ogni 20 unità e con tacche più piccole ogni 5
unità. Le unità fanno riferimento ai valori dello slider, non hai pixel.
Queste istruzioni impostano solo le unità delle tacche. Per renderle visibili si deve chiamare
la seguente istruzione:
slider.setPaintTicks(true);
Si può obbligare lo slider ad agganciarsi alle tacche. Ogni volta che l’utente smette di
trascinare lo slider in questa modalità, la barra si sposta sulla tacca più vicina. Questa
modalità viene attivata con la seguente istruzione:
slider.setSnapToTicks(true);
slider.setPaintLabels(true);
Le etichette possono essere, oltre che numeri, di altri tipi per esempio stringhe o icone
anche se la procedura è un po’ contorta. L’autoboxing facilita questo compito:
1. E’ necessario riempire una tabella hash con chiavi di tipi Integer (valore della tacca)
e valori di tipo Component (di solito si utilizzano oggetti JLabel).
Per eliminare la “scia” dello slider che si sposta, si chiama la seguente istruzione:
slider.setPaintTrack(false);
slider.setInverted(true);
Il componente JSpinner
Il componente JSpinner è una casella di testo con due piccoli pulsanti su un lato. Quando si fa click
sui pulsanti, il valore della casella di testo viene incrementato o decrementato. I valori dello
spinner possono essere numeri, date, valori di un elenco oppure, come nella maggior parte dei
casi, una sequenza qualsiasi di valori rispetto ai quali è possibile determinare i valori precedenti e
successivi.
L’impostazione predefinita prevede che lo spinner sia costituito da interi e che i pulsanti
definiscano incremento e decrementi di 1.
Si ottiene il valore corrente chiamando il metodo getValue che restituisce un Object. Per
questo oggetto va definito un cast Integer e si recupera il valore tramite il wrapper
corrispondente:
Sono disponibili due costruttore SpinnerNumberModel, uno con parametri int e l’altro con
parametri double. Nel caso in cui anche uno solo dei parametri sia un numero a virgola
mobile si utilizza il secondo costruttore.
Gli spinner non si limitano a utilizzare valori numerici. Si può impostare uno spinner in grado di
replicare una collezione qualsiasi di valori. E’ sufficiente passare uno SpinnerListModel al
costruttore JSpinner. Per esempio:
String[] fonts =
GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyName();
JSpinner listSpinner = new JSpinner(new SpinnerListModel(fonts);
Un altro utilizzo comodo dello spinner riguarda le date che l’utente può incrementare o
decrementare. Uno spinner di questo tipo viene inizializzato con la data odierna mediante
la seguente chiamata:
Swing supporta anche un altro tipo di elementi molto diffuso nelle interface utente: I menu a
discesa. Una barra dei menu nella parte superiore della finestra contiene i nomi dei menu a
discesa. Facendo click su un nome si apre il nume che contiene le voci di menu e i menu secondari.
Quando l’utente fa click su una voce di menu, si chiudono tutti i menu e si invia un messaggio al
programma.
Una barra dei menu è semplicemente un componente che può essere aggiunto nella posizione
desiderata, di solito si vuole che compaia nella parte superiore di un frame.
frame.setJMenuBar(menuBar);
menuBar.add(editMenu);
ActionListener lister = . . . ;
pasteItem.addActionListener(listener);
Il metodo add(String s) della classe JMenu permette di aggiungere facilmente una voce di
menu alla fine di un menu e inoltre restituisce la voce di menu appena creata come
nell’esempio:
E’ inoltre possibile creare voci di menu formate da caselle di controllo o pulsanti di opzione
all’interno di un menu
cutItem.setIcon(“cut.gif”);
Menu pop-up
Un menu pop-up è un menu che non è collegato a una barra dei menu ma si può trovare in una
qualsiasi posizione.
Si crea un menu pop-up in modo analogo a come si crea un menu normale, ma un menu
pop-up non prevede un titolo:
popup.show(panel, x, y);
Di solito si imposta un menu pop-up in modo che compaia quando l’utente fa click su un
determinato pulsante del mouse (il cosiddetto menu contestuale). Ad esempio in Windows
corrisponde al pulsante secondario del mouse (solitamente quello destro).
component.setComponentPopupMenu(true);
Mnemonici da tastiera
L’utente esperto trova molto comodo selezionare i menu e le voci di menu mediante mnemonici
da tastiera (mnemonic).
Per selezionare un menu di livello superiore dalla barra dei menu, si preme il tasto ALT
insieme alla lettera mnemonica. Per esempio, si preme ALT+H per selezionare il menu Help.
Si possono definire mnemonici da tastiera per le voci di menu specificando una lettera nel
costruttore della voce di menu:
Se è presente un oggetto Action, si può aggiungere lo mnemonico come valore del tasto
Action MNEMONIC_KEY, come indicato di seguito:
Il carattere mnemonico da tastiera viene visualizzato automaticamente nel menu, con la lettera
sottolineata. Quando si visualizza il menu, l’utente deve solo premere il tasto T per selezionare la
voce corrispondente.
Può accadere di non voler sottolineare la prima lettera della voce di menu che coincide con la
lettera mnemonica. Per esempio, se si imposta la lettera “A” per la voce di menu ”Save As”, ha più
senso sottolineare la seconda “A” (Save As).
cutItem.setDisplayedMnemonicIndex(5);
Acceleratori da tastiera
Gli mnemonici da tastiera permettono di selezionare un menu secondario o una voce di menu dal
menu aperto. Al contrario gli acceleratori (accelerator) sono scorciatoie da tastiera che
permettono di selezionare voci di menu senza aprire il menu corrispondente. Per esempio, molti
programmi collegano gli acceleratori CTRL+O e CTRL+S in corrispondenza delle voci Open e Save
dal menu File.
Per collegare un acceleratore a una voce di menu si utilizza il metodo setAccelerator che
prende come parametro un oggetto di tipo KeyStroke. Per esempio la seguente chiamata
collega l’acceleratore CTRL+O alla voce di menu openItem:
openItem.setAccelerator(KeyStroke.getKeyStroke(“ctrl O”);
Si possono collegare gli acceleratori sono alle voci di menu, non ai menu. In effetti gli
acceleratori, non aprono il menu, ma attivano direttamente l’evento azione a esso
associato.
Barre degli strumenti
Ciò che rende speciali le barre degli strumenti è che si possono spostare in una posizione, per
esempio lungo uno dei quattro bordi del frame. Quando si rilascia il pulsante del mouse, la barra
degli strumenti viene collocata nella nuova posizione. Inoltre può anche essere completamente
sganciata dal frame; in questo caso è contenuta in un suo frame. Quando si chiude un frame che
contiene una barra degli strumenti sganciata, la barra ritorna nel frame originale.
Per creare una barra degli strumenti e per aggiungere un componente all’interno:
oppure si specifica una stringa titolo che deve comparire quando la barra degli strumenti
non è agganciata ai bordi:
oppure si può aggiungere un oggetto Action che mostra la piccola icona dell’azione:
bar.add(blueAction)
bar.addSeparator();
I pulsanti sono i component più comuni all’interno delle barre degli strumenti, ma non ci sono
limitazioni nei component che si possono aggiungere. Per esempio, si può aggiungere una casella
combinata.
Suggerimenti
Uno svantaggio delle barre degli strumenti è che gli utenti possono confondere il significato delle
piccole icone che si trovano su di esse, Per risolvere questo problema è progettisti delle interfacce
hanno inventato i suggerimenti (tooltip). Un suggerimento vinee attivato quando il cursore si
ferma per qualche istante sopra un pulsante. Quando l’utente allontana il mouse, il suggerimento
viene rimosso.
exitButton.setToolTipText(“Exit”);
exitAction.putValue(Action.SHORT_DESCRIPTION, “Exit”);
Finestre di dialogo
Finora tutti I component dell’interfaccia utente sono stati fatti comparire in un frame creato
dall’applicazione. Questa è la situazione più comune se si scrivono applet da eseguire in un
browser web. Se invece si scrivono applicazioni, è preferibile distinguere le finestre di dialogo per
fornire o acquisire informazioni dall’utente.
Analogamente alla maggior parte dei sistemi a finestre, AWT distingue tra finestre di dialogo
modali e non modali. Una finestra di dialogo modale non permette agli utenti di interagire con le
altre finestre dell’applicazione fintanto che la si utilizza; viene utilizzata quando è necessario
ricavare determinate informazioni dall’utente prima di proseguire con l’esecuzione del
programma. Una finestra di dialogo non modale, invece permette all’utente di digitare
informazioni nella finestra e nel resto dell’applicazione. Un esempio di finestra di dialogo non
modale è rappresentato dalla barra degli strumenti.
JOptionPane
Swing prevede una classe JOptionPane, che permette di realizzare una semplici finestre di dialogo
modali: prevede un set di finestre che possono bastare quando è necessario chiedere all’utente
una singola informazione.
La classe JOptionPane ha quattro metodi statici che mostrano queste finestre di dialogo:
DEFAULT_OPTION YES_NO_OPTION
YES_NO_CANCEL_OPTION OK_CANCEL_OPTION
Ognuno di questi metodi prevede come primo parametro il componente genitore, che si
può comunque settare a null qualora non dovesse esserci.
Una tipica finestra di dialogo, ha i seguenti componenti:
1. un’icona sul lato sinistro che dipende da uno dei seguenti cinque tipi di messaggi:
Inoltre può avere un componente aggiuntivo per l’input dell’utente; per esempio una
casella di testo oppure una casella combinata.
JFileChooser
Quando si scrive un’applicazione si vuole spesso essere in grado di aprire e salvare dei file. Swing
propone una classe JFileChooser che permette di visualizzare una finestra di dialogo modale per la
selezione dei file simile a quella utilizzata dalla maggior parte delle applicazioni native.
I passi necessari per realizzare una finestra di dialogo sono:
chooser.setCurrentDirectory(new File(“.”));
Ciò che si deve sapere per ora dell’oggetto File è che il costruttore File(String filename)
trasforma un file o una directory in un oggetto File.
chooser.setSelectedFile(new File(filename));
4) Per consentire all’utente di selezionare più file nella finestra di dialogo, si chiama il metodo
setMultiSelectionEnabled(true); questa opzione è facoltativa
6) L’impostazione predefinita prevede che l’utente possa selezionare solo i file. Se si vuole che
l’utente possa selezionare le directory si chiama il metodo setFileSelectionMode:
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
7) Non essendo una sottoclasse di JDialog, invece di chiamare setVisible(true) si chiamano i
metodi showOpenDialog oppure showSaveDialog. In queste chiamate si deve definire il
componente genitore:
La classe FileFilter definisce due metodi astratti che vanno ridefiniti nella sottoclasse:
boolean accept(File f)
String getDescription()
Il primo deve restituire true se il File f deve essere accettato e quindi visualizzato, false se
invece deve essere ignorato. Il secondo serve per fornire la descrizione che JFileChooser
visualizza nell’elenco dei filtri selezionabili dall’utente.
chooser.addChooSableFileFilter(new TxtFilter());
Se si vuole si può realizzare una classe più generica, in modo che possa essere facilmente
riutilizzata per estensioni differenti passando al costruttore la Stringa dell’estensione che si
vuole filtrare e la Stringa della descrizione che si vuole far apparire
Selettore di colori
Un altro selettore fornito da Swing è JColorChooser. Questo selettore viene utilizzare per scegliere
il valore di un colore; inoltre contiene metodi per creare finestre di dialogo che lo contengano.
Di seguito è riportato come si visualizza una finestra di dialogo modale per il selettore di
colori:
In alternative si può visualizzare una finestra di dialogo non modale relativa a un selettore
di colori:
1. un componente genitore
2. il titolo della finestra di dialogo
3. un flag per selezionare una finestra di dialogo modale o non modale
4. un selettore di colori
5. listener per i pulsanti OK e Cancel, oppure null se non si vuole un listener
L’esempio di seguito costruisce una finestra di dialogo non modale che imposta il colore di
sfondo quando l’utente fa clic sul pulsante OK:
chooser = newJColorChooser();
dialog = JColorChooser.createDialog
(parent, “Background Color”, false, chooser,
new ActionListener() {
public void actionPerformed(ActionEvent event) {
setBackground(chooser.getColor());
}
}, null);
// l’ultimo parametro null significa che non c’è il listener del pulsante cancel