PROGRAMMAZIONE GRAFICA
Creazione di interfaccie utente “grafiche”, ovvero basate su
concetti quali finestra, casella di testo, bottone, barra degli
strumenti, menu.
Elementi fondamentali:
• Componenti e composizione: l’interfaccia grafica viene
costruita assemblando componenti pronti, quali finestre,
bottoni, caselle di testo;
• Layout: posizionamento degli elementi nell’interfaccia
grafica. E’ un problema non banale quando si vuole che
l’applicazione sia multipiattaforma e indipendente dalla
risoluzione e dalla dimensione dei caratteri.
• Event-oriented programming: il programma non è più in
comando dell’interazione con l’utente. Deve reagire
appropriatamente alle azioni svolte dall’utente.
• Programmazione grafica: è possibile creare componenti
che si disegnano autonomamente.
Librerie per la grafica in Java:
• AWT: presente nel JDK, risale a Java 1.0. E’ poco flessibile,
possiede meno componenti. Ogni componente è nativo,
ovvero ha lo stesso aspetto degli altri componenti del sistema
operativa;
• Swing: presente nel JDK, risale a Java 2. Flessibile, potente,
anche se più complessa da usare. Indipendente dalla
piattaforma e skinnable (vedi Look And Feel).
Ing. Aime – Programmazione grafica in Java con la libreria Swing
1
COMPOSIZIONE
Finestra
Componenti
Pannello
(contenitore)
Secondo
pannello
Osservazioni:
• Componenti: la finestra mostra vari componenti, quali
etichette (nome, descrizione), caselle di testo, bottoni, liste a
discesa, radio e check buttons, liste, e pannelli, ovvero
generici contenitori di altri componenti (decorati con un
bordo e un titolo)
• Composizione: la finestra contiene un pannello, che contiene
dei componenti, ma anche un secondo pannello, il quale
contiene a sua volta dei bottoni;
Ing. Aime – Programmazione grafica in Java con la libreria Swing
2
POSIZIONAMENTO E GESTIONE LAYOUT
X
Y
Ogni componente è dotato di un sistema di riferimento cartesiano,
la cui unità di misura è il pixel (la cui dimensione dipende dal
numero di pixel presenti sullo schermo e dalla dimensione dello
schermo, per una definizione più accurata si veda
http://it.wikipedia.org/wiki/Pixel).
Ad esempio, possiamo dire che l’etichetta nome ha una posizione
(3, 6) rispetto all’origine, e una dimensione di 20 per 8 pixel.
Ciascun contenitore ha il proprio riferimento cartesiano. La
posizione di jButton2, ad esempio, è riferita al sistema cartesiano
di Pannello2, non all’intera finestra.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
3
X
X
Y
Y
Il dimensionamento e il posizionamento fisso in pixel non sono
però affidabili: se si cambia la dimensione o il tipo dei font o la
risoluzione del video, o si cerca di ridimensionare la finestra, si
possono ottenere componeti sovrapposti, mal distribuiti, o
posizionati fuori dall’area visibile.
Java introduce i layout manager, gestori del posizionamento, che
risolvono questi problemi ricalcolando la posizione assoluta dei
componenti in funzione delle suddette variabili.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
4
EVENT ORIENTED PROGRAMMING
Paradigma di interazione in un programma testuale: il software
propone delle domande all’utente, e si aspetta una risposta
(testuale).
Il programma di norma interrompe la sua esecuzione nell’attesa
della risposta, la riposta è una sola, è sufficiente verificare che sia
appropriata. Il programma domina l’interazione con l’utente.
Il programma termina quanto termina la main.
Paradigma di interazione in un programma grafico: il
programma predispone una interfaccia utente grafica, l’utente
decidere cosa quale azioni vuole eseguire. Ad esempio, può
compilare prima il campo nome e poi la descrizione, e premere ok
senza aver fornito la sua età. Il programma di norma non termina
quanto termina la main, ma quando viene chiusa l’ultima
finestra.
L’utente domina l’interazione, il programma può soltanto
“reagire” agli stimoli forniti dall’utente.
Quindi, il programma resta in attesa di “eventi” generati
dall’azione dell’utente, ed esegue determinate routine quando
accadono eventi ritenuti interessanti. Vi sono molti eventi, ma il
programma ne ascolterà soltanto una parte.
Ad esempio, relativamente ad un bottone siamo interessati al click
sul bottone, ma probabilmente non al fatto che qualcuno ha
premuto il tasto “A” mentre il bottone era attivo (anche se
potremmo ascolatare anche questo evento).
Alla stessa maniera, non saremo direttamente interessati ad eventi
quali il ridimensionamento di una finestra (ma il layout manager,
al contrario, sarà molto interessato in questi ultimi).
Ing. Aime – Programmazione grafica in Java con la libreria Swing
5
Mouse
Mouse
Mouse
Tastiera
Tastiera
Tastiera
Semantici
Virtual Machine
+ Swing
Componente
Ascoltatori
L’utente opera sulla finestra del programma con mouse e tastiera.
La virtual machine e la libreria Swing ricevono questi eventi
“grezzi”, o di basso livello, e li inviano al componente a cui sono
dedicati.
Per decidere quale componente è il destinatario, vengono usati
due algoritmi:
• se l’evento origina dal mouse, si determina quale è il
componente che sta sotto il puntatore del mouse;
• se l’evento origina dalla tastiera, si invia al componente che
ha il “focus” (di norma tale componente è evidenziato con un
bordo particolare). Il “focus” può essere spostato ciccando
sui componenti o premendo i tasti TAB e MAISC-TAB.
Il componente notifica questi eventi così come li ha ricevuti, ma
crea anche eventi di più alto livello. Ad esempio, un click può
comportare la selezione/deselezione: verrà notificato sia l’evento
di click, che un evento di selezione/deselezione.
Un programma grafico aggancia degli “ascoltatori” ai
componenti, per poter ascoltare i particolari eventi a cui è
interessato e reagire di conseguenza.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
6
Come sempre in Java, questi concetti sono mappati su classi:
• un evento è rappresentato da un oggetto, istanza di una
particolare classe di evento, riporta un riferimento al
componente che lo ha generato e ulteriori informazioni
specifiche in funzione del tipo di evento (ad esempio, un
evento di click riporta quale bottone del mouse è stato
premuto, se erano premuti alcuni tasti speciali sulla tastiera
insieme al click, eccetera);
• un ascoltatore (listener) è un oggetto che implementa una
determinata interfaccia. Quando un evento viene scatenato,
verrà invocato uno dei metodi di questa interfaccia. Ad
esempio, MouseListener è una interfaccia, fra i vari metodi
di questa interfaccia abbiamo
public void mouseClicked(MouseEvent e);
Quando l’evento di click viene scatenato, verrà invocato
questo metodo passando come parametro il MouseEvent.
• l’ascoltatore di deve registrare presso il componente per
poter ascoltare (e può rimoeve la registrazione per smettere
di ascoltare).
public void addMouseListener(MouseListener l)
public void removeMouseListener(MouseListener l)
• Un componente può avere più ascoltatori, il medesimo
ascoltatore può ascoltare eventi da più componenti.
Bottone 1
E1
Ascoltatore1
E1
Bottone 2
E2
Ascoltatore2
Ing. Aime – Programmazione grafica in Java con la libreria Swing
7
RIASSUMENDO
Una interfaccia grafica viene costruita mediante i seguenti passi:
1. si creano e si configurano i componenti;
2. si assembla l’interfaccia inserendo componenti base dentro i
contenitori (pannelli) e questi dentro una finestra;
3. si specifica la gestione del layout (algoritmo generale,
dettagli per i singoli componenti)
4. si agganciano dei listener ai componenti per poter reagire alle
azioni dell’utente.
A run time, il programma aspetta gli input dell’utente e reagisce.
Alcune interazioni sono già predisposte nei componenti (ad
esempio, un campo di testo reagire alla tastiera inserendo i
caratteri premuti nella casella).
Altre interazioni sono programmate nei listener, e vengono
attivate quando l’utente esegue determinate azioni (ad esempio,
premere un bottone).
ESEMPIO
Ing. Aime – Programmazione grafica in Java con la libreria Swing
8
import javax.swing.*; import java.awt.*;
import java.awt.event.*; import java.util.Date;
class FirstExample extends JPanel implements
ActionListener {
JButton bottone;
JTextField testo;
public FirstExample() {
// costruzione e configurazione componenti
bottone = new JButton("Premi qui");
testo = new JTextField();
testo.setColumns(20);
// aggiunta dei componenti al pannello
this.add(bottone);
this.add(testo);
// aggancio i listener (me stesso)
bottone.addActionListener(this);
}
// dichiarato in ActionListener
// verrà invocato quando il bottone sarà premuto
public void actionPerformed(ActionEvent event) {
Date ora = new Date();
testo.setText(ora.toString());
System.out.println("Sono stato invocato da:\n" +
event.getSource());
System.out.println();
}
public static void main(String[] args) {
JFrame frame = new JFrame("Primo esempio");
frame.setContentPane(new FirstExample());
frame.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
// la main termina, ma il programma no!!!
}
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
9
GERARCHIA DEI COMPONENTI IN JAVA
Object
Component
AWT
Swing
Container
Window
JComponent
Frame
Dialog
JFrame
JDialog
JPanel
JList
JTextComponent
JTextField
AbstractButton
JTextArea
JToggleButton
JCheckBox
JButton
JRadioButton
Osservazioni:
• ogni componente grafico è rappresentato da una classe.
• i componenti sono disposti lungo una gerarchia di
ereditarietà i metodi presenti nelle classi base sono
disponibili in tutte le sottoclassi!
• Nell’ovale sono riportate le classi che rappresentano le
finestre. Di due tipi, normale (JFrame), di dialogo (usata di
norma per chiedere all’utente informazioni).
Ing. Aime – Programmazione grafica in Java con la libreria Swing
10
• In corsivo le classi di AWT, le classi di Swing iniziano tutte
per J.
GERARCHIA DEGLI EVENTI
Object
EventObject
AWTEvent
ActionEvent
ContainerEvent
KeyEvent
ComponentEvent
InOutEvent
MouseEvent
ItemEvent
WindowEvent
Package
java.awt.event
Ogni evento viene accompagnato da un oggetto che lo
rappresenta.
Per ogni evento, è possibile risalire al componente che lo ha
generato invocando il metodo
public Object getSource();
Ing. Aime – Programmazione grafica in Java con la libreria Swing
11
COMPONENTI AWT
Component
Classe base (astratta) di tutti i componenti grafici. Di seguito sono
riportati alcune proprietà e eventi del componente.
Alcune proprietà (manipolate con metodi set/get)
Background
Color di sfondo
Bounds
Area occupata dal componente nel suo
contenitore (Rectangle)
Enabled
Un componente riceve gli eventi solo se abilitato
Font
Tipo di carattere usato nel componente
Focusable
Se il componente può ricevere il focus
Foreground
Colore di primo piano
Location
Posizione dell’angolo in alto a sinistra (Point)
MinimumSize Dimensione minima per il componente
(Dimension)
MaximumSize Dimensione massima per il componente
Parent
Il contenitore in cui è collocato il componente.
Può essere null
Size
Dimensione del componente (classe Dimension)
Visibile
Se vero, il componente è visibile. Usato anche per
mostrare le finestre a video dopo averle costruite
Alcuni fra i listener accettati
KeyListener
Per ascoltare eventi come la pressione di
tasti (solo se il componente ha il focus)
MouseListener
Eventi base del mouse (click, ingresso e
uscita del puntatore)
MouseMotionListener Eventi avanzati, movimento,
trascinamento
MouseWheelListener Eventi della rotellina del mouse, se
presente
Ing. Aime – Programmazione grafica in Java con la libreria Swing
12
Esiste poi un metodo che viene invocato ogni volta che il
componente deve essere disegnato:
public void paint(Graphics g);
dove Graphics è un oggetto dotato di metodi per disegnare linee,
rettangoli, ellissi, poligoni, eccetera. Ogni componente ridefinisce
questo metodo per poter disegnare correttamente il suo aspetto.
Container
E’ un contenitore di altri componenti. Pertanto:
• esistatono metodi per aggiungere/rimuovere i componenti
contenuti, e per ispezionare quali componenti sono presenti;
• è possibile associare un layout manager
public
public
public
public
public
public
Component add(Component comp);
add(Component comp, Object constraints);
void remove(Component comp);
int getComponentCount();
Component getComponent(int n);
void setLayout(LayoutManager mgr);
Ing. Aime – Programmazione grafica in Java con la libreria Swing
13
COMPONENTI SWING
JFrame
La finestra.
Alcune proprietà (manipolate con
metodi set/get)
Title
Titolo della finestra
Resizable
Se vero, la finestra è ridimensionabile
DefaultClose Operazione svolta alla chiusura. Valori possibili:
Operation
WindowConstants.DO_NOTHING_ON_CLOSE
WindowConstants.HIDE_ON_CLOSE
WindowConstants.DISPOSE_ON_CLOSE
WindowConstants.EXIT_ON_CLOSE
import javax.swing.*;
import java.awt.*;
public class Finestra extends JFrame {
public Finestra(String title) {
super(title);
setSize(200, 200);
setLocation(100, 200);
setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
System.out.println(
"Prima di creare la finestra");
Finestra f = new Finestra("Prima finestra");
f.setVisible(true);
System.out.println(
"Sto per uscire dalla main");
}
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
14
JComponent
Classe base dei componenti Swing. Aggiunge molti metodi e
proprietà, ma la maggior parte sono “avanzati”, e non verranno
presi in considerazione.
Alcune proprietà (manipolate con metodi set/get)
Border
Bordo del componente (sottoclassi di Border)
Opaque
Boolean, indica se lo sfondo è trasparente o pieno
(default, trasparente)
Metodi per il disegno (invocato dalla paint di JComponent, si
occupa di richiamare paintComponent dopo aver disegnato il
bordo):
protected void paintComponent(Graphics g);
In aggiunta, tutti i discendenti di JComponent sono in grado di
modificare il proprio aspetto quando viene cambiato il “Look and
Feel”.
JPanel
Pensato per essere un semplice contenitore di componenti. Non ha
nessuna differenza particolare, a meno che il look and feel non
imponga qualche differenza estetica (ad esempio, uno sfondo
grafico).
JLabel
Semplice etichetta di testo.
Attenzione: JLabel non è passivo, ha tutta la gamma di eventi
ereditati dai suoi padri, come ad esempio la gestine degli eventi
del mouse, presente sin dalla radice della gerarchia, Container.
Alcune proprietà (manipolate con metodi set/get)
Text
Il testo mostrato nell’etichetta
Ing. Aime – Programmazione grafica in Java con la libreria Swing
15
AbstractButton e i bottoni
Classe base astratta di tutti i bottoni.
Qualunque bottone sarà dotato di un testo, la proprietà text.
Inoltre, qualunque bottone emette un ActionEvent ogni volta che
il bottone viene premuto (con il mouse, o con la barra spaziatrice
quando il bottone ha il focus). Un ascolatore di ActionEvent deve
implementare ActionListener:
public interface ActionListener extends
EventListener {
public void actionPerformed(ActionEvent e);
}
L’ascoltatore dovrà poi registrarsi presso il bottone usando il
metodo:
public void addActionListener(ActionListener l);
JButton è una sottoclasse di AbstractButton
semplice, non vi sono funzionalità
aggiuntive degne di nota.
JToggleButton è una sottoclasse di AbstractButton. Ha lo stesso
aspetto di un JButton, ma può restare “premuto”. Aggiunge una
proprietà selected (setSelected, isSelected) per indicare il suo
stato (premuto o non premuto).
JCheckBox è una sottoclasse di
JToggleButton, con un aspetto grafico
differente.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
16
JRadioButton è una ulteriore sottoclasse di JToggleButton.
Ha un aspetto grafico differente, e può essere incluso in un
ButtonGroup per creare un insieme di selezioni esclusive fra loro.
Ad esempio:
import javax.swing.*; import java.awt.*;
import java.awt.event.*;
public class RadioSample extends JPanel implements
ActionListener {
JRadioButton rbtUno, rbtDue, rbtTre;
ButtonGroup group;
JLabel label;
public RadioSample() {
// crea e configura i componenti
rbtUno = new JRadioButton("Uno");
rbtUno.setSelected(true);
rbtDue = new JRadioButton("Due");
rbtTre = new JRadioButton("Tre");
label = new JLabel("Seleziona un bottone");
// crea e configura il gruppo
group = new ButtonGroup();
group.add(rbtUno); group.add(rbtDue);
group.add(rbtTre);
// aggiungi i componenti
add(rbtUno); add(rbtDue); add(rbtTre);
add(label);
// gestione eventi
rbtUno.addActionListener(this);
rbtDue.addActionListener(this);
rbtTre.addActionListener(this);
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
Gestione di più
sorgenti di
evento con lo
stesso listener
17
public void actionPerformed(ActionEvent evt) {
JRadioButton src =
(JRadioButton) evt.getSource();
System.out.println("Evento da " +
src.getText());
if(src.isSelected())
label.setText("Selezionato: " +
src.getText());
}
public static void main(String[] args) {
JFrame frame = new JFrame("Radio sample");
frame.setContentPane(new RadioSample());
frame.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
JTextField e JTextArea
Entrambi i componenti espongono la proprietà text che
consente di leggere/impostare il testo contenuto.
JTextField è pensato per testi brevi, disposti su una sola riga.
JTextArea al contrario permette di scrivere testi ampi. Inoltre, è
capace di effettuare il ritorno a capo automatico quando siano
state attivate le proprietà wrapStyleWord e lineWrap.
Poiché JTextArea può raggiungere dimensioni ragguardevoli, è
opportuno aggiungere delle barre di scorrimento.
Per tale scopo esiste JScrollPane, un contenitore dotato di barre
di scorrimento pensato per contenere componenti troppi “ampi”
per essere visualizzati per intero.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
18
import javax.swing.*; import java.awt.*;
import java.awt.event.*;
public class TextSample extends JPanel implements
ActionListener {
JTextField testo; JTextArea area;
JScrollPane scroll; JButton btnAggiungi;
public TextSample() {
// crea e configura i componenti
testo = new JTextField("Campo di testo");
testo.setColumns(20);
btnAggiungi = new JButton("Aggiungi testo");
area = new JTextArea("TextArea");
area.setLineWrap(true);
area.setWrapStyleWord(true);
scroll = new JScrollPane(area);
scroll.setPreferredSize(
new Dimension(300, 200));
// aggiungi i componenti
add(testo);
add(btnAggiungi);
add(scroll);
// gestione eventi
btnAggiungi.addActionListener(this);
}
public void actionPerformed(ActionEvent evt) {
area.setText(area.getText() +
testo.getText());
}
public static void main(String[] args) {
...
}
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
19
GESTIONE DEL LAYOUT
Ogni Container è dotato di un layout manager, che calcola la
posizione dei componenti in base alle loro dimensioni
minime/preferite/massime e in base ad eventuali vincoli
aggiuntivi specificati quando si inseriscono i componenti nel
container.
Vedremo tre tipi di layout:
• FlowLayout: è il layout di default dei JPanel, ovvero il
layout manager visto sino ad ora;
• BorderLayout: un semplice layout manager, utile in varie
occasioni
• GridBagLayout: il layout manager più flessibile, ma anche
il più difficile da utilizzare, tanto complesso che faremo uso
di una classe di supporto per semplificarne l’utilizzo.
I constraint di norma sono specificati quando si aggiunge il
componente al Container. Vi sono infatti più metodi per
l’aggiunta, in overload, fra i quali troviamo:
void add(Component comp);
void add(Component comp, Object constraint);
Ing. Aime – Programmazione grafica in Java con la libreria Swing
20
FlowLayout
Un layout manager che dispone i componenti per riga, ciascuno
dimensionato secondo la sua preferred size. Se il container non è
sufficientemente largo, il layout manager va a capo.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
21
BorderLayout
Il border layout prevede la presenza di un massimo di 5
componenti, disposti come in figura:
Gli elementi sono disposti come i 4 segni cardinali, più il centro.
L’elemento di centro si allarga sia in altezza che in larghezza, gli
altri solo in larghezza (west e east) o solo in altezza (north e
south).
Ing. Aime – Programmazione grafica in Java con la libreria Swing
22
// aggiungi i componenti
add(button1, BorderLayout.NORTH);
add(button2, BorderLayout.CENTER);
add(button3, BorderLayout.EAST);
add(button4, BorderLayout.WEST);
add(button5, BorderLayout.SOUTH);
Nota: non è obbligatorio riempire tutte le posizioni.
GridBagLayout con GridBuilder
In questa sede verrà presentato un sottoinsieme delle possibilità
del GridBagLayout. L’idea di base è quella di collocare i
componenti nelle celle di una griglia “elastica”, ovvero capace di
ridimensionarsi quando il contenitore viene ridimensionato.
Ogni riga e colonna ha un peso. Un peso nullo significa che la
riga o la colonna faranno
0
1
0
uso della dimensione
0
minima dei componenti in
esse, e non cercheranno di
allargarsi, un peso non nullo
0
al contrario consentirà alla
colonna di allargarsi.
Maggiore il peso, maggiore
lo spazio occupato dalla riga
1
o dalla colonna.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
23
0
1
0
0
0
1
Ogni componente è posizionato in una cella, ma può
eventualmente occupare più celle (grid size maggiore di uno).
Nella figura sono mostrati 4 componenti, tre dei quali occupano
più di una cella.
0
1
0
0
0
1
Ing. Aime – Programmazione grafica in Java con la libreria Swing
24
Ogni componente può sfruttare in modo diverso l’area della
cella: può occupare soltanto la sua area preferenziale, estendersi
in larghezza, in altezza, o in entrambe le direzioni:
0
1
0
1
1
Se il componente non sfrutta tutta l’area della cella, può essere
posizionato in modo diverso al suo intero:
NorthWest
West
SouthWest
North
Center
South
NorthEast
East
SouthEast
Infine, un componente può avere una spaziatura rispetto al bordo
della cella, detto inset (usato per evitare che i componenti siano
troppo addossati l’uno all’altro):
0
1
0
1
Ing. Aime – Programmazione grafica in Java con la libreria Swing
25
Per creare un layout con il GridBagLayout occorre decidere:
• quante righe e quante colonne sono necessarie;
• quali pesi dare a righe e colonne;
• quali posizioni e numero di celle saranno occupate dai
componenti;
• come i componenti si allargano e, se necessario, in che
posizione devono essere collocati.
GridBuilder facilita la codifica di queste operazioni.
Nel costruttore vengono specificati il container, i pesi e l’inset:
// 5 righe, con i rispettivi pesi, 2 colonne,
// un inset pari a 3 pixel
GridBuilder gb = new GridBuilder(container,
new double[] { 0, 0, 0, 1, 0 },
new double[] { 0, 1}, 3);
Il grid builder tiene traccia della riga e della colonna correnti,
partendo da 0,0. Ogni volta che si aggiunge un componente la
colonna viene incrementata, se si raggiunge la fine riga, si passa
automaticamente alla riga successiva: non è quindi necessario
specificare riga e colonna per i componenti, si continua
semplicemente a chiamare la add per aggiungere nuovi
componeti.
gb.add(new JLabel(“Etichetta”));
gb.add(new JTextFiled(“Prova”));
gb.add(new Jlabel(“Etichetta2”));
Ing. Aime – Programmazione grafica in Java con la libreria Swing
26
gb.add(new JButton(“Bottone”));
Se è necessario saltare una cella si può chiamare skip(), se è
necessario andare a capo prima della fine della riga, newLine().
E’ inoltre possibile leggere e impostare row e column con gli
opportuni getter e setter.
Il metodo add restituisce un oggetto GridConstraints, che
consente di specificare i restanti parametri, ovvero dimensione,
spazio utlizzato e posizionamento.
public interface GridConstraints {
public GridConstraints gridSize(int gridWidth,
int gridHeight);
public
public
public
public
public
public
public
public
public
GridConstraints
GridConstraints
GridConstraints
GridConstraints
GridConstraints
GridConstraints
GridConstraints
GridConstraints
GridConstraints
north();
northEast();
northWest();
east();
center();
west();
southEast();
south();
southWest();
public GridConstraints fillHorizontal();
public GridConstraints fillVertical();
public GridConstraints fillBoth();
}
Ogni metodo restituisce un riferimento all’oggetto
GridConstraints stesso, questo consente di effettuare più chiamate
in cascata:
gb.add(new JLabel(“Ciao”)).
Ing. Aime – Programmazione grafica in Java con la libreria Swing
27
gridSize(2, 1).fillHorizontal().north();
Attenzione: specificare una gridSize > 0 non fa spostare il cursore
del grid builder. Se una cella è stata coperta da un componente
con larghezza > 0 bisogna saltarla chiamando skip()
Ing. Aime – Programmazione grafica in Java con la libreria Swing
28
Esempio
Si costruisca una finestra come la seguente:
Per prima cosa, individuiamo righe, colonne e pesi:
0
1
0
0
0
1
0
Ing. Aime – Programmazione grafica in Java con la libreria Swing
29
Questo individua anche la posizione degli elementi. Notiamo però
che l’etichetta Modulo di registrazione e il bottone Ok sono
centrati rispetto alla finestra devono occupare una intera riga
per essere posizionati al centro.
Pensiamo all’occupazione di spazio: l’etichetta del nome sembra
occupare tutto lo spazio orizzontale, la text area del commento,
anche quello verticale.
Infine, il posizionamento. Le etichette Nome e Età e il testo per
l’età sono a West, Commento è a NorthWest i restanti sono al
centro.
Il codice di costruzione dentro un JPanel allora è:
GridBuilder gb = new GridBuilder(this,
new double[] { 0, 0, 0, 1, 0 },
new double[] { 0, 1}, 3);
gb.add(new JLabel("Modulo di
registrazione")).gridSize(2, 1);
gb.newLine(); // attenzione!
gb.add(new JLabel("Nome")).west();
gb.add(new JTextField()).fillHorizontal();
gb.add(new JLabel("Età")).west();
gb.add(new JTextField(3)).west();
gb.add(new JLabel("Commento")).northWest();
JscrollPane scroll = new JScrollPane(
new JTextArea());
gb.add(scroll).fillBoth();
gb.add(new JButton("Ok")).gridSize(2, 1);
Ing. Aime – Programmazione grafica in Java con la libreria Swing
30
Reazione del pannello ai ridimensionamenti:
Ing. Aime – Programmazione grafica in Java con la libreria Swing
31
LAYOUT E COMPOSIZIONE DI PANNELLI
Ogni pannello è dotato di un proprio layout manager. Se non si
riesce ad ottenere il risultato voluto con un solo layout manager, si
possono comporre fra loro i pannelli e usare un layout manager
separato per ciascuno. Ad esempio:
In questa finestra sono presenti tre pannelli:
• il panello principale, con un BorderLayout, completamente
ricoperto dagli altri;
• il pannello dati, posto al centro del pannello principale,
dotato di un GridBagLayout
• il pannello con i bottoni, a sud del panello principale, con un
flow layout allineato a destra.
dataPanel (GridBagLayout)
buttonPanel (FlowLayout,
destra)
Principale (BorderLayout)
Ing. Aime – Programmazione grafica in Java con la libreria Swing
32
class MultiLayout extends JPanel {
JTextField txfName;
JTextField txfSurname;
JTextField txfAge;
JButton btnOk;
JButton btnCancel;
public MultiLayout() {
JPanel dataPanel = new JPanel();
txfName = new JTextField();
txfName.setColumns(20);
txfSurname = new JTextField();
txfSurname.setColumns(20);
txfAge = new JTextField();
txfAge.setColumns(3);
GridBuilder builder =
new GridBuilder(dataPanel,
new double[] {0,0,0, 1},
new double[] {0,1}, 3);
builder.add(new JLabel("Nome")).west();
builder.add(txfName).fillHorizontal();
builder.add(new JLabel("Cognome")).west();
builder.add(txfSurname).fillHorizontal();
builder.add(new JLabel("Età")).west();
builder.add(txfAge).west();
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(
new FlowLayout(FlowLayout.RIGHT));
btnOk = new JButton("Ok");
btnCancel = new JButton("Cancel");
buttonPanel.add(btnOk);
buttonPanel.add(btnCancel);
setLayout(new BorderLayout());
add(dataPanel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
}
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
33
DISEGNO LIBERO CON SWING
Ogni classe di Swing si disegna appropriatamente usando il
metodo paintComponent.
E’ possibile creare una propria classe che ridefinisce (override) il
metodo paintComponent per disegnare liberamente con l’oggetto
Graphics.
I metodi per disegnare figure aperte e testo sono:
drawLine(), drawRect(), drawRoundRect(),
draw3DRect(), drawOval(), drawArc(), drawString(),
drawPolygon(), drawPolyLine()
I metodi per disegnare figure piene sono:
fillRect(), fillRoundRect(), fill3DRect(),
fillOval(), fillArc(), fillPolygon(),
fillPolyLine()
Infine, i seguenti metodi impostano il colore e il font (ovvero, il
tipo di carattere usato):
getColor(), getFont(), setColor(), setFont().
I colori vengono specificati con gli oggetti Color. Si può
istanziare un oggetto Color specificando le componenti RGB o
usare le costanti simboliche definite in Color, come
Color.BLACK, Color.RED, Color.GREEN, …
I font possono essere creati specificando il nome di un carattere
(potete usare “Arial”, “Times New Roman”, “Courier”), lo stile
(Font.BOLD, Font.ITALIC o metterli insieme con Font.BOLD |
Font.ITALIC), e la dimensione.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
34
Tutti i metodi di disegno accettano delle coordinate: sono
coordinate in pixel rispetto all’origine.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Grafica1 extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillOval(80, 10, 40, 20);
g.setColor(Color.GREEN);
g.fillRoundRect(80, 160, 40, 40, 10, 5);
g.setColor(Color.BLUE);
g.drawArc(20, 20, 160, 160, 90, 270);
g.drawLine(20, 100, 100, 100);
g.drawLine(100, 20, 100, 180);
g.drawRect(10, 90, 20, 20);
g.setColor(Color.BLACK);
g.setFont(new Font("Arial", Font.BOLD, 12));
g.drawString("Testo libero!", 140, 80);
}
public static void main(String[] args) {
...
}
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
35
FINESTRE DI DIALOGO
Una finestra di dialogo rappresenta una finestra secondaria, usata
di norma per confermare inserimenti, aggiungere dettagli, eccetera
(si pensi alle finestre di dialogo formato/carattere di Word, o alla
finestra Configure/Options di JCreator).
Di norma queste finestre hanno un padre e sono modali. Una
finestra è modale rispetto al padre quando impedisce qualunque
interazione con il padre fino a che non viene chiusa. Di fatto, una
volta chiamato setVisible(true) il codice del padre resta congelato.
I costruttori possono avere le seguenti forme:
JDialog(Frame parent, String title, boolean modal);
JDialog(Dialog parent, String title, boolean modal);
Dato un componente comp si può ottenere il Frame che lo
contiene con:
Frame padre = OptionPane.getFrameForComponent(comp);
Al di la di questa differenza, una JDialog si comporta esattamente
come un JFrame: è una finestra, ha un content pane, un metodo
pack, e tutti gli altri metodi ereditati da Component.
Ing. Aime – Programmazione grafica in Java con la libreria Swing
36
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DialogSample extends JPanel implements
ActionListener {
JCheckBox check;
public DialogSample() {
check = new JCheckBox("Prova la selezione");
JButton btnSeleziona = new jButton("Seleziona");
add(btnSeleziona);
add(check);
btnSeleziona.addActionListener(this);
}
public void actionPerformed(ActionEvent event) {
SelectionDialog dialog =
new SelectionDialog(this);
System.out.println("Il codice si blocca e “ +
“ aspetta che la dialog si chiuda");
dialog.setVisible(true);
System.out.println("Il codice prosegue");
if(dialog.risposta) {
check.setSelected(true);
check.setText("Hai risposto si");
} else {
check.setSelected(false);
check.setText("Hai risposto no");
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Due finestre");
frame.setContentPane(new DialogSample());
frame.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
37
class SelectionDialog extends JDialog
implements ActionListener {
boolean risposta = false;
JButton btnSi;
JButton btnNo;
public SelectionDialog(Component parent) {
super(JOptionPane.getFrameForComponent(parent),
"Selezione", true);
JPanel buttons = new JPanel();
JLabel label =
new JLabel("Scegli una risposta");
btnSi = new JButton("Si");
btnNo = new JButton("No");
buttons.add(label);
buttons.add(btnSi);
buttons.add(btnNo);
setContentPane(buttons);
pack();
btnSi.addActionListener(this);
btnNo.addActionListener(this);
}
public void actionPerformed(ActionEvent event) {
risposta = event.getSource() == btnSi;
// chiudi la finestra e rilascia le risorse
setVisible(false);
dispose();
}
Ing. Aime – Programmazione grafica in Java con la libreria Swing
38