Paola Magillo, Univestita' di Genova, Corso di Interfacce Utente per Informatica, a.a. 2002-2003.

INTERFACCE GRAFICHE IN JAVA - I

[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. Java Swing e' presente a partire da Java 1.2 (ma esiste estensione Swing a Java 1.1): 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: 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'.

Versione AWT (AWTExample.java)

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();
    }
}

Versione Swing (SwingExample.java)

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

  1. Importare i packages necessari
  2. Stabilire finestra top-level
  3. Stabilirne il contenuto
  4. Stabilire gestione degli eventi nelle componenti
  5. 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. La relazione (gerarchia) di contenimento ha la seguente rappresentazione ad albero:

Versione AWT:

      Frame  (finestra principale, contenitore)
        |
   +----+-----+
   |          |
 Button     Label     (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".