Paola Magillo, Univestita' di Genova, Corso di Programmazione II per SMID, a.a. 2007-2008.

Lezione 13:

CASO DI STUDIO: GESTIONE DI UNA BIBLIOTECA - PARTE II
Interfaccia grafica

L'interfaccia grafica per la gestione della biblioteca e' organizzata nel seguente modo.

Il programma viene lanciato o senza parametri oppure con parametro il nome di un file che contiene una biblioteca.

La finestra principale contiene un'immagine e ha una barra di menu' con tre menu':

  1. Menu "generale" con voci:
  2. Menu' "gestione biblioteca" con voci:
  3. Menu' "gestione libri" con voci:

Tranne "salva" e "esci", tutte le altre voci, quando selezionate, fanno apparire una finestra di dialogo che chiede all'utente le informazioni necessarie per compiere l'operazione:

Inoltre, in caso di errore appare una finestra di dialogo col messaggio d'errore.

Classi che costituiscono l'interfaccia grafica:

Dopo averle scaricate generare la documentazione con Javadoc (digitando: javadoc *.java).

Finestre di dialogo

Siccome le finestre di dialogo usate nell'interfaccia hanno caratteristiche comuni, sono organizzate in una gerarchia di ereditarieta' (= gerarchia di super-classi e sotto-classi):

          Dialog1
             |
   +---------+---------+
   |                   |
Dialog2             Dialog4
   |
Dialog3

  • Dialog1:
    Super-classe di tutte, ha solo bottone Ok per chiudere la finestra.
    Non usata direttamente, sono usate le sotto-classi.
  • Dialog2:
    Sotto-classe di Dialog1, ha anche posto per le informazioni di un libro, e bottone Canc.
    Usata per acquisire un nuovo libro (utente digita le informazioni e poi preme Ok oppure Canc).
  • Dialog3:
    Sotto-classe di Dialog2, ha anche bottoni per scorrere avanti/indietro l'array dei libri.
    Usata per prestare, restituire e dismettere un libro (utente scorre l'array, quando ha il libro voluto preme Ok, oppure preme Canc).
  • Dialog4:
    Sotto-classe di Dialog1, ha anche un messaggio.
    Usata per notificare gli errori.

Vediamo in dettaglio le classi...

Dialog1

Sorgente.

La finestra e' divisa (tramite BorderLayout) in parte superiore (nord), centrale e inferiore (sud).
La parte sud contiene un pannello (con FlowLayout) con bottone Ok, le altre parti non sono usate.

  Dialog1(Border)
     |
     |SOUTH
     |
   Panel(Flow)
     |
   Button

Ha metodo addOkListener per associare comportamento (ActionListener) al bottone Ok.

Ha due funzioni showListener() e hideListener() che ritornano due listener per mostrare e nascondere questa finestra di dialogo:

  1. il primo dovra' essere associato al bottone sulla finestra principale che fa apparire questa finestra di dialogo
  2. il secondo al bottone di questa finestra di dialogo che deve chiuderla senza far nulla (ora l'unica scelta e' il bottone Ok ma le sotto-classi potranno avere altri bottoni).

Dialog2

Sorgente.

La parte centrale e' occupata da un panello che mostra le informazioni di un libro della biblioteca. Per ottenere questo risultato, il pannello e' diviso in due: sotto-pannello sinistro con 3 label (diciture esplicative autore, titolo, copie) e sotto-pannello destro 3 campi di testo (posto per le info vere e proprie), entrambi a griglia 3x1.
La parte nord e' ancora vuota.
Aggiunge al pannello nella parte sud il bottone Canc.

          Dialog3(Border)
          /            |
         /SOUTH        |CENTER
        /              |
  Panel(Flow)       Panel(Border)
   |      |         |          | 
  2 Buttons         |WEST      |CENTER
                    |          |
            Panel(Grid3x1)    Panel(Grid3x1)
                |  |  |          |   |   |
                3 Labels        3 TextFields

Ha metodo addCancListener per associare comportamento (ActionListener) al bottone Canc.

Questa finestra sara' usata per acquisire un nuovo libro (utente digita le informazioni nei campi di testo e poi preme Ok oppure Canc).

Dialog3

Sorgente.

La parte nord e' occupata da un pannello con bottoni per scorrere l'array dei libri: primo, indietro, avanti, ultimo.
I campi di testo presenti nella parte centrale non sono editabili e vengono riempiti non piu' dall'utente ma dal programma, con le informazioni del libro corrente. Inoltre cambia il testo dell'etichetta esplicativa del numero di copie (dopo averla recuperata dal contenitore).

                   Dialog3(Border)
              /          |           \
             /SOUTH      |CENTER      \NORTH
            /            |             \
  Panel(Flow)       Panel(Border)       Panel(Grid1x4)
   |      |         |         |            | | | |
  2 Buttons         |WEST     |CENTER     4 Buttons
                    |         |
            Panel(Grid3x1)    Panel(Grid3x1)
                |  |  |          |   |   |
                3 Labels        3 TextFields

Questa finestra sara' usata per prestare, restituire e dismettere un libro (utente scorre l'array dei libri usando i quattro bottoni in alto, e poi sceglie il libro premendo il bottone Ok, oppure preme Canc).

Ha funzioni mostraLibro(int cod) e codiceScelto() per assegnare il libro che deve essere mostrato nei campi di testo e per leggere quale libro e' correntemente mostrato (in questo caso il libro e' rappresentato dalla sua posizione nell'array interno alla biblioteca).

Ha associata una biblioteca, che devo passare come parametro al costruttore.

Dialog4

Sorgente.

La parte centrale e' occupata da un'etichetta (label) che mostra un messaggio.

    Dialog4(Border)
     |          |
     |SOUTH     |CENTER
     |          |
Panel(Flow)    Label
     |
   Button

Ha metodo mettiMessaggio(String msg) che serve a impostare il messaggio.

Questa finestra sara' usata per notificare gli errori.

Finestra principale

Realizzata dalla classe GestioneBiblioteca, sotto-classe di Frame.

Sorgente.

Attributi (tutti privati):

Unico attributo pubblico: costante stringa BIBLIO (="biblio.txt") che contiene il nome convenzionale del file su cui salvare una biblioteca non caricata da file.

Costruttori

Per creare l'interfaccia grafica vera e propria, i costruttori chiamano il metodo ausiliario "costruisci".

Il metodo "costruisci" di GestioneBiblioteca

Il metodo "costruisci" costruisce le finestre di dialogo, associa i listener ai bottoni di tali finestre, costruisce i menu', associa i listener alle voci di menu'.
Vediamo in dettaglio i passi.

1) Crea finestra di dialogo per gli errori (dError) di classe Dialog4. Stabilisce comportamento per il bottone "Ok" (nascondera' la finestra, action listener ritornato dal metodo hideListener() chiamato sulla finestra di dialogo stessa).

2) Crea finestra di dialogo per nuovo libro (dNuovo) di classe Dialog2. Stabilisce comportamento per i bottoni "Ok" (action listener di classe EseguiNuovo, ved. dopo) e "Canc" (in modo analogo a "Ok" della finestra errori).

3) Crea finestra di dialogo per restituziuone libro (dRestit) di classe Dialog3. Stabilisce comportamento per i bottoni "Ok" (action listener di classe EseguiRestituzione, ved. dopo) e "Canc" in modo analogo a sopra.

4) Crea finestra di dialogo per prestito libro (dPresta) di classe Dialog3. Stabilisce comportamento per i bottoni "Ok" (action listener di classe EseguiPrestito, ved. dopo) e "Canc" in modo analogo a sopra.

5) Crea finestra di dialogo per dismette libro (dDismetti) di classe Dialog3. Stabilisce comportamento per i bottoni "Ok" (action listener di classe EseguiDismissione, ved. dopo) e "Canc" in modo analogo a sopra.

Tutte queste finestre di dialogo dipendono dal frame sul quale stiamo eseguendo "costruisci", che e' identificato da "this".

6) Crea e aggiunge le voci al menu' "generale", stabilisce i comportamenti delle voci.
Gli action listener delle voci del menu' generale (scrittura biblioteca e uscita dal programma) sono scritti direttamente "in loco".

7) Crea e aggiunge le voci al menu' "gestione biblioteca", stabilisce i comportamenti delle voci.
Le voci di questo menu' (nuovo libro e dismetti libro) hanno per action listener quello ritornato dal metodo showListener() della corrispondente finestra di dialogo: tale metodo apre la finestra. Sara' poi il listener del bottone Ok di tale finestra ad eseguire l'operazione vera e propria.

8) Crea e aggiunge le voci al menu' "gestione libri", stabilisce i comportamenti delle voci.
Riguardo agli action listener delle voci di questo menu' (presta libro e restituisci libro), vale quanto detto sopra per le voci del menu' "gestione biblioteca".

9) Stabilisce che il frame e' gestito con BorderLayout, di cui e' usata solo la parte centrale. In essa trova posto un pannello con immagine (oggetto di classe ExImage vista in lezione 9). L'immagine e' nel file libri.gif.

Gestione dei bottoni "Ok" nelle finestre di dialogo

Quattro classi interne a GestioneBiblioteca definiscono i comportamenti per i bottoni "Ok" delle 4 finestre di dialogo.
Tali classi implementano tutte ActionListener.

Funzionamento del listener EseguiNuovo:

  1. Controlla che i parametri (autore, titolo, numero copie) contenuti nei campi di testo della finestra di dialogo non siano vuoti.
  2. Se sono vuoti solleva eccezione.
  3. Eccezione si puo' sollevare anche nella conversione da stringa a intero del contenuto del campo che rappresenta il numero di copie.
  4. Se non vi sono eccezioni chiama sulla biblioteca la funzione nuovoLibro; poi pulisce e nasconde la finestra di dialogo.
  5. In caso di eccezione, imposta il messaggio nella finestra di dialogo degli errori, e la mostra.

Schema generale del funzionamento degli altri tre listener:

  1. Preleva dalla finestra di dialogo il codice del libro scelto, chiamando la funzione codiceScelto().
  2. Se il codice e' -1 (= nessun libro scelto) solleva eccezione.
  3. Se non vi sono eccezioni, esegue l'operazione chiamando sulla biblioteca l'opportuna funzione, cioe' a seconda dei casi dismettiLibro, prestaLiro o restitLibro; poi nasconde la finestra di dialogo.
  4. In caso di eccezione, imposta il messaggio opportuno nella finestra di dialogo degli errori, e la mostra.

Il main di GestioneBiblioteca

Il main guarda se sulla command-line e' dato un parametro. Se si', usa quel parametro come nome file da cui leggere la biblioteca. Altrimenti, considera una biblioteca vuota. Questo e' ottenuto chiamando uno o l'altro dei due costruttori della classe GestioneBiblioteca. Visualizza infine l'interfaccia.