Paola Magillo, Univestita' di Genova,
Corso di Interfacce Utente per Informatica, a.a. 2007-2008.
LABORATORIO - INTERFACCE GRAFICHE IN JAVA
Contesto generale
L'obiettivo e' realizzare in Java la tradizionale "calcolatrice"
con
- bottoni per le 10 cifre
- riquadro (non editabile) che mostra il valore corrente
- bottoni per le quattro operazioni binarie di addizione,
sottrazione, moltiplicazione, divisione (simboli + - * /)
- bottone per la fine (simbolo =)
- bottone per l'azzeramento del valore corrente (simbolo C)

Procederemo per gradi:
- prima la realizzazione della parte grafica dell'interfaccia
(senza gestione degli eventi)
- poi la gestione degli eventi per quanto riguarda la
scrittura del numero nel display
- poi la gestione delle operazioni aritmetiche con controllo sulla
"validita'" delle azioni dell'utente nello stato corrente
Non occorre consegnare nulla, questo e' solo un esercizio
che vi sara' utile per il progetto finale del corso.
Nel PRIMO LABORATORIO ci aspettiamo che facciate tutta la parte 1
e almeno qualcosa della parte 2.
SUGGERIMENTO:
E' molto utile programmare tenendo aperta
a fianco una finestra sul sito con il manuale on-line delle
classi Java:
http://java.sun.com/j2se/1.5/docs/api/index.html
1 - Realizzazione della parte grafica
L'obiettivo di questa prima parte e'
solo predisporre l'interfaccia, non di farla funzionare.
Cioe' creare le finestre con la gerarchia di
contenitori intermedi (con relativi layout manager)
e dispositivi, ma non ancora gestire gli eventi nei dispositivi.
Scelta dei dispositivi da usare
- per il display del numero abbiamo bisogno di un TextField
che puo' essere reso non editabile tramite apposito metodo
(cercate tra i metodi di TextField quello che serve allo scopo,
nota: lo troverete tra i metodi della super-classe TextComponent)
- per i tasti abbiamo bisogno di 16 istanze di Button
Scelta della gerarchia di contenimento e dei layout manager
La gerarchia di contenimento dell'interfaccia puo' essere (in AWT):
Frame
|
---+---
| |
TextField Panel
|
-----+-----
| .... |
Button .... Button
In Swing il text field e il panel non saranno direttamente dentro alla
finestra (JFrame), ma al suo pannello di contenuto.
Bisogna decidere i layout manager per i due contenitori:
il frame della finestra principale e il panel che contiene i bottoni:
Che cosa sarebbe successo se...
-
Scegliere nel border layout le posizioni NORTH + SOUTH oppure
NORTH + CENTER oppure CENTER + SOUTH provoca effetti diversi quando
l'utente redimensiona la finestra, provare per credere!
Perche'?
-
Scegliere per il frame un'altra classe di layout
manager al posto di border layout, per esempio poteva venire in
mente di usare un GridLayout 2 x 1, provoca un diverso
dimensionamento degli elementi, provare per credere!
Perche'?
Che cosa abbiamo ottenuto finora
L'interfaccia non gestira' ancora gli eventi,
quindi vedrete che agendo per esempio sui bottoni
questi vengono illuminati (lo fa Java automaticamente) ma
non si ha alcun effetto dal punto di vista dell'applicazione
(perche' non ci sono listener collegati).
2 - Gestione degli eventi per la scrittura del numero
Riprendiamo ora l'interfaccia e iniziamo a farla funzionare veramente.
Per adesso aggiungiamo la parte di gestione degli eventi relativa alla
scrittura del numero.
Abbiamo bisogno di una variabile che tenga il numero corrente.
- il numero corrente e' inizialmente zero.
- quando l'utente aziona un bottone-cifra, il numero corrente viene
moltiplicato per 10 e gli viene sommata la cifra corrispondente al
bottone azionato, il nuovo numero viene scritto nel text field
- quando l'utente aziona il bottone per l'azzeramento,
il numero corrente viene riportato a zero e viene scritto nel text field
Per realizzare questo comportamento serviranno:
- action listener per i bottoni delle 10 cifre
- action listener per il bottone di azzeramento
Gli action listener per le 10 cifre si comportano tutti allo stesso modo,
cambia solo la cifra.
Quindi possiamo fare una sola classe che, dentro l'implementazione del
metodo actionPerformed andra' a vedere quale dei 10
bottoni e' stato azionato (c'e' un metodo della classe Event
che ritorna l'oggetto su cui e' avvenuto l'evento, cercatelo)
Che cosa abbiamo ottenuto finora
La nostra interfaccia ora scrive il numero sul display, ma i tasti
operazioni (+ - * / =) ancora non fanno nulla quando vengono premuti.
3 - Gestione degli eventi completa
Completiamo ora la gestione degli eventi per arrivare alla calcolatrice
funzionante.
Notiamo subito che per un'operazione occorrono due operandi, dei quali
solo uno e' quello correntemente mostrato sul display.
Non sempre esistono entrambi, quando non esistono entrambi l'operazione
non si puo' fare...
Dobbiamo quindi progettare lo stato interno della calcolatrice
e vedere come va modificato in base alle azioni dell'utente,
inoltre vedere i casi in cui certe azioni dell'utente non sono valide...
Variabili di stato per la calcolatrice
Parte "invisibile" sull'interfaccia (variabili solo dell'applicazione):
-
a1 = primo operando, che e' anche il risultato dell'ultima
operazione (se per ultima cosa e' stata fatta un'operazione), puo'
non esistere
-
op = operazione impostata (una tra le quattro), puo' non esistere,
puo' esistere solo se esiste il primo operando
-
a2 = secondo operando, puo' non esistere, puo' esistere solo se
esiste l'operazione
Parte "visibile" sull'interfaccia:
- il numero visualizzato nel text field, che e'
il secondo operando se esiste, altrimenti il primo se esiste,
altrimenti niente
Stati possibili
- s0 "attendo primo operando" (e' anche lo stato iniziale)
- s1 "ho primo operando, attendo operazione"
- s2 "ho primo operando e operazione, attendo secondo operando"
- s3 "ho tutto, attendo il via per applicare operazione ai
due operandi"
Operazioni valide e transizioni di stato
- Da s0 posso andare:
- in s1 se l'utente batte un tasto cifra
(si imposta il primo operando a1)
- nessun'altra azione dell'utente e' valida
- Da s1 posso andare:
- in s2 se l'utente batte un tasto operazione + - * /
(si imposta l'operazione op)
- in s0 se l'utente batte l'azzeramento C
- resto in s1 se l'utente batte un tasto cifra
(si modifica il primo operando a1)
- nessun'altra azione dell'utente e' valida
- Da s2 posso andare:
- in s3 se utente batte un tasto cifra
(si imposta il secondo operando a2)
- in s0 se l'utente batte l'azzeramento C
- nessun'altra azione dell'utente e' valida
- Da s3 posso andare:
- in s1 se utente batte il tasto "uguale"
(si calcola il risultato che diventa il primo operando a1)
- in s2 se utente batte il tasto un tasto operazione
(si calcola il risultato che diventa il primo operando a1,
si imposta la nuova operazione op)
- in s3 se utente batte un tasto cifra
(si modifica il secondo operando a2)
- in s0 se l'utente batte l'azzeramento C
Implementazione dello stato interno
Dovrete aggiungere delle variabili per a1, op, a2.
Probabilmente vi servira' una
variabile stato per tenere lo stato corrente
(a seconda dello stato saprete se
il contenuto attuale di a1, op, a2 e' valido).
In alternativa potete prevedere valori speciali "non validi"
per a1, op, a2 e desumere lo stato dall'eventuale non
validita' di alcune di queste tre variabili.
Scrittura degli action listener
Gli action listener dovranno agire anche sulle variabili di stato interno
oltre che sulla parte "visibile" dell'interfaccia (secondo
le transizioni di stato illustrate sopra). Bisognera':
- scrivere gli action listener per i bottoni delle 4 operazioni
(sono uguali, cambia solo l'operazione da
applicare, si puo' fare una sola classe come gia' detto per
i bottoni delle cifre, ved. parte 2)
- scrivere l'action listener per il bottone "uguale"
- modificare gli action listener (scritti nella parte 2) per
i bottoni delle cifre e il bottone di azzeramento "C"
Abilitazioni e disabilitazioni
Ricordate di disabilitare i dispositivi corrispondenti ad
azioni non valide e di riabilitarli quando l'azione diventa valida!
Anche questo si fa dentro gli action listener.
Ultima finitura
Mettere anche un
window listener per gestire azione di chiusura della finestra
da parte dell'utente.
Adesso la calcolatrice e' davvero finita!