INTERFACCE GRAFICHE IN JAVA
[Per corso su Java vedere
http://java.sun.com/docs/books/tutorial/]
Java prevede nella sua API librerie di classi da usare in un programma
per creare e gestire GUI.
Parte delle Java Foundation Classes (JFC), librerie di classi
standard Java.
In Java sia le finestre che gli elementi/dispositivi di interfaccia
sono chiamati componenti.
Due librerie di componenti:
Note storiche
Il primo a nascere e' Java Abstract Widget Toolkit (AWT),
gia' in Java 1.0, migliorato in Java 1.1.
Invariato nelle versioni successive.
- piu' limitato nella varieta' di componenti di interfaccia forniti
- componenti di interfaccia meno sofisticati
(es. bottoni possono avere etichette solo testuali)
- AWT components sono "heavyweight"
Java Swing e' presente a partire da Java 1.2
(ma esiste estensione Swing a Java 1.1):
- maggiore varieta' di compomenti di interfaccia
- componenti piu' sofisticati (es. posso avere bottoni etichettati
con testo e/o immagini)
- Swing components sono "lightweight" (piu' efficienti)
- aspetto riconfurabile (la stessa interfaccia puo' essere visualizzata
con aspetto stile Windows o stile Motif ecc.)
- funzioni avanzate per grafica 2D
Importante: NON mischiare
componenti AWT e Swing in un'interfaccia.
Le componenti AWT (heavyweight) vengono sempre disegnate sopra
le componenti Swing (lightweight), con possibile effetto errato
(es: tendine dei menu').
AWT e Swing hanno struttura e modo d'uso molto simile.
Li vediamo entrambi parallelamente.
Le classi di componenti di AWT hanno equivalente in Swing.
Componenti Swing si riconoscono perche' il nome inizia per
"J" (es: Button e JButton).
Metodo orientato a oggetti
Essendo Java un linguaggio object-oriented, tutto e' classe:
-
ogni tipo di componente di interfaccia: finestre, dispositivi...
-
ogni informazione accessoria associata ad una componente di interfaccia:
fonts, layout managers che controllano il posizionamento dei dipositivi
in una finestra...
-
ogni tipo di evento
-
le callback per gli eventi: per definire una callback devo definire
una classe "listener" (=ascoltatrice, recettrice) del tipo di evento
che mi interessa
Le classi sono organizzate in gerarchie di ereditarieta' secondo
paradigma object-oriented.
Schema di un programma che realizza interfaccia in Java
Esempio
L'interfaccia consta di una finestra contenente
un bottone e un'etichetta posizionati uno sopra l'altro.
L'etichetta mostra il numero di volte in cui il bottone e' stato azionato.
Quando utente aziona il bottone, l'etichetta si incrementa di una unita'.
import java.awt.*;
import java.awt.event.*;
public class AWTExample extends Frame
{
private static String labelPrefix = "Number of clicks: ";
private int numClicks = 0;
Label label = null;
Button button = null;
public AWTExample()
{
label = new Label(labelPrefix + "0 ");
button = new Button("Click me!");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{ numClicks++;
label.setText(labelPrefix + numClicks);
}
});
setLayout(new GridLayout(2, 1));
add(button);
add(label);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{ System.exit(0);
}
});
pack();
setVisible(true);
}
public static void main(String[] args)
{
AWTExample app = new AWTExample();
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SwingExample extends JFrame
{
private static String labelPrefix = "Number of clicks: ";
private int numClicks = 0;
JLabel label = null;
JButton button = null;
public SwingExample()
{
label = new JLabel(labelPrefix + "0 ");
button = new JButton("Click me!");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{ numClicks++;
label.setText(labelPrefix + numClicks);
}
});
Container panel = getContentPane();
panel.setLayout(new GridLayout(2, 1));
panel.add(button);
panel.add(label);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{ System.exit(0);
}
});
pack();
setVisible(true);
}
public static void main(String[] args)
{
SwingExample app = new SwingExample();
}
}
Interfaccia di AWTExample e di SwingExample (dopo vari click):
Schema generale
-
Importare i packages necessari
-
Stabilire finestra top-level
-
Stabilirne il contenuto
-
Stabilire gestione degli eventi nelle componenti
-
Far partire l'interfaccia
Importare i packages
Le JFC sono divise moduli chiamati packages.
Moduli principali di AWT: java.awt e java.awt.event.
Modulo principale di Swing: javax.swing, Swing e' un'estensione di AWT.
Stabilire finestra top-level
L'interfaccia e' realizzata dalla classe AWTExample,
sottoclasse di Frame
(classe AWT corrispondente ad una finestra top-level adatta ad essere
la finestra primaria di una applicazione).
Analogamente nel caso Swing SwingExample e'
sottoclasse di JFrame.
I punti 3,4,5 sono eseguiti nel costruttore della classe
AWTExample / SwingExample: l'interfaccia crea se stessa e parte.
Il main semplicemente esegue la costruzione di un oggetto della classe.
Stabilire il contenuto della finestra
Creare tutti i componenti (qui bottone e label) e posizionarli nella
finestra eventualmente usando contenitori intermedi.
Stabilire il layout manager dei contenitori usati.
-
In AWT: li aggiungo direttamente nel Frame (che e' un
contenitore).
-
In Swing: li aggiungo nel "pannello di contenuto" associato
al JFrame.
La relazione (gerarchia)
di contenimento ha la seguente rappresentazione ad albero:
Versione AWT:
Frame (finestra principale, contenitore)
|
+----+-----+
| |
JButton JLabel (bottone ed etichetta)
Versione Swing:
JFrame (finestra principale, contenitore top-level)
|
content panel (contenitore intermedio)
|
+----+-----+
| |
JButton JLabel (bottone ed etichetta)
In un'interfaccia piu' complicata potrei avere piu' livelli nella
gerarchia di contenimento.
Il layout manager stabilisce come sono posizionati i componenti dentro a un
contenitore.
Usiamo layout a griglia con 2 righe e 1 colonna.
L'istruzione pack fa si' che il contenuto della finestra venga
compattato per occupare il minimo spazio necessario.
Stabilire gestione degli eventi
Il bottone gestisce evento "attivazione" modificando l'etichetta della
label.
La finestra principale gestisce evento "chiusura" terminando l'applicazione.
Per gestire evento "attivazione" (classe Actionevent) e' necessario
definire una sotto-classe di ActionListener che implementi il metodo
ActionPerformed eseguendo l'operazione desiderata.
Poi creare un oggetto di tale classe ed associarlo al bottone.
Il tutto si puo' fare contemporaneamente: l'istruzione usata crea un
oggetto ActionListener dove il metodo ActionPerformed
e' ridefinito nel modo indicato
(ActionPerformed e' l'unico metodo di ActionListener).
Analogamente per evento "chiusura" (classe Windowevent) della
finestra.
Differenza: qui definisco sottoclasse di WindowAdapter invece che di
WindowListener perche' intendo riferinire solo il metodo
windowClosing (WindowListener ha anche altri metodi).
Esiste un adapter per ogni classe listener che prevede piu' di un
metodo. Le classi listener con un metodo solo non hanno bisogno di
adapter).
Far partire l'interfaccia
L'istruzione setVisible mappa sullo schermo la finestra top-level e tutto
il suo contenuto.
Da questo momento si innesca automaticamente il "ciclo degli eventi".
Componenti Java
Una interfaccia e' fatta da tre tipi di componenti:
-
Finestre top-level (sempre almeno una)
gestite dal window manager
-
Dispositivi
incaricati di mostrare informazioni e/o
catturare input
-
I dispositivi sono collocati dentro le finestre mediante
una gerarchia di contenitori intermedi
(idea delle scatole cinesi)
Tutti questi elementi (finestre top-level, contenitori, dispositivi)
in Java sono detti componenti
e sono classi che ereditano dalla classe base
Component (oppure MenuComponent) in AWT,
e da JComponent in Swing.
Ogni contenitore ha un layout manager che stabilisce in
che modo gli oggetti devono essere dislocati al suo interno.
Le finestre top-level sono anch'esse contenitori, detti contenitori
top-level.
Un contenitore puo' contenere dispositivi o altri contenitori.
Un contenitore intermedio e' contenuto in un altro contenitore, che
puo' essere top-level o intermedio.
Gerarchia di contenimento
Descritta da foresta di alberi dove la relazione padre-figlio nell'albero
rispecchia la relazione di contenimento.
La foresta e' fatta da tanti alberi
quante le finestre top-level dell'interfaccia
(es: 2 alberi se ho una finestra principale e un dialogo).
- Finestre top-level: radici della foresta
- Contenitori intermedi: nodi interni della foresta
- Dispositivi: foglie della foresta
Nota bene:
La "gerarchia" di contenimento rispecchia la gerarchia
di annidamento tra le finestre che realizzano le varie componenti.
Non ha niente a che vedere con la "gerarchia" delle
classi nel paradigma object-oriented.