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

Lezione 08:

INTERFACCE GRAFICHE IN JAVA - II

Componenti Java

Una interfaccia e' fatta da:

Vedere "A Visual Guide to Swing Components", http://java.sun.com/docs/books/tutorial/ui/features/components.html

In Java tutti questi sono detti componenti e, tranne le finestre top-level, sono classi che ereditano (direttamente o indirettamente) dalla classe base JComponent (a sua volta sotto-classe della classe AWT Component).

Le finestre topo-level invece ereditano indirettamente dalla classe AWT Window (a sua volta sotto-classe della classe AWT Component).

Panoramica sui componenti Java

Citiamo solo i piu' interessanti. Per gli altri e anche per descrizione dettagliata delle classi e dei loro metodi ved. il manuale in linea http://java.sun.com/j2se/1.4.2/docs/api/index.html.

Contenitori Top-level o finestre:

Contenitori intermedi:

Dispositivi attivi o di controllo (grafica e comportamento, cioe' anche input dall'utente, ciascun tipo di dispositivo di controllo e' adatto a ricevere un certo tipo di input):

Dispositivi inerti (solo grafica, cioe' solo output verso l'utente):

Dispositivi specifici per scopi particolari:

Gerarchia di contenimento

Un contenitore puo' contenere dispositivi o altri contenitori. Un contenitore intermedio e' contenuto in un altro contenitore, che puo' essere top-level o intermedio.

Si ha una gerarchia di contenimento separata per ogni finestra dell'interfaccia (es: due se ho una finestra principale e una finestra di dialogo).

La gerarchia di contenimento e' descritta da un albero dove la relazione padre-figlio rispecchia la relazione di contenimento.

Nota bene: La "gerarchia" di contenimento rappresenta la relazione di contenimento fra i componenti (componente figlio occupa un'area di schermo "ritagliata" dentro quella del componente padre).
Non ha niente a che vedere con la "gerarchia" delle classi nel paradigma object-oriented (che rappresenta invece la relazione super-classe / sotto-classe).

Ogni contenitore ha un layout manager che stabilisce in che modo gli oggetti devono essere dislocati al suo interno.
Fanno eccezione alcuni contenitori piu' sofisticati (es. JScrollPane, JSplitPane) che hanno un proprio modo predefinito di disporre il contenuto).

Layout Management

Processo di stabilire automaticamente dimensioni e posizione delle componenti all'interno di un contenitore. Ogni contenitore (sia top-level che intermedio) ha un layout manager.

I layout manager sono oggetti di classi che implementano l'interfaccia Java AWT "LayoutManager".

Potrei lavorare senza layout manager, ma allora dovrei fornire posizione assoluta di ogni componente all'interno del contenitore, ed avrei problemi quando il contenitore top-level viene redimensionato dall'utente.

La super-classe Container ha i seguenti metodi, che percio' sono ereditati da tutte le classi di contenitori:

A seconda del tipo di layout manager presente, va usata l'una o l'altra forma del metodo "add".

Questo si applica ai contenitori di tipo generale (es. JPanel e il pannello di contenuto di una finestra).

I contenitori che hanno un proprio modo predefinito di disporre il contenuto (es. JScrollPane, JSplitPane) spesso hanno anche proprie funzioni per aggiungere componenti.

Classi di layout manager

Esempio

Il programma ExLayout.java accetta Flow, Border, o Grid come opzioni da command line e mostra questi tre layout in azione. Crea 5 etichette con sfondo di colori diversi e le dispone secondo il layout specificato.

Inizialmente impacchetta la finestra nel minimo spazio sufficiente. Quando l'utente cambia le dimensioni alla finestra, il layout manager ne riadatta il contenuto.

FlowLayout (tutti in fila)

I componenti sono messi uno dopo l'altro orizzontalmente finche' ci stanno, poi si va a capo e si forma un'altra linea, ecc.

Costruttori della classe FlowLayout:

Per aggiungere componenti si usa il metodo "add" nella forma senza posizione. I componenti sono messi in fila nello stesso ordine in cui sono aggiunti.

BorderLayout (centro + 4 punti cardinali)

Il contenitore e' diviso in 5 zone:

+--------------------------+
|          NORTH           |
+------+------------+------+
| EAST |   CENTER   | WEST |
+------+------------+------+
|          SOUTH           |      
+--------------------------+

La zona CENTER tende ad occupare tutto lo spazio eccedente quando la finestra viene allargata.

Cosruttori della classe BorderLayout:

Per aggiungere componenti si usa la forma di "add" con la posizione, che e' una fra BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.EAST, BorderLayout.WEST, BorderLayout.CENTER.
Il componente viene aggiunto a quella specificata tra le 5 zone.
Va messo un solo componente per zona! E' permesso lasciare vuote alcune zone, che assumeranno dimensione nulla.

GridLayout (griglia)

Il contenitore e' organizzato a tabella con un certo numero di righe e colonne.

Cosruttori della classe GridLayout:

Per aggiungere componenti si usa la forma di "add" senza posizione.
I componenti vengono aggiunti nell'ordine a riempire la griglia riga dopo riga:

+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
| 5 | 6 | 7 | 8 |
+---+---+---+---+
Se voglio lasciare vuote delle posizioni, metto come riempitivo una etichetta (classe JLabel) senza testo.

Impacchettamento

I contenitori top-level (finestre) hanno metodo

Da chiamare dopo aver aggiunto tutte le componenti e sottocomponenti alla finestra e prima di renderla visibile.

Usa i layout manager di tutti i contenitori presenti nella gerarchia di contenimento che ha per radice la finestra.

Per la visualizzazione

Le finestre appena costruite sono per default non visibili, le devo rendere visibili da programma con apposita istruzione (setVisible).

Gli altri componenti sono per default visibili all'interno del contenitore che li contiene, purche' questo sia visibile.
Un componente sara' visibile sullo schermo se e' visibile e lo sono anche tutti i contenitori risalendo la gerarchia di contenimento fino alla finestra radice.

Esistono i metodi (comuni a tutti i componenti perche' appartengono alla super-classe Component):

Dispositivi in Java

Etichetta (JLabel)

Serve per mostrare informazioni (es. un titolo, un messaggio di istruzioni o di errore...). Occupa un'area rettangolare con bordi non segnati, e puo' contenere una stringa e/o un'immagine.

Esempi:
Ne abbiamo visto uno con etichetta testo in SwingExample (ved. lezione scorsa).
Vediamo tutte le possibilita' in ExJLabel, serve anche il file immagine fiore.gif (nel sorgente ci sono le tre alternative, due commentate e una no, bisogna editare e cambiare per vedere le altre).

Bottone di comando (JButton)

Serve per invocare un'operazione (es. per chiudere una finestra).

Ha l'aspetto di un rettangolo con bordi ben segnati e e puo' contenere una stringa e/o un'immagine (che indica l'operazione corrispondente).

Sensibile al click del mouse (evento di azionamento del bottone). Durante il click il bottone cambia aspetto per dare feedback che e' stato azionato.

Esempi:
Ne abbiamo visto uno con etichetta testo in SwingExample (ved. lezione scorsa).
Vediamo tutte le possibilita' in ExJButtons, serve anche il file immagine fiore.gif.

Bottone a due stati (JCheckBox)

Serve per impostare selezione o non selezione di una scelta.

Ha l'aspetto di una casellina con un'etichetta testuale accanto. Il quadrato puo' contenere un segno, la cui presenza o assenza denota lo stato della scelta.
Ha uno stato interno booleano (per dire selezionato o non selezionato), con i metodi setState e getState.

Sensibile al click del mouse (due eventi: azionamento e cambiamento di stato).
Al click lo stato del bottone si inverte (da selezionato a non selezionato o viceversa), dandone feedback grafico.

Esempi: rimandati a dopo i bottoni radio.

Metodi interessanti della classe ItemEvent, parametro della funzione (callback) itemStateChanged di ItemListener:

Inoltre tutte le classi gli eventi (anche la gia' citata ActionEvent) hanno il metodo:

Bottoni radio (JRadioButton)

I bottoni radio sono simili ai check box, ma sono presenti a gruppi e in ogni momento solo un bottone del gruppo puo' essere selezionato (selezionarne uno automaticamente disseleziona quello precedente).

Si dice che le scelte sono mutuamente esclusive.

Per ottenere un gruppo di radio button devo:

  1. creare i vari bottoni di classe JRadioButton
  2. creare un nuovo oggetto "gruppo", di classe ButtonGroup
  3. aggiungere ciascuno di essi al gruppo
Attenzione: il gruppo non e' un contenitore, in cui i bottoni sono collocati nell'interfaccia, e' solo un meccanismo per dire quali bottoni devono diventare mutuamente esclusivi

Esempio:
rb1 = new JRadioButton("uno",true); // e' inizialmente "on"
rb2 = new JRadioButton("due");
rb3 = new JRadioButton("tre");
ButtonGroup bg = new ButtonGroup();
bg.add(rb1);
bg.add(rb2);
bg.add(rb3);

Quando utente preme un bottone radio in un gruppo, si generano tre eventi:

  1. ItemEvent sul bottone premuto: suo stato cambia da non selezionato a selezionato
  2. ItemEvent sul bottone che era selezionato in precedenza: suo stato cambia da selezionato a non selezionato
  3. ActionEvent sul bottone premuto

Java distingue graficamente i JCheckBox (scelte indipendenti) dai JRadioButton (che fanno parte di un gruppo di scelte esclusive) tramite diversa foma della casellina.

Esempio

Il programma Ex3Buttons mostra i tre tipi di bottoni (di comando, check box, radio).

Esercizio: aggiungere la gestione degli eventi (facendo stampare qualcosa su standard output ad ogni bottone).

Campo di testo (JTextField)

Permette l'introduzione di input testuale. Esempio: nome utente per login.

Ha l'aspetto di un'area rettangolare in cui l'utente inserisce il testo. Quando l'utente clicca all'interno dell'area, appare un cursore, i caratteri digitati successivamente sulla tastiera sono diretti al campo di input e vengono mostrati (echo) come feedback.

Sensibile a quando l'utente preme return all'interno dell'area di inserimento (evento di azionamento).

Posso leggere e modificare la stringa contenuta: metodi getText e setText

Il campo di testo puo' essere editabile (default) o non editabile (puo' essere utile renderlo non editabile in alcune situazioni): metodi isEditable e setEditable.

Esempio: rimandato a dopo l'area di testo.

Area di testo (JTextArea)

Area di testo a piu' linee (eventualmente posso collocarla dentro un pannello con barre di scorrimento).

La gestione degli eventi e' complessa. Posso gestire anche selezione di parti di testo...

Metodi interessanti della classe TextArea:

Esempio

Il programma ExJText mostra un campo e un'area di testo. L'area di testo riporta ogni volta cio' che l'utente digita nel campo di testo.

Per tutti i componenti Java

I metodi elencati qui sono in tutte le classi di componenti perche' ereditati dalla super-classe comune Component (talvolta JComponent).

Colore

In Java i colori sono oggetti della classe Color, un colore puo' essere creato dando le tre componenti red,green,blue, oppure posso usare uno dei colori gia' fatti che sono costanti nella classe Color (es. Color.red, Color.white...).

Abilitazione e disabilitazione

Un componente puo' essere disabilitato cioe' gli puo' essere impedito di ricevere eventi. Per default e' abilitato.

Di solito si disabilitano i dispositivi di controllo che corrispondono ad opzioni non sensate nello stato corrente dell'applicazione. I dispositivi non attivi sono distinguibili graficamente (es: colore meno intenso).

Dimensioni e allineamenti

Le dimensioni di un componente non sono in genere fissate:

Esistono funzioni per assegnare a un componente delle dimensioni specificate, ma di solito queste non verranno rispettate da Java, per i motivi sopra elencati.
Infatti Java assegna le dimensioni ai componenti secondo un processo di calcolo (innescato per es. dalla funzione "pack").

Per assegnare dimensioni e posizione a un componente, Java tiene conto di informazioni fornite dal componente:

Metodi interessanti:

Le dimensioni preferite e gli allineamenti hanno valori di default (es. per un bottone la dimensione preferita e' quella grande a sufficienza per mostrare tutta l'etichetta e non piu' grande del necessario).