ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Organizzazione della lezione
16. Java: Swing
Vittorio Scarano
Algoritmi e Strutture Dati: Sistemi Distribuiti
Corso di Laurea in Informatica
Università degli Studi di Salerno
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
2
Programmazione grafica
Alcuni problemi di AWT
• Il minimo comune denominatore”
– interfaccia intuitiva e gradevole
– tutti gli applicativi oggigiorno sono grafici
– per piattaforme come X/Motif, Macintosh, Windows
• In Java 1.0 viene introdotto Abstract Windows Toolkit
(AWT)
• Principi di AWT:
– indipendenza dalla reale rappresentazione grafica attraverso
i “peer”
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
• Una necessità:
• componenti dipendenti dall’ambiente che gestivano il vero
input/output grafico
• Alcuni bug su varie piattaforme
• Il passo successivo
– Netscape progetta la Internet Foundation Classes
– che rappresentano finestre in maniera uguale su tutte le
piattaforme
• La Sun decide di partire da IFC per presentare Swing
– che fa parte delle Java Foundation Classes
3
•
•
•
•
Swing e AWT
Ricca dotazione di interfacce
Piattaforma più robusta e testata
Minore dipendenza dalla piattaforma di base
Risultato coerente su tutte le piattaforme
• Di AWT si usano comunque alcune componenti:
– gestione eventi, etc.
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Caratteristiche di Swing
4
– ma possibile programmare l’aspetto (es. alla Windows)
• Alcuni (piccoli) problemi:
– essendo soluzioni implementate senza i peer saranno più
lenti del corrispondente in AWT
Swing+
AWT
AWT
• Di AWT si usano comunque alcune componenti:
– gestione eventi, etc.
5
6
1
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
Un primo passo: creazione di un frame
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Organizzazione della lezione
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
• Una finestra di massimo livello cioè direttamente
visualizzata dal Sistema Operativo è detta frame
• La classe di AWT si chiama Frame, quella di Swing si
chiama JFrame (notare la doppia maiuscola)
• Fondamentale la ereditarietà:
– tutti i nostri componenti grafici devono ereditare da una
complessa (ma non necessariamente conosciuta) gerarchia
• I frame sono contenitori:
– possono contenere altre componenti grafiche
7
La classe SimpleFrame
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
import javax.swing.*;
public class SimpleFrame extends JFrame {
public SimpleFrame () {
setSize (WIDTH,HEIGHT);
}
public static final int WIDTH = 300;
public static final int HEIGHT= 200;
}
La classe SimpleFrameTest
SimpleFrameTest.java
• Import
import javax.swing.*;
– per la extends
• Sottoclasse di JFrame
• Costruttore
– uso del metodo della
classe JFrame per
settare la dimensione
• Variabili di istanza
– solo costanti utilizzate
public class SimpleFrameTest {
public static void main (String[] args) {
SimpleFrame f = new SimpleFrame();
f.setDefaultCloseOperation (
JFrame.EXIT_ON_CLOSE);
f.show();
}
}
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
SimpleFrame.java
8
• Semplice programma
di test
• Crea un frame
• Setta alcune
caratteristiche
– termina il programma
quando il frame viene
chiuso
• Mostra il frame
9
Alcune caratteristiche di un frame
10
La classe CenteredFrame
CenteredFrame.java
– la posizione
– il titolo
– la icona (in alto a sinistra a sulla barra)
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
• Tra le tante caratteristiche ereditate da JFrame
• Nel prossimo esempio:
– vogliamo creare un frame al centro dello schermo
• abbiamo bisogno di Toolkit per prelevare la dimensione corrente
dello schermo
– scegliendo il titolo e la icona
11
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CenteredFrame extends JFrame {
public CenteredFrame () {
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize=
kit.getScreenSize();
int screenHeight=screenSize.height;
int screenWidth=screenSize.width;
setSize (screenWidth/2,screenHeight/2);
setLocation (screenWidth/4,
screenHeight/4);
Image img = kit.getImage("icon.gif");
setIconImage(img);
setTitle("Centered Frame");
}
}
• Import
– per extends e Toolkit
• Uso di Toolkit
– prelevare le dimensioni
dello schermo
• Set dimensione
• Set locazione
• Set immagine della
icona del frame
• Set titolo
12
2
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
La classe CenteredFrameTest
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
import javax.swing.*;
public class CenteredFrameTest {
public static void main (String[] args) {
CenteredFrame f = new
CenteredFrame();
f.setDefaultCloseOperation (
JFrame.EXIT_ON_CLOSE);
f.show();
}
Usiamo i Frame come contenitori
• Semplice programma
di test
• Crea un frame
• Setta alcune
caratteristiche
• Possiamo aggiungere dei componenti ai Frame
• Ricca disponibilità:
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
CenteredFrameTest.java
– termina il programma
quando il frame viene
chiuso
• Mostra il frame
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
import javax.swing.*;
import java.awt.*;
public class HelloWorldFrame extends JFrame{
public HelloWorldFrame () {
setTitle ("Ciao Mondo!");
setSize (300,200);
HelloWorldPanel p = new
HelloWorldPanel();
Container c = getContentPane();
c.add(p);
}
}
class HelloWorldPanel extends JPanel{
public void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawString ("Ciao a tutti!", 75,100);
}
}
• che si occupa di ridisegnare la finestra ad ogni spostamento,
ridimensionamento, etc
import javax.swing.*;
import java.awt.*;
– per extends
• Costruttore:
– setta il titolo e la size
– crea un Panel
• uso classe interna allo
stesso file (privata)
– preleva il ContentPane
del JFrame
– aggiunge il pannello p
15
14
public class HelloWorldFrame extends JFrame{
public HelloWorldFrame () {
setTitle ("Ciao Mondo!");
setSize (300,200);
HelloWorldPanel p = new
HelloWorldPanel();
Container c = getContentPane();
c.add(p);
}
}
class HelloWorldPanel extends JPanel{
public void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawString ("Ciao a tutti!", 75,100);
}
}
• Classe interna:
– di uso privato di
HelloWorldFrame
• Override del metodo
– con chiamata al metodo
della superclasse
– e aggiunta di una
stampa di una stringa
16
La visualizzazione di immagini
• Semplice programma
di test
• Crea un frame
• Setta alcune
caratteristiche
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
import javax.swing.*;
import java.awt.*;
public class HelloWorldTest {
public static void main ( String[] args) {
HelloWorldFrame f = new
HelloWorldFrame();
f.setDefaultCloseOperation (
JFrame.EXIT_ON_CLOSE);
f.show();
}
}
– offre un metodo paintComponent() dalla superclasse
HelloWorldFrame.java
• Import
La classe HelloWorldTest
HelloWorldTest.java
• La idea di JPanel:
La classe HelloWorldFrame (2)
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
HelloWorldFrame.java
• che è un contenitore ma che può anche essere soggetto
all’inserimento di testo, disegni etc.
– basta fare override del metodo senza dimenticare di
richiamare il metodo della superclasse
13
La classe HelloWorldFrame (1)
– tra gli altri JPanel
– termina il programma
quando il frame viene
chiuso
• Mostra il frame
17
• Si usano metodi per caricare una immagine e per
visualizzarla su un pannello
• Alcuni commenti:
– le immagini possono essere caricate da URL (e quindi da
Internet) con estrema facilità
– lentezza nel caricamento
• nel primo esempio lo ignoriamo e poi vediamo come può essere
risolto
18
3
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
La classe ImageFrame (1)
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ImageFrame extends JFrame{
public ImageFrame () {
setTitle ("Eccomi...");
setSize (800,700);
ImagePanel p = new ImagePanel();
Container c = getContentPane();
c.add(p);
}
}
class ImagePanel extends JPanel{
//…. continua
La classe ImageFrame (2)
ImageFrame.java
• Import
– per extends
• Costruttore:
– setta il titolo e la size
– crea un Panel
• uso classe interna allo
stesso file (privata)
– preleva il ContentPane
del JFrame
– aggiunge il pannello p
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ImageFrame.java
// … continua
class ImagePanel extends JPanel{
public ImagePanel () {
image = Toolkit.getDefaultToolkit().
getImage("foto.gif");
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawImage ( image, 75,100, null);
}
private Image image;
}
• Variabile istanza di
ImagePanel
– per la immagine
• Costruttore:
– carica la foto.gif
• L’override di
paintComponent
– traccia la immagine
19
La classe ImageTest
import javax.swing.*;
import java.awt.*;
public class ImageTest {
public static void main ( String[] args) {
ImageFrame f = new ImageFrame();
f.setDefaultCloseOperation (
JFrame.EXIT_ON_CLOSE);
f.show();
}
}
Il problema del caricamento
• Semplice programma
di test
• Crea un frame
• Setta alcune
caratteristiche
• Il caricamento della immagine viene effettuato
mediante un thread
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ImageTest.java
20
– termina il programma
quando il frame viene
chiuso
• Mostra il frame
– eseguito in maniera asincrona:
• il programma continua mentre viene caricata l’immagine
– questo per immagini grandi oppure immagini che vanno
caricate da rete non è corretto
• Si deve fare in modo di fare “aspettare” nel costruttore
di ImagePanel l’effettivo caricamento
• Ecco come si fa:
21
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ImageFrame.java
// …resto del file (classe ImageFrame) identico
class ImagePanel extends JPanel{
public ImagePanel () {
image = Toolkit.getDefaultToolkit().
getImage("foto.gif");
MediaTracker t = new
MediaTracker(this);
t.addImage(image,1); // id immagine
try {t.waitForID(1); }
catch (InterruptedException e) {}
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawImage ( image, 75,100, null);
}
private Image image;
}
Organizzazione della lezione
• Si definisce un oggetto
che traccia il
caricamento della
immagine
• Si aggiunge l’immagine
• Si aspetta il caricamento
effettuato della
immagine con ID 1
23
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
La classe (modificata) ImagePanel
22
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
24
4
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
La interazione in un ambiente grafico
Due approcci estremi
• L’approccio alla VisualBasic
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
• Un ambiente grafico deve garantire la interazione con
gli utenti
– rispondere ai click dell’utente in maniera “sensata”
• un click può:
–
–
–
–
essere ignorato
selezionare una voce da un menù
attivare un bottone
iniziare una azione di drag and drop
– rispondere alla pressione di tasti della tastiera
• scrivere testo “da qualche parte” sullo schermo
• Il sistema operativo monitora l’ambiente e segnala gli
eventi ricevuti al programma in esecuzione
25
L’approccio di Java: un compromesso
• un pulsante HelpButton ha la azione HelpButton_Click
• basta scrivere una procedura con questo nome per farne eseguire il
codice in risposta ad una azione dell’utente
• L’approccio alla C
– necessario scrivere il codice che costantemente controlla una
“coda di eventi” per trattarla (mega-switch)
– possibile creare nuovi eventi
– estremamente complessa
26
Gli oggetti evento
• Il programmatore ha il controllo:
• In un linguaggio OO come Java, è ovvio che gli eventi siano
incapsulati in un oggetto java.util.EventObject
• dalle sorgenti (bottoni, barre di scorrimento, etc.)
• ai rilevatori (listener)
• Il Modello di delega degli eventi
– permette di mantenere il pieno controllo e la estendibilità del
codice
– al prezzo di scrivere (e debuggare) un pochino in più di
codice (rispetto, ad esempio, al Visual Basic)
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
– delle modalità di trasmissione degli eventi
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
– ogni elemento della interfaccia grafica ha una lista di eventi
fissati
– con le sue sottoclassi ActionEvent e WindowEvent
• Il funzionamento:
– (1) un listener è una istanza di una classe che implementi la
interface Listener
– (2) una sorgente di eventi può registrare oggetti listener
– (3) quando si verificano eventi allora la sorgente invia ai listener
registrati gli oggetti Event
– (4) i listener usano le informazioni nell’oggetto Event per
determinare la loro reazione
27
Uno schema di funzionamento
Un programma di esempio
• Un frame con 3 bottoni:
class MyListener implements ActionListener {
….
public void actionPerformed (ActionEvent ev) {
// la reazione all’evento
}
}
• (2) La registrazione del listener sulla sorgente:
ActionListener lis = new MyListener( );
JButton butt = new JButton (“Ok”);
butt.addActionListener(lis);
• (3) Ogni volta si verifica un evento, allora l’oggetto butt avvisa
il listener lis inviando come parametro l’Event
• (4) l’oggetto lis allora esegue il metodo actionPerformed()
29
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
• (1) Il Listener
28
– alla pressione di uno di questi bottoni, il colore di sfondo
cambia a seconda del bottone premuto
• La struttura delle classi:
– nello stesso file: Buttonframe.java
• una classe ButtonPanel che contiene i bottoni
• una classe ButtonFrame che contiene ButtonPanel
• una classe ColorAction che fa il Listener dei bottoni
– una classe ButtonTest per il semplice uso di ButtonFrame
• Attenzione: esempio lievemente diverso da quello sul libro:
• classe ButtonTest in un file separato
• non si usano le classi “interne” (classi definite all’interno di altre classi)
30
5
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
La classe ButtonTest
La classe ButtonFrame (1)
ButtonTest.java
– per usare JFrame
• Metodo main
public class ButtonTest
{
public static void main(String[] args)
{
ButtonFrame frame = new ButtonFrame();
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
– crea un frame
ButtonFrame
– ne setta alcune
caratteristiche
• termina il programma
quando il frame viene
chiuso
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ButtonFrame.java
• Import
import java.awt.*;
import javax.swing.*;
– mostra il frame
//… continua
class ButtonPanel extends JPanel {
public ButtonPanel() {
JButton yButton = new JButton(“Giallo");
JButton bButton = new JButton("Blu");
JButton rButton = new JButton("Rosso");
add(yButton);
add(bButton);
add(rButton);
ColorAction yAction = new ColorAction(
Color.yellow,this);
ColorAction bAction = new ColorAction(
Color.blue, this);
ColorAction rAction = new ColorAction(
Color.red, this);
yButton.addActionListener(yAction);
bButton.addActionListener(bAction);
rButton.addActionListener(rAction);
}
} // fine ButtonPanel… continua
• Crea 3 bottoni con
etichetta
• Aggiungi (add di
JPanel) i tre bottoni al
pannello
• Crea 3 listener
– ad ognuno passa il
colore e una reference
al Panel
• Aggiungi un Listener a
• Creazione di un
ButtonPanel …
• … e aggiunta del
ButtonPanel al Frame
}
ButtonFrame.java
class ColorAction implements ActionListener
{
public ColorAction(Color c, JPanel p)
{
backgroundColor = c;
pann = p;
}
public void actionPerformed(
ActionEvent event)
{
pann.setBackground(backgroundColor);
pann.repaint();
}
private Color backgroundColor;
private JPanel pann;
ciascun bottone
}
33
Organizzazione della lezione
32
• Implementa la interface
ActionListener
• Costruttore
– 2 parametri
• il colore da settare
• il pannello di cui
cambiare il colore
• Il metodo per la
esecuzione della azione
– set background
– forza il repaint del
pannello
• Variabili di istanza
34
Modifica del look-and-feel
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
– set del titolo
– set della dimensione
La classe ButtonFrame (3)
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ButtonFrame.java
ButtonPanel panel = new ButtonPanel();
Container contentPane = getContentPane();
contentPane.add(panel);
• Import
• Costruttore:
} // fine della classe ButtonFrame
// … continua con le classi ButtonPanel
// … e ColorAction
31
La classe ButtonFrame (2)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ButtonFrame extends JFrame
{
public ButtonFrame()
{
setTitle("ButtonTest");
setSize(300, 200);
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
• La ambientazione grafica (look-and-feel) permette di
offrire un ambiente grafico familiare all’utente
• Sono disponibili:
– Metal (specifico di Swing)
– Windows (disponibile solo su Windows)
– Mac (disponibile solo su Mac)
– Motif (X)
• Interessante:
– è possibile far cambiare a run-time la ambientazione
35
36
6
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
La classe PlafTest
La classe PlafFrame (1)
PlafFrame.java
• Standard applicazione
di esempio…
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
PlafTest.java
public class PlafTest
{
public static void main(String[] args)
{
PlafFrame frame = new PlafFrame();
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
• Import
• Costruttore:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class PlafFrame extends JFrame
{
public PlafFrame() {
setTitle("PlafTest");
setSize(300, 200);
PlafPanel panel = new PlafPanel();
Container contentPane = getContentPane();
contentPane.add(panel);
}
}
// fine della classe PlafFrame
// … continua con le classi PlafPanel
// … e LookAction
– set del titolo
– set della dimensione
• Creazione di un
PlafPanel …
• … e aggiunta del
PlafPanel al Frame
37
PlafFrame.java
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
class PlafPanel extends JPanel {
public PlafPanel() {
makeButton("Metal",
"javax.swing.plaf.metal.MetalLookAndFeel");
makeButton("Motif",
"com.sun.java.swing.plaf.motif.MotifLookAndFeel");
La classe PlafFrame (3)
• Usa un metodo per creare
un bottone e registrare un
listener
• Argomenti
– label bottone
– stringa della classe da usare
per cambiare look
makeButton("Windows",
"com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
}
void makeButton(String name, String plafName) {
JButton button = new JButton(name);
add(button);
LookAction l = new LookAction(this, plafName);
button.addActionListener(l);
}
• makeButton()
}
// fine della classe PlafPanel .. continua …
– crea bottone e aggiunge al
pannello
– crea listener e lo aggiunge
PlafFrame.java
class LookAction implements ActionListener {
public LookAction(JPanel p, String s) {
pann = p;
look = s;
}
public void actionPerformed(ActionEvent event) {
try {
UIManager.setLookAndFeel(look);
SwingUtilities.updateComponentTreeUI
(pann);
}
catch(Exception e) { e.printStackTrace(); }
}
JPanel pann;
String look;
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
La classe PlafFrame (2)
38
}
• Costruttore
– setta le variabili di istanza:
• pannello su cui cambiare
look-and-feel
• nome del Look da cambiare
• Metodo per la azione
– usa metodi statici
• per cambiare il Look-and-feel
• per aggiornare tutte le
componenti correnti del
pannello
– necessario un try..catch
• Variabili di istanza
39
Eventi della finestra
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Organizzazione della lezione
40
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
41
• Quando la finestra è soggetta a qualche operazione da
parte dell’utente, diventa sorgente di un WindowEvent
• La interfaccia messa a disposizione per implementare
dei listener è WindowListener:
• Un problema:
• implementare
tutti i metodi
anche se sono
vuoti
public interface WindowListener() {
void windowOpened(WindowEvent e);
void windowClosing(WindowEvent e);
void windowClosed(WindowEvent e);
void windowIconified(WindowEvent e);
void windowDeiconified(WindowEvent e);
void windowActivated(WindowEvent e);
void windowDeactivated(WindowEvent e);
}
42
7
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
Un semplice “trucchetto”: l’adapter
Organizzazione della lezione
• Per evitare la implementazione di metodi vuoti:
void windowOpened(WindowEvent e) { }
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
..
..
– esiste una classe di nome WindowAdapter che implementa
tutti i metodi vuoti
– e basta estendere questa classe ( extends non implements)
• facendo override dei soli metodi da definire non vuoti!
class Terminator extends WindowAdapter {
void windowClosed(WindowEvent e) {
System.exit(0);
}
}
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
43
Elementi di una componente di interfaccia
44
Schema model-view-controller
• Componenti di interfaccia utente:
• Lo schema modello-vista-controller è usato da Swing
• Principio guida (della programmazione OO):
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
– bottoni, campo di testo, menù etc.
• Tre elementi costitutivi:
– il contenuto
• lo stato di un pulsante, il testo di un campo di testo, etc.
– l’aspetto visivo
• colori, dimensioni, font, etc.
– il comportamento
• reazione agli eventi utente e di altri oggetti
– ogni oggetto deve avere un numero limitato di responsabilità
(compiti da assolvere)
• Questo schema permette, in generale, di separare
all’interno della componente grafica
– gli aspetti dei dati contenuti,
– la rappresentazione grafica
– e la loro interazione con l’ambiente circostante
45
Lo schema model-view-controller
46
Alcuni vantaggi dello schema
• Memorizzazione dei dati (modello) diversa dalla
presentazione (vista)
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
• Ogni componente grafica viene implementata da tre
classi:
– un modello
• che serve a memorizzare il contenuto
– per una casella di testo, memorizza la stringa
– una vista
• che serve a visualizzare il contenuto
– per un casella di testo, contiene font, dimensioni, posizione etc.
– un controller
• che permette la interazione con l’utente
– per una casella di testo, permette la modifica, cancellazione del contenuto,
etc.
47
– lo stesso file HTML può essere presentato come “preview”
(come appare sul browser) oppure come file di testo ASCII
(con tutti i tag)
• Il controller controlla l’input
– e decide se informare il modello (cambia il contenuto)
oppure la vista (è cambiata la presentazione)
– l’altra componente ignora le informazioni inviate alla
componente che deve essere informata
48
8
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
Swing e lo schema progettuale
Un esempio: la classe JButton (1)
• Di norma, per ogni componente grafica esiste
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
• Normalmente i programmatori ignorano questo
schema:
– interagiscono con una classe wrapper (tipo JButton)
– le modifiche a JButton vengono da questa inoltrata alla
componente modello, vista oppure controller
• Si può comunque recuperare il modello da una classe
wrapper
• Permette di creare ambienti innestabili
– una classe modello che implementa una interfaccia
– per JButton esiste una interfaccia ButtonModel che viene
implementata da una classe DefaultButtonModel
• I metodi di ButtonModel
– getActionCommand()
• stringa di comando della azione associate al bottone
– getMnemonic()
• scorciatoia da tastiera
– isArmed(),is Enabled(), is Pressed(), is Rollover(), isSelected()
– riutilizzare componenti cambiandone solamente la vista
– a volte possibile a run-time!
• se il bottone è stato premuto/abilitato/premuto (mouse è ancora lì)/ mouse è sul
pulsante/selezionato (pulsante di scelta)
49
Organizzazione della lezione
• E’ possibile recuperare l’oggetto modello della
butt = new JButton (“Giallo”);
componente: JButton
ButtonModel model = button.getModel();
• Ogni componente usa un oggetto vista la cui classe ha
un nome che termina con UI (User Interface)
– per JButton esiste una classe BasicButtonUI
• Alcune componenti usano un oggetto controller
dedicato, la cui classe ha nome che termina con
UIListener
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Un esempio: la classe JButton (2)
50
– per JButton esiste una classe ButtonUIListener
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
51
La classe ButtonFrameBorder (1)
ButtonFrameBorder.java
• Si occupano di implementare una politica di gestione
del posizionamento dei componenti sulla finestra
• Disponibili una varia gamma di classi
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Gestori del layout
52
– disponibili da Sun
– ma anche da altri produttori di software
• Nell’esempio di ButtonFrame:
– i pulsanti si trovavano al centro della finestra
– e mantenevano la posizione centrale al ridimensionamento
della finestra
– usa il BorderLayout (di default posiziona al centro)
53
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ButtonFrame extends JFrame
{
public ButtonFrame()
{
setTitle("ButtonTest");
setSize(300, 200);
ButtonPanel panel = new ButtonPanel();
Container contentPane = getContentPane();
contentPane.add(panel);
• Import
• Costruttore:
– set del titolo
– set della dimensione
• Creazione di un
ButtonPanel …
• … e aggiunta del
ButtonPanel al Frame
}
} // fine della classe ButtonFrame
// … continua con le classi ButtonPanel
// … e ColorAction
54
9
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
La classe ButtonFrame (2) con il
Un altro Layout Manager: BorderLayout
FlowLayout
//… continua
class ButtonPanel extends JPanel {
public ButtonPanel() {
setLayout (new
FlowLayout(FlowLayout.RIGHT));
JButton yButton = new JButton(“Giallo");
JButton bButton = new JButton("Blu");
JButton rButton = new JButton("Rosso");
add(yButton);
add(bButton);
add(rButton);
ColorAction yAction = new ColorAction(
Color.yellow,this);
ColorAction bAction = new ColorAction(
Color.blue, this);
ColorAction rAction = new ColorAction(
Color.red, this);
……
• Seleziona come
gestore del Layout un
oggetto FlowLayout
• Permette di definire con più precisione la posizione
• Divide la finestra in:
– che viene creato
passando una costante
definita nella classe
– che posizione a destra i
pulsanti
– altra scelta LEFT e
CENTER
ButtonFrameBorder.java
– il Giallo a nord
– il blu a est
– il rosso a sud
• Cosa accade?
57
La soluzione: un Panel che contiene i
pulsanti
JPanel cont = new JPanel();
cont.add(yellowButton);
cont.add(blueButton);
cont.add(redButton);
add(cont, BorderLayout.SOUTH);
….
• Seleziona come
gestore del Layout un
oggetto BorderLayout
• Crea 3 bottoni
• Crea un Pannello
– al quale aggiunge i tre
pulsanti
– con il gestore di layout
standard
(BorderLayout)
• Poi aggiunge il
pannello a sud
56
//… continua
class ButtonPanel extends JPanel {
public ButtonPanel() {
setLayout (new BorderLayout());
JButton yButton = new JButton(“Giallo");
JButton bButton = new JButton("Blu");
JButton rButton = new JButton("Rosso");
add(yButton, BorderLayout.SOUTH);
add(bButton, BorderLayout.SOUTH);
add(rButton, BorderLayout.SOUTH);
……
• Si usa BorderLayout()
• Posizioniamo:
– tutti i pulsanti a sud
• Cosa accade?
• Solo un componente può essere
inserito a sud:
• l’ultimo sostituisce il precedente
• Come si fa?
58
Organizzazione della lezione
59
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
//… continua
class ButtonPanel extends JPanel
{
public ButtonPanel()
{
setLayout (new BorderLayout());
JButton yellowButton = new JButton("Giallo");
JButton blueButton = new JButton("Blu");
JButton redButton = new JButton("Rosso");
South
E se mettiamo tutti e tre i pulsanti a Sud?
• Si usa BorderLayout()
• Posizioniamo:
ButtonFrameBorder.java
West Center East
– di default su JFrame (inserimento al centro)
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
//… continua
class ButtonPanel extends JPanel {
public ButtonPanel() {
setLayout (new BorderLayout());
JButton yButton = new JButton(“Giallo");
JButton bButton = new JButton("Blu");
JButton rButton = new JButton("Rosso");
add(yButton, BorderLayout.NORTH);
add(bButton, BorderLayout.EAST);
add(rButton, BorderLayout.SOUTH);
……
North
• Ridimensiona i componenti in modo che riempiano
tutto lo spazio disponibile
55
Cosa accade se usiamo BorderLayout()?
ButtonFrameBorder.java
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ButtonFrameBorder.java
• La programmazione grafica con Swing e AWT
• Un primo approccio con Swing: frame e pannelli
• Gli eventi dell’ambiente grafico
– i listener (rilevatori di evento)
– modifica del Look-and-feel
– adapter a interfacce
• Lo schema di progettazione di Swing
• I gestori di layout
• Campi di testo
60
10
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
Componenti per input di testo
Listener per campi di testo
• Due componenti:
• Implementa la interfaccia DocumentListener con i
metodi:
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
– JTextField per l’input di un rigo di testo
– JTextArea per l’input di una area di testo (più righi)
• Entrambe derivano dalla classe astratta
JTextComponent
– che contiene la maggior parte dei metodi tra cui:
• void setText (String t)
– modifica il testo della componente
• String getText()
– restituisce il testo della componente
• void setEditable (boolean b)
– può essere modificata oppure no
TextTest.java
– in uno scriviamo il nome
– nell’altro (non editabile) compare “Ciao…”
• Necessario (a parte la classe TextTest)
– una classe TextFrame che
• crea due oggetti JTextField
• setta il listener di uno dei due (quello di input) a TextListener a cui
passa le reference dei due campi
• setta l’altro JTextField a non editabile
– una classe TextListener
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
import java.awt.*;
import javax.swing.*;
62
public class TextTest
{
public static void main(String[] args)
{
TextFrame frame = new TextFrame();
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
• Import
– per usare JFrame
• Metodo main
– crea un frame
TextFrame
– ne setta alcune
caratteristiche
• termina il programma
quando il frame viene
chiuso
– mostra il frame
63
La classe TextFrame (1)
64
La classe TextFrame (2)
•
•
•
•
Import
Costruttore: (continua)
Creazione di un JPanel
Creazione di due
JTextField
– il secondo non editabile
• Aggiunta del listener a
nome
– passando nome e saluto
65
TextFrame.java
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
• Per aggiungere un listener ad un campo si usa:
La classe TextTest
• nel costruttore prende due variabili di reference JTextField
• quando il testo sul primo campo cambia, scrive la stringa sul
secondo
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
– si devono esplicitamente implementare i 3 metodi anche se
servono vuoti
JTextField nome = new JTextField(30);
TextListener lis = new TextListener();
nome.getDocument().addDocumentListener(lis);
• Una finestra che contenga due campi di testo:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
class TextFrame extends JFrame {
public TextFrame() {
setTitle("Test sul Testo");
setSize(300, 200);
Container contentPane = getContentPane();
JPanel pan = new JPanel ();
JTextField nome = new JTextField(30);
JTextField saluto = new JTextField(40);
saluto.setEditable (false);
TextListener lis = new TextListener(
nome,saluto);
nome.getDocument().addDocumentListener(
lis);
// … continua la classe TextFrame
• Sfortunamente nessuna classe adapter è disponibile:
61
Un esempio di uso
TextFrame.java
– void insertUpdate (DocumentEvent e) { }
– void removeUpdate (DocumentEvent e) { }
– void changedUpdate (DocumentEvent e) { }
//…
// continua il costruttore di TextFrame
contentPane.add(nome,
BorderLayout.NORTH);
contentPane.add(saluto,
BorderLayout.SOUTH);
}
}
• Aggiunge i due campi
di testo al Container
– uno a nord
– l’altro a sud
• Attenzione:
– il layout manager di
default di JFrame è
BorderLayout
// fine classe TextFrame
// continua con la classe TextListener
66
11
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
La classe TextFrame (3)
class TextListener implements
DocumentListener {
public TextListener (JTextField n,JTextField s) {
nome = n;
saluto = s;
}
public void insertUpdate(DocumentEvent e)
{saluto.setText("Ciao " + nome.getText());}
public void removeUpdate(DocumentEvent e)
{saluto.setText("Ciao " + nome.getText());}
public void changedUpdate(DocumentEvent e)
{saluto.setText("Ciao " + nome.getText());}
JTextField nome;
JTextField saluto;
}
Un esempio “reale”: conversione lire/euro
• Implementa
• Due campi di testo:
DocumentListener
• Costruttore
– assegna i due campi di
testo passati
• Tre metodi per gli
eventi di cui è “in
ascolto”
– settano il testo di saluto
a seconda del contenuto
di nome
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
TextFrame.java
– uno (editabile) in cui si inseriscono il valore in lire
– uno (non editabile) in cui viene scritto il corrispettivo in euro
• Struttura simile al programma precedente:
– Calculator (che istanzia CalculatorFrame)
– CalculatorFrame (che istanzia i campi di testo ed usa
TextListener per le modifiche al campo)
– TextListener (che implementa i metodi per le modifiche al
valore in lire e il calcolo del valore in euro)
67
La classe Calculator
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
import java.awt.*;
import javax.swing.*;
public class Calculator
{
public static void main(String[] args)
{
CalculatorFrame frame =
new CalculatorFrame();
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
La classe CalculatorFrame
CalculatorFrame.java
• Import
– per usare JFrame
• Metodo main
– crea un frame
CalculatorFrame
– ne setta alcune
caratteristiche
• termina il programma
quando il frame viene
chiuso
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Calculator.java
68
// soliti import!! :-)
class CalculatorFrame extends JFrame {
public CalculatorFrame() {
setTitle("Euroconvertitore");
setSize(100, 100);
Container contentPane = getContentPane();
JPanel pan = new JPanel ();
JTextField v = new JTextField(10);
JTextField r=new JTextField(10);
r.setEditable (false);
TextListener lis = new TextListener(v,r);
v.getDocument().addDocumentListener(lis);
contentPane.add(v, BorderLayout.NORTH);
contentPane.add(r, BorderLayout.SOUTH);
– mostra il frame
•
•
•
•
Import
Costruttore:
Creazione di un JPanel
Creazione di due
JTextField
– il secondo non editabile
• Aggiunta del listener a
v
– passando v e r
}
}
69
La classe TextListener (1)
import java.util.*;
import java.text.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
class TextListener
implements DocumentListener {
public TextListener (JTextField v,
JTextField r) {
valuta = v;
risultato = r;
}
La classe TextListener (2)
TextListener.java
• Import
• Implementa
DocumentListener
• Costruttore
– assegna i due campi
passati alle due variabili
di istanza (definite nel
seguito)
// continua
71
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
TextListener.java
70
// continua…
public void insertUpdate(DocumentEvent e) {
int lire;
try {
lire = Integer.parseInt(valuta.getText());
} catch (NumberFormatException g)
{lire = -1;}
double euro = lire / 1936.27;
if (lire >= 0) {
NumberFormat fmt =
NumberFormat.getNumberInstance();
fmt.setMaximumFractionDigits(2);
risultato.setText(fmt.format(euro));
} else
risultato.setText(ERRORE);
}
// identici removeUpdate e changedUpdate
// continua
• Prova a convertire la
stringa in un intero
• altrimenti lire è negativo
• Converte in euro
• Se il valore in lire era
valido:
– converte arrotondando alla
seconda cifra decimale
• altrimenti stampa una
stringa di errore
72
12
ASD: Sistemi Distribuiti (Prof. Scarano)
11/06/2002
Cosa altro può fare Swing per me? (1)
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
TextListener.java
• Variabili di istanza per
contenere i riferimenti per
i due campi di testo
• La stringa di errore
(costante)
// continua…
JTextField valuta;
JTextField risultato;
final String ERRORE = "Valore errato";
}
// fine classe TextListener
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
La classe TextListener (3)
Dialog
SplitPane
Frame
Panel
TabbedPane
Toolbar
InternalFrame
LayeredPane
73
ScrollPane
Buttons
74
ASD: Sistemi Distribuiti. Vi.ttorio Scarano
Cosa altro può fare Swing per me? (2)
Combo Box
List
Menu
Slider
Text Fields
Color Chooser
Progress Bar
Label
Text
Tool tip
File Chooser
Tree
Table
75
13