Le interfacce utente grafiche (Graphical User Interface)

Le interfacce utente grafiche (Graphical User Interface)
Il primo package Java che gestisce gli elementi di una GUI 1 è awt. Gli elementi di una GUI si
distinguono in oggetti di due tipi:
• oggetti contenitori
• oggetti componenti
Java usa un sistema generico per gestire la grafica, definendo elementi grafici comuni (oggetti
componenti che possono essere contenitori) in modo da costruire programmi eseguibili su varie
piattaforme e con ambienti grafici differenti (Windows ha un modo di visualizzare le finestre e gli
altri elementi grafici diverso da quello usato da Linux o da MacOs cioè il sistema operativo della
Applet). Il secondo pakage Java che gestisce gli elementi di una GUI, detto swing, è un'estensione
di awt e permette la vera indipendenza dalla piattaforma.
Tra i tipici oggetti contenitori il package awt rende disponibili:
•
•
•
frame (finestra): la classica finestra costituita da un’area rettangolare e da una barra del
titolo
panel (pannello): la forma più comune di contenitore che può essere visualizzato sullo
schermo.
canvas (area di disegno): una semplice superficie di disegno particolarmente utile per
visualizzare immagini o per effettuare altre operazioni grafiche.
I componenti sono oggetti con una propria rappresentazione grafica. Alcuni importanti componenti
della GUI di Java sono:
• Label (etichette)
• Button (pulsanti)
• TextField (campi di testo)
• TextArea (aree di testo)
• Checkbox (caselle di controllo)
Nella gerarchia di classi per i componenti ed i contenitori in Java si può notare che la radice della
maggior parte degli elementi
del package awt
è rappresentata
dalla classe astratta Component
(che a sua volta eredita dalla
superclasse Object,
superclasse di tutti
gli oggetti Java).
In realtà le classi
TextField
e TextArea ereditano
da TextComponent
con radice Component.
Le classi per creare controlli
e la classeCanvas
ereditano direttamente da Component.
1
2
La classe Frame
eredita da Window
che eredita da
Container2.
Da libro Gallo-Salerno “Java – La programmazione a oggetti” ed. Minerva Italica [UD C3]
Containers http://java.sun.com/docs/books/tutorial/uiswing/components/index.html
A differenza delle applicazioni, un Applet, non necessita di una finestra per essere eseguito infatti la
finestra è quella del browser a cui si aggiunge un pannello che rappresenta l’applet.
La classe Applet, infatti, eredita da Panel che eredita da Container la cui radice è appunto
Component.
Creazione e uso dei contenitori standard
La classe JFrame ha i seguenti metodi costruttori:
•
•
JFrame()
JFrame(“Stringa”)
Crea una finestra senza titolo
Crea una finestra senza titolo specificato in Stringa
Altri metodi che si applicano ad un oggetto della classe JFrame:
•
•
•
•
•
•
setSize(larghezza, altezza)
setLocation( x, y)
pack()
setVisible(boolean)
show())
setResizable(boolean)
dispose()
Dimensiona la finestra
Posiziona la finestra (coordinate del punto in alto a sinistra)
Ottimizza le dimensioni della finestra a seconda del contenuto
Per rendere visibile la finestra se true (deprecato il metodo
Per rendere ridimensionabile con mouse se true
Per chiudere la finestra, deallocando le risorse
La classe JPanel ha il seguente metodo costruttore:
•
JPanel ()
Crea un pannello per inserire componenti GUI
L’inserimento degli oggetti all’interno dei contenitori si realizza con il metodo add() con la
sintassi:
oggettoContenitore.add (oggettoDaAggiungere)
Tale metodo è polimorfo cioè opera su argomenti di diverse classi.
nb: è possibile aggiungere un componente e contemporaneamente sceglierne la posizione nel contenitore
(con possibili West, North, East, South e Center o equivalenti costanti in swing)
oggettoContenitore.add (“orientamento”, oggettoDaAggiungere )
es: nomePannello.add (“West”, nomeComponente);
nomePannello.add (“North”, nomeComponente);
// esempio di Applicazione con uso di oggetti GUI in ambiente JCreator
import java.awt.*;
import javax.swing.*;
public class Finestra {
private JFrame f ;
private Container c;
private JPanel p;
public Finestra ()
{ // costruttore
f = new JFrame("Visualizza sfondo colorato");
// crea frame o cornice invisibile
c = f.getContentPane();
// recupera il "muro grezzo"
// cioè il riquadro dei contenuti senza barra dei menù
// per impostare le dimensioni e la posizione:
f.setSize(300,150);
// misure in pixel: larghezza, altezza
f.setLocation(200,100);
// (0,0) angolo sup. sin
p = new JPanel();
p.setBackground(Color. lightGray);
// sfondo del pannello colorato
c.add(p);
f.setVisible(true);
// aggiunge il pannello
// mostra il frame (dimensioni 300x150) - deprecato show()
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
// rende attiva l'icona di chiusura
// nella barra del titolo
}
public static void main(String [] args) {
Finestra o = new Finestra();
// creo oggetto che "ha - un" oggetto JFrame ed un oggetto JPanel
}
}
nb:
setDefaultCloseOperation(JFrame.FLAG);
questo metodo permette di modificare l'azione di default di Java di continuare ad eseguire l'applicazione che
ha generato il frame anche dopo aver clickato sull'apposito bottone di chiusura del frame; segue un elenco
del significato del campo flag :
EXIT_ON_CLOSE : terminazione del programma quando il frame viene chiuso
DISPOSE_ON_CLOSE : chiude e libera il solo oggetto frame, il processo continua
DO_NOTHING_ON_CLOSE : mantiene aperto il frame e continua il processo (ignoriamo l'evento)
HIDE_ON_CLOSE : chiude il frame e continua l'esecuzione
Per nascondere i frames: setVisible(false) - deprecato hide()
Creazione e uso dei componenti standard
La classe JLabel : un esempio
// Applicazione con uso dei componenti di una GUI
// in ambiente JCreator
// Uso di un pannello per introdurre
// componenti JLabel
// e gestione di layout con allineamento in griglia
import java.awt.*;
import javax.swing.*;
public class MiaFinestra extends JFrame{
private Container c;
private JPanel p;
private JLabel l1, l2, l3, l4;
public MiaFinestra () {
// costruttore
super ("Finestra con componenti"); // imposta il titolo del frame invisibile
setSize(300,150);
// per impostare le dimensioni e la posizione(misure in pixel) :
setLocation(200,100);
// (0,0) angolo sup. sin.
setResizable(true);
// per ridimensionare con mouse
c = getContentPane();
// recupera il "muro grezzo"
p = new JPanel();
// per inserimento componenti con layout di tipo FlowLayout
// cioè uno di seguito all’altro da sinistra a destra
p.setBackground (Color.lightGray);
p.setLayout(new GridLayout (4,1)); // per evidenziare allineamento 4 RIGHE, 1 COLONNA
JLabel l1 = new JLabel ("Etichetta con sfondo colorato");
JLabel l2 = new JLabel ("Allineata al centro", JLabel.CENTER);
JLabel l3 = new JLabel ("Allineata a sinistra", JLabel.LEFT);
JLabel l4 = new JLabel ("Allineata a destra", JLabel.RIGHT);
l1.setBackground (Color.cyan);
l1.setOpaque(true);
// per vedere sfondo su sfondo
p.add(l2);
p.add(l3);
p.add(l4);
p.add(l1);
// aggiunge al pannello un'etichetta allineata al centro
// aggiunge al pannello un'etichetta allineata a sinistra
// aggiunge al pannello un'etichetta allineata a destra
// aggiunge al pannello un'etichetta con sfondo colorato
c.add(p); // aggiunge il pannello
setVisible(true); // mostra il frame (dimensioni 300x150)
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main(String [] args) {
MiaFinestra o = new MiaFinestra();
}
// creo oggetto che "ha" componenti Gui
}
Altri metodi :
• String getText()
restituisce il testo dell’etichetta o del JComponent
• setText (“Stringa”)
modifica il testo dell’etichetta o del JComponent
• int getHorizontalAlignment() restituisce come intero l’allineamento dell’etichetta (0 o 1 o 2)
• setHorizontalAlignment (int) modifica l’allineamento dell’etichetta a seconda della costante
intera: JLabel.CENTER o LEFT, RIGHT, LEADING, TRAILING (per default)
• setFont(Oggetto_classe_Font) modifica il tipo di carattere dell’etichetta
Le classi JButton, JTextField, JTextArea, JCheckBox, JRadioButton e ButtonGroup
// Applicazione per illustrare creazione di componenti di una GUI in ambiente JCreator
// Uso di pannello per introdurre componenti (per default con layout di tipo FlowLayout
// cioè i componenti sono aggiunti uno di seguito all’altro da sinistra a destra)
import java.awt.*;
import javax.swing.*;
public class Gui2 {
private JFrame f ;
private Container c;
private JPanel p;
private JLabel l;
private JButton b1, b2;
private JTextField t1, t2;
private JTextArea a1, a2;
private JCheckBox c1, c2, c3;
private ButtonGroup g;
private JRadioButton rb1, rb2;
// per creare pulsanti di opzione (uno solo selezionabile) detti Radio Button
public Gui2 () {
// costruttore
f = new JFrame("Finestra con componenti"); // crea frame invisibile
f.setSize(450,330);
// misure in pixel per impostare le dimensioni
f.setLocation(200,100); // e la posizione con (0,0) angolo sup. sin.
f.setResizable(true); // per ridimensionare con mouse
c = f.getContentPane();
p = new JPanel();
p.setBackground (Color.lightGray); // sfondo colorato
l = new JLabel ("Etichetta");
b1 = new JButton ();
b2 = new JButton ("Bottone");
t1 = new JTextField (30);
t2 = new JTextField ("immetti il nome", 20);
a1 = new JTextArea(5, 20);
// senza barre a scorrimento se non si inserisce in JScrollPane
a2 = new JTextArea("immetti una lista di nomi ", 5, 20);
a1.append ("Dimensionata con 5 righe e 20 colonne");
c1 = new JCheckBox();
c2 = new JCheckBox("Testo");
c3 = new JCheckBox("Testo attivato", true);
c1.setToolTipText("Senza testo");
// per visualizzare, al passaggio del mouse, testo esplicativo
g = new ButtonGroup(); // per gestire selezione
rb1 = new JRadioButton("Lingua Francese", false);
rb2 = new JRadioButton("Lingua Francese", true);
g.add(rb1);
g.add(rb2);
p.add(l); // aggiunge al pannello un'etichetta con testo
p.add(b1); // aggiunge al pannello un bottone colorato con etichetta
p.add(b2); // aggiunge al pannello un bottone con testo
p.add(t1); // aggiunge al pannello un campo di testo con ampiezza specificata
p.add(t2); // aggiunge al pannello un campo di testo con inizializzazione
// ed ampiezza specificata
p.add(a1); // aggiunge al pannello un' area di testo con Righe e Colonne specificate
p.add(a2); // aggiunge al pannello un'area di testo con inizializzazione
// e Righe e Colonne specificate
p.add(c1); // aggiunge al pannello una casella di controllo vuota e disattivata
p.add(c2); // aggiunge al pannello una casella di controllo con stringa
p.add(c3); // aggiunge al pannello una casella di controllo con stringa ed attivata
p.add(rb1); // aggiunge al pannello i Radio Button
p.add(rb2);
c.add(p); // aggiunge il pannello
f.setVisible(true);
// mostra il frame (dimensioni 400x400)
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main(String [] args) {
Gui2 o = new Gui2();
}
}
Altri metodi della classe JButton:
• String getText()
per ottenere il valore dell’etichetta dell’oggetto, deprecato getLabel()
Altri metodi della classe JCheckBox:
• String getText()
restituisce il valore dell’etichetta, deprecato getLabel()
• setText(“Stringa”)
imposta il valore dell’etichetta, deprecato setLabel()
Altri metodi delle classi che ereditano da JComponent:
• String getToolTipText() restituisce il valore del testo settato con setToolTipText
Altri metodi della classe JRadioButton ereditati dalla classe AbstractButton:
• isSelected()
ritorna il valore booleano che indica lo stato del radio-bottone
• setSelected (stato)
per settare lo stato del radio-bottone
Posizionamento diretto di un elemento GUI o tramite gestori di layout
Nel posizionamento diretto (dipendente dalle impostazioni grafiche del sistema) non abbiamo
bisogno di un gestore di layout (layout manager3) e dobbiamo indicare questo fatto con l’istruzione:
setLayout (null);
Definiremo poi le dimensioni dell’elemento e lo posizioneremo mediante il metodo setBounds()
con sintassi:
setBounds(x,y,larghezza,altezza) // x,y dell’angolo sup. sin.
Per default il gestore di layout per tutti i contenitori di tipo pannello è la classe FlowLayout che
aggiunge i componenti uno di seguito all’altro da sinistra a destra (nello stesso ordine in cui
vengono aggiunti col metodo add ): riempita la prima riga si inizia la seconda e così via.
Abbiamo già fatto uso della classe GridLayout con costruttore GridLayout (numero righe,
numero colonne) per posizionare i componenti nelle celle di una tabella tutte caratterizzate dalla
stessa dimensione. Un altro costruttore permette di impostare anche la spaziatura verticale e quella
orizzontale: GridLayout (num_righe, num_colonne, spaziatura_verticale, spaziatura_orizzontale)
BorderLayout
BorderLayout divide lo schermo in cinque regioni: North, East, West,
South, Center. È, di default il gestore di layout per i contenitori ad alto
livello come i Content Pane.
BorderLayout assicura a North, South, East e West tanto spazio quanto
richiedono, lo spazio rimanente viene assegnato a Center.
BorderLayout può essere costruito con costruttore BorderLayout () oppure con BorderLayout
(spaziatura_orizzontale, spaziatura_verticale) specificano lo spazio orizzontale e verticale tra due
componenti.
nb: nel package swing tali regioni vengono definite dalle costanti BorderLayout.PAGE_START,
BorderLayout.LINE_START, BorderLayout.LINE_END, BorderLayout.PAGE_END e
BorderLayout.CENTER rispettivamente per indicare in alto, a sinistra, a destra, in basso e
centro.
Oltre alle numerose classi che già awt introduceva per gestire il posizionamento, swing rende
disponibile anche la classe BoxLayout per una scelta general purpose nell’impilare i vari elementi.
3
Gestori di Layout http://java.sun.com/docs/books/tutorial/uiswing/layout/visual.html (guida visuale)
/******************************************************************/
/* GESTIONE DI UN LAYOUT SEMPLICE MEDIANTE USO DI SWING ****/
/******************************************************************/
import javax.swing.*;
import java.awt.*;
public class SempliceLayout extends JFrame {
//Creiamo i componenti
JLabel ipLabel = new JLabel("IP host", SwingConstants.LEFT);
// per default a sinistra
JLabel passwordLabel = new JLabel("Password", SwingConstants.LEFT);
JLabel fileDaInviareLabel = new JLabel("File da inviare", SwingConstants.LEFT);
JTextField ipText = new JTextField(20);
// impostiamo numero caratteri
JPasswordField passwordText = new JPasswordField(20); // impostiamo numero caratteri
JTextField fileDaInviareText = new JTextField(20);
// impostiamo numero caratteri
JButton pulsante = new JButton("Inizia TX");
public SempliceLayout() {
// costruttore dell'applicazione
super("File transfer appz");
setSize(320, 150);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel pannello = new JPanel();
// dimensioni adatte [*]
// impostiamo le proprietà dei componenti
ipText.setEditable(true);
fileDaInviareText.setEditable(true);
passwordText.setEchoChar('*');
// usiamo il Layout di default di JPanel di tipo FlowLayout
pannello.add(ipLabel);
pannello.add(ipText);
pannello.add(passwordLabel);
pannello.add(passwordText);
pannello.add(fileDaInviareLabel);
pannello.add(fileDaInviareText);
pannello.add(pulsante);
setContentPane(pannello); // rendiamo il pannello parte del nostro frame
setResizable(false);
// immodificabili dimensioni [*]
setVisible(true);
// visualizziamo il tutto
}
public static void main(String argv[]) {
new SempliceLayout();
}
}
/*****************************************************************************/
/* GESTIONE DI UN LAYOUT A GRIGLIA AVANZATA MEDIANTE USO DI SWING ****/
/*****************************************************************************/
import javax.swing.*;
import java.awt.*;
public class Layout extends JFrame {
//Creiamo i componenti
JLabel ipLabel = new JLabel("IP host", SwingConstants.LEFT);
// per default a sinistra
JLabel passwordLabel = new JLabel("Password", SwingConstants.LEFT);
JLabel fileDaInviareLabel = new JLabel("File da inviare", SwingConstants.LEFT);
JTextField ipText = new JTextField();
// non ci preoccupiamo di impostare numero caratteri
JPasswordField passwordText = new JPasswordField();
JTextField fileDaInviareText = new JTextField();
JButton pulsante = new JButton("Inizia TX");
// Definiamo un metodo che ci servirà per definire i limiti di layout
void impostaLimite(GridBagConstraints gbc, int gx, int gy, int gw, int gh, int wx, int wy) {
gbc.gridx = gx;
gbc.gridy = gy;
gbc.gridwidth = gw;
gbc.gridheight = gh;
gbc.weightx = wx;
gbc.weighty = wy;
}
public Layout() {
// costruttore dell'applicazione
super("File transfer appz");
setSize(300, 120);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel pannello = new JPanel();
// impostiamo le proprietà dei componenti
ipText.setEditable(true);
fileDaInviareText.setEditable(true);
passwordText.setEchoChar('*');
//definiamo il gestore di layout
GridBagLayout grigliaAvanzata = new GridBagLayout();
// griglia personalizzata
GridBagConstraints limite = new GridBagConstraints();
pannello.setLayout(grigliaAvanzata);
//definiamo i limiti di ogni componente e lo aggiungiamo al pannello
impostaLimite(limite,0,0,1,1,35,0);
//etichetta IP host
limite.fill = GridBagConstraints.NONE;
limite.anchor = GridBagConstraints.EAST;
grigliaAvanzata.setConstraints(ipLabel,limite);
pannello.add(ipLabel);
impostaLimite(limite,1,0,1,1,65,100);
//campo IP host
limite.fill = GridBagConstraints.HORIZONTAL;
grigliaAvanzata.setConstraints(ipText,limite);
pannello.add(ipText);
impostaLimite(limite,0,1,1,1,0,0);
//etichetta password
limite.fill = GridBagConstraints.NONE;
limite.anchor = GridBagConstraints.EAST;
grigliaAvanzata.setConstraints(passwordLabel,limite);
pannello.add(passwordLabel);
impostaLimite(limite,1,1,1,1,0,100);
//campo password
limite.fill = GridBagConstraints.HORIZONTAL;
grigliaAvanzata.setConstraints(passwordText,limite);
pannello.add(passwordText);
impostaLimite(limite,0,2,1,1,0,0);
//etichetta File da inviare
limite.fill = GridBagConstraints.NONE;
limite.anchor = GridBagConstraints.EAST;
grigliaAvanzata.setConstraints(fileDaInviareLabel,limite);
pannello.add(fileDaInviareLabel);
impostaLimite(limite,1,2,1,1,0,100);
//campo File da inviare
limite.fill = GridBagConstraints.HORIZONTAL;
grigliaAvanzata.setConstraints(fileDaInviareText,limite);
pannello.add(fileDaInviareText);
impostaLimite(limite,0,3,2,1,0,50);
// Pulsante
limite.fill = GridBagConstraints.NONE;
limite.anchor = GridBagConstraints.CENTER;
grigliaAvanzata.setConstraints(pulsante,limite);
pannello.add(pulsante);
setContentPane(pannello);
// rendiamo il pannello parte del nostro frame
setVisible(true); // Visualizziamo il tutto!
}
public static void main(String argv[]) {
Layout nf = new Layout();
}
}
GridBagLayout può organizzare interfacce grafiche complesse rendendo possibile dividere il
container in una griglia e, a differenza del GridLayout, può disporre i suoi componenti in modo tale
che si estendano anche oltre un’unica cella, attraverso la classe GridBagConstraints.
/******************************************************************************/
/* SEMPLICI ETICHETTE, CAMPI ED AREE DI TESTO MEDIANTE USO DI SWING ****/
/******************************************************************************/
import javax.swing.*;
import java.awt.GridLayout;
public class EtichetteEcampi extends JFrame {
JLabel etichetta1 = new JLabel("Allineamento a sinistra ",SwingConstants.LEFT);
JLabel etichetta2 = new JLabel("Allineamento al centro",SwingConstants.CENTER);
JLabel etichetta3 = new JLabel("Allineamento a destra ", SwingConstants.RIGHT);
JTextField campoDiTesto = new JTextField("Immetti qui una stringa...",30);
JTextArea areaDiTesto = new JTextArea("Questa é un'area di testo di\n5 righe e 30 colonne",5,30);
public EtichetteEcampi() {
super("Etichette e campi");
setSize(350, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel pannello = new JPanel();
// impostiamo le proprietà dei componenti
campoDiTesto.setEditable(true);
areaDiTesto.setLineWrap(true);
areaDiTesto.setWrapStyleWord(true);
// ora aggiungiamo i componenti al pannello
pannello.setLayout(new GridLayout(0,1));
pannello.add(etichetta1);
pannello.add(etichetta2);
pannello.add(etichetta3);
pannello.add(campoDiTesto);
pannello.add(areaDiTesto);
// rendiamo il pannello parte del nostro frame
setContentPane(pannello);
setVisible(true); // Visualizziamo il tutto!
}
public static void main(String argv[]) {
EtichetteEcampi ec = new EtichetteEcampi();
}
}
nb: public GridLayout (int rows, int cols) crea un layout a griglia dove tutti i componenti sono delle stesse
dimensioni. Uno tra numero rige e colonne - ma non entrtambi - può essere zero: significa che un qualsiasi
numero di oggetti può essere inserito o nell'unica riga o nell'unica colonna
// da http://www.java2s.com/Code/JavaAPI/javax.swing/SwingConstantsRIGHT.htm
Etichette e bordi
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class EtichetteBordi {
private JLabel label1, label2,label3;
private JFrame frame;
private JPanel p;
public EtichetteBordi(){
label1 = new JLabel("BottomRight", SwingConstants.RIGHT);
label2 = new JLabel("CenterLeft", SwingConstants.LEFT);
label3 = new JLabel("TopCenter", SwingConstants.CENTER);
label1.setVerticalAlignment(SwingConstants.BOTTOM);
label2.setVerticalAlignment(SwingConstants.CENTER);
label3.setVerticalAlignment(SwingConstants.TOP);
label1.setBorder(BorderFactory.createLineBorder(Color.black));
label2.setBorder(BorderFactory.createLineBorder(Color.black));
label3.setBorder(BorderFactory.createLineBorder(Color.black));
frame = new JFrame("AlignmentExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p = new JPanel(new GridLayout(3, 1, 0, 8)); // righe, colonne, pixel tra colonne, pixel tra righe
// in questa applicazione, con unica colonna,
// è indifferente hgap che pùò valere anche 0
p.add(label1);
p.add(label2);
p.add(label3);
p.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); // top, left, bottom, right
frame.setContentPane(p);
frame.setSize(300, 200);
frame.setVisible(true);
}
public static void main(String[] args) {
new EtichetteBordi();
}
}
nb: public GridLayout (int rows, int cols, int hgap, int vgap) crea un layout a griglia dove tutti i
componenti sono delle stesse dimensioni e rende possibile impostare il numero di pixel tra le colonne come
per il margine destro e sinistro dai bordi (horizontal gap) ed il numero di pixel tra le righe come per i
margini in alto e basso dai bordi (vertical gap).
/**
* @(#)Gui.java
* Gui application
* @author 3AI
* @version 1.00 2009/4/4
*/
import java.awt.*;
import javax.swing.*;
class MioPanel extends JPanel{
public MioPanel(){
this.setPreferredSize(new Dimension(180, 150)); // per reimpostare dinamicamente
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(20,20, 100,80);
g.setColor(Color.blue);
g.drawRect(30,30, 80,60);
g.setColor(Color.black);
g.drawString("ciao",50,60);
}
}
class Bottone extends JPanel{
private JButton b;
public Bottone(){
b = new JButton("label del bottone");
b.setBackground(Color.white);
b. setPreferredSize(new Dimension(130, 15));
this.add(b); // oggetto corrente
}
}
public class Gui {
private JFrame f;
private Container c;
private MioPanel p; // pannelli personalizzati
private Bottone p2;
public Gui(){
f = new JFrame("Due pannelli"); // crea un nuovo JFrame Inizialmente invisibile con titolo
c = f.getContentPane(); // recupera il "muro grezzo"
p = new MioPanel(); // crea pannello personalizzato adattabile alle dimensioni della finestra
p2 = new Bottone(); // crea altro pannello personalizzato adattabile alle dimensioni di bottone e finestra
p2.setBackground(Color.blue);
c.setLayout(new BorderLayout()); // scelta di Layout che distingue tra alto, basso, destra, sinistra e centro
c.add(p,BorderLayout.CENTER); // al centro il pannello con disegno
c.add(p2,BorderLayout.PAGE_END); // in basso il bottone (per retrocompatibiltà anche SOUTH)
f.pack();
// ottimizza le dimensioni della finestra
f.setLocation(400,150);
f.setVisible(true);
// mostra il JFrame
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] v){
Gui gui = new Gui();
}
}
// Lo stesso esempio di Applicazione con uso GUI già usato per introdurre componenti GUI
// in un pannello. Posizionamento tramite gestori di layout: impilando in verticale
import java.awt.*;
import javax.swing.*;
public class Gui2 {
private JFrame f ;
private Container c;
private JPanel p;
private JLabel l;
private JButton b1, b2;
private JTextField t1, t2;
private JTextArea a1, a2, a3;
private JScrollPane sp;
private JCheckBox c1, c2, c3:
private ButtonGroup g;
private JRadioButton rb1, rb2;
// con barre a scorrimento inserendo JTextArea in JScrollPane
// per creare pulsanti di opzione (uno solo selezionabile) detti Radio Button
public Gui2 () {
// costruttore
f = new JFrame("Finestra con componenti");
// crea frame invisibile
// per impostare le dimensioni e la posizione:
f.setSize(450,330);
// misure in pixel
f.setLocation(200,100);
// (0,0) angolo sup. sin.
f.setResizable(true);
// per ridimensionare con mouse
c = f.getContentPane();
// recupera il "muro grezzo"
p = new JPanel();
p.setBackground (Color.lightGray); // sfondo colorato
p.setLayout (new BoxLayout (p, BoxLayout.PAGE_AXIS)); // impila gli elementi in verticale nel pannello
l = new JLabel ("Etichetta");
b1 = new JButton ();
b2 = new JButton ("Bottone");
b1.setBackground (Color.cyan);
b1.setText("Bottone con etichetta"); // imposta il valore dell’etichetta ( deprecato setLabel (testo) )
t1 = new JTextField (30);
t2 = new JTextField ("immetti il nome", 20);
a1 = new JTextArea(5, 20);
a1.append("Dimensionata con 5 righe e 20 colonne");
a2 = new JTextArea("immetti una lista di nomi ", 5, 20);
a3 = new JTextArea("immetti un commento personale ", 2, 15);
sp = new JScrollPane(a3);
// per vedere barre a scorrimento in JTextArea
c1 = new JCheckBox();
c2 = new JCheckBox("Testo");
c3 = new JCheckBox("Testo attivato", true);
c1.setToolTipText("Senza testo"); // per visualizzare, al passaggio del mouse, testo esplicativo
// Per creare pulsanti di opzione (uno solo selezionabile) detti Radio Button
g = new ButtonGroup(); // per gestire selezione
rb1 = new JRadioButton("Lingua Francese", false);
rb2 = new JRadioButton("Lingua Francese", true);
g.add(rb1);
g.add(rb2);
p.add(l); // aggiunge al pannello un'etichetta con testo
p.add(b1); // aggiunge al pannello un bottone colorato con etichetta
p.add(b2); // aggiunge al pannello un bottone con testo
p.add(t1); // aggiunge al pannello un campo di testo con ampiezza specificata
p.add(t2); // aggiunge al pannello un campo di testo con inizializzazione ed ampiezza specificata
p.add(a1); // aggiunge al pannello un' area di testo con Righe e Colonne specificate
p.add(a2); // aggiunge al pannello un'area di testo con inizializzazione e Righe e Colonne specificate
p.add(sp); // aggiunge al pannello un Pannello a scorrimento che contiene
// un'area di testo con inizializzazione e Righe e Colonne ridotte per visualizzare barre a scorrimento
p.add(c1); // aggiunge al pannello una casella di controllo vuota e disattivata
p.add(c2); // aggiunge al pannello una casella di controllo con stringa
p.add(c3); // aggiunge al pannello una casella di controllo con stringa ed attivata
p.add(rb1); // aggiunge al pannello i Radio Button
p.add(rb2);
c.add(p); // aggiunge il pannello
f.setVisible(true);
// mostra il frame (dimensioni 400x400)
f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE);
}
public static void main(String [] args) {
Gui2 o = new Gui2();
}
}
nb: per “impilare” in orizzontale BoxLayout (nomeContenitore, BoxLayout.LINE_AXIS)
Impilando gli elementi in verticale nel pannello
Impostando 6 Righe e 2 colonne
(con solo 12 componenti)
Default: un componente dopo l’altro
Lo stesso modo di introdurre componenti GUI si può realizzare con Applet o piuttosto JApplet se si
usano JComponent. Vediamo un esempio che crea una finestra diversa da quella del browser
(confrontare con l’applicazione Gui):
// esempio di JApplet con uso dei componenti di una GUI (chiusura finestra browser per uscire)
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class GuiA extends JApplet {
public void init() {
JFrame f = new JFrame("Finestra con componenti"); // crea frame invisibile
f.setSize(300,150);
f.setLocation(200,100);
// misure in pixel per impostare le dimensioni
// e la posizione con (0,0) angolo sup. sin.
f.setResizable(true); // per ridimensionare con mouse
Container c = f.getContentPane();
JPanel p = new JPanel();
p.setBackground (Color.gray);
// recupera il "muro grezzo"
// sfondo colorato
p.setLayout(new GridLayout(4,4)); // per evidenziare allineamento
JLabel l1 = new JLabel ("Etichetta con sfondo colorato");
JLabel l2 = new JLabel ("Allineata al centro", JLabel.CENTER);
JLabel l3 = new JLabel ("Allineata a sinistra", JLabel.LEFT);
JLabel l4 = new JLabel ("Allineata a destra", JLabel.RIGHT);
l1.setBackground (Color.cyan);
l1.setOpaque(true);
p.add(l2);
p.add(l3);
p.add(l4);
p.add(l1);
// vedere sfondo su sfondo
// aggiunge al pannello un'etichetta allineata al centro
// aggiunge al pannello un'etichetta allineata a sinistra
// aggiunge al pannello un'etichetta allineata a destra
// aggiunge al pannello un'etichetta con sfondo colorato
c.add(p); // aggiunge al frame il pannello colorato
f.setVisible(true);
// mostra il frame (dimensioni 300x150)
// NB: si noti come per ragioni di sicurezza sia proibito l’uso di
// f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
}
Nel codice HTML: <object code ="GuiA.class" width= "300" height= "0"></object>
le dimensioni obbligatorie pur se nulle, qui sono scelte in modo da permettere di leggere
completamente, eseguendo in ambiente JCreator, il titolo della cornice del visualizzatore della
Java Applet Window con messaggio di Applet avviato o non avviato.
NB: Un’ applet dunque può aprire un'altra finestra ma compare automaticamente un avviso anche
solo come piccola icona di allerta in alto a sinistra della nuova finestra che ricorda come la Java
Applet Window non sia mai completamente invisibile.
nb: per eseguire la pagina html con opzione Run in JCreator, salvare tale pagina web nella stessa
cartella del bytecode (classes). Si noti che,scegliendo come progetto Basic Java Applet
si crea nella sottocartella classes la seguente pagina
<html>
<head> </head>
<body bgcolor="000000">
<center><applet code
width
height
</applet>
</center>
</body>
= "NomeClasse.class"
= "500"
= "300" >
</html>
con uso di tag obsoleto <applet></applet>
Esercizio:
Creare un’applet che disegni il cruscotto di un’automobile in una finestra separata.
Nel cruscotto devono apparire
•
•
•
•
4 bottoni con testo: Freccia Sx, Freccia Dx, Freno Manuale, Avvia Motore
un’etichetta con testo Luci con associate 3 caselle opzione (esclusiva) con testo posizioni,
anabbaglianti, abbaglianti , tutte non attivate
un’etichetta carburante
ed un JTextField largo 30 pixel
150 pixel
570 pixel
Soluzione:
// esempio di JApplet con uso contenitori e componenti GUI
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class Cruscotto extends JApplet {
public void init() {
JFrame f = new JFrame ("Cruscotto di un auto");
f.setSize (570, 150);
f.setLocation (100,100);
f.setResizable(true); // con mouse ridimensionabile
Container c = f.getContentPane(); // recupera il "muro grezzo"
ButtonGroup luci = new ButtonGroup();
JRadioButton rb1 = new JRadioButton("posizioni", false);
JRadioButton rb2 = new JRadioButton("anabbaglianti", false);
JRadioButton rb3 = new JRadioButton("abbaglianti", false);
luci.add(rb1);
luci.add(rb2);
JButton FrecciaSx = new JButton ("Freccia Sx");
JButton FrecciaDx = new JButton ("Freccia Dx");
JButton FrenoManuale = new JButton ("Freno Manuale");
JButton AvviaMotore = new JButton ("Avvia Motore");
JTextField carburante = new JTextField (30);
c.setLayout (new GridLayout (3,4,10,10));
c.add(FrecciaSx);
c.add(FrecciaDx);
c.add(AvviaMotore);
c.add(FrenoManuale);
c.add(new Label("Luci"));
c.add(rb1);
c.add(rb2);
c.add(rb3);
c.add(new Label("Carburante"));
c.add(carburante);
f.setVisible(true);
}
}
Nel codice HTML:
<object code ="Cruscotto.class" width= "0" height= "0"></object>
nb: per eseguire la pagina html con opzione Run in JCreator, salvare tale pagina web nella stessa
cartella del bytecode (classes).
I Canvas
Tra i vari contenitori Java il Canvas (area di disegno o tela) è una semplice superficie di disegno
particolarmente utile per visualizzare immagini o per effettuare altre operazioni grafiche.
Un oggetto di tipo Canvas è semplicemente una porzione rettangolare di schermo, una specie di
pannello che possiede un proprio metodo paint() che, pur diverso dall’omonimo metodo di un
Applet, usa anch’esso oggetti della classe Graphics ed è richiamato dal sistema in fase di creazione
e aggiornamento in modo che l’oggetto Graphics associato possa aggiornarsi .
Una istanza della classe Canvas non è molto utile: riceve eventi da tastiera e da mouse, ma non li
tratta, ed il metodo paint() non disegna alcunché.
Generalmente la classe Canvas è usata solo come base per subclassi, che possono generare
oggetti più utili: una subclasse di Canvas generalmente farà almeno un’override del metodo
paint() e possibilmente anche dei metodi di gestione degli eventi come quelli del mouse e della
tastiera.
Quando il contenuto del canvas dovrà essere modificato al di fuori del metodo paint(), sarà
possibile richiamare il contesto grafico con i metodi getGraphics(). Vedremo come questi
metodi possono essere usati per i canvas creando ad esempio un bottone di forma personalizzata e
colore modificato da eventi
Pur se è possibile disegnare direttamente in ogni Component, ed è comune disegnare direttamente
su applet e finestre, è di solito meglio collocare ogni operazione di disegno nelle sottoclassi del
Canvas: nei casi in cui sia necessario disegnare su un’applet che contiene anche dei bottoni, l'uso
di un canvas è pressochè inevitabile.
// esempio di Applicazione con uso GUI (necessita una finestra o JFrame)
// Per disegnare uso di classe che eredita da Canvas
import java.awt.*;
import javax.swing.*;
public class Graf{
public Graf () {
JFrame f = new JFrame("Finestra"); // crea frame invisibile
Container c = f.getContentPane(); // recupera il "muro grezzo"
Disegno d = new Disegno();
// classe esterna che eredita da Canvas
c.add (d);
f.setSize(300,180);
// per impostare le dimensioni e la posizione: misure in pixel
f.setLocation(200,100);
// (0,0) angolo sup. sin.
f.setResizable(true); // per ridimensionare (per default non ridimensionabili) con mouse
f.setVisible(true);
// mostra il frame (dimensioni 300x150)
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main(String [] args) {
Graf ogg = new Graf();
}
}// fine classe principale
// classe esterna eventualmente nello stesso file Graf.java
class Disegno extends Canvas {
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillRect(20,20,100,80); // rettangolo pieno
g.setColor(Color.blue);
g.drawRect(30,30,80,60);
// linea rettangolare
g.setColor(Color.black);
g.drawString("ciao", 50,60);
Font f1 = new Font("Times", Font.PLAIN, 20);
g.setFont(f1);
g.drawString("ciao", 200,60);
// cambiare font
// per recuperare le proprietà del font
f1 = g.getFont();
int size = f1.getSize();
int style = f1.getStyle();
String name = f1.getName();
g.drawString("Font di dimensioni " + size, 50,140);
System.out.println("Font di dimensioni "+ size +" stile " + style + " e nome " + name);
}
}// fine classe che eredita da Canvas
Esercizio:
Creare un Applet che disegni un’automobile in modo
stilizzato:
1) direttamente nella finestra del browser.
2) con un canvas in una finestra separata. Si
costruisca una classe AutoC con gli opportuni metodi
grafici già usati per disegnarla direttamente nella
finestra del browser.
Soluzione: esempio di Applet che usa canvas in una finestra separata
import java.awt.*;
import java.applet.*;
import javax.swing.*;
public class AutoC extends JApplet {
Auto A;
public void init() {
JFrame f1 = new JFrame ("Disegna auto");
A = new Auto();
// istanza che eredita da Canvas
f1.setSize (500, 420);
f1.setLocation (50,50);
f1.setResizable(true); // con mouse ridimensionabile
Container c =f1.getContentPane();
c.add(A);
f1.setVisible(true);
}
}
class Auto extends Canvas {
public void paint(Graphics g) {
Font f = new Font("Times Roman", Font.BOLD, 20);
g.setFont(f);
g.fillOval(120, 220, 60,60); // una ruota piena
g.fillOval(320, 220, 60,60); // altra ruota piena
g.setColor(Color.blue);
// carrozzeria blu
g.drawRect(50, 150, 400, 70);
g.drawLine(170,150,200,100);
g.drawLine(330,150,300,100);
g.drawLine(300,100,200,100);
g.setColor(Color.yellow);
// luci gialle
g.fillRect(50, 170, 20, 30);
g.setColor(Color.red);
// luci rosse
g.fillRect(430, 150, 20, 20);
g.setColor(Color.cyan);
// testo cyan
g.drawString("Automobile", 200, 350);
}
}
Codice HTML:
<html>
<head><title>Disegno di un Auto </title></head>
<body>
<object code ="AutoC.class"
width= "500"
height= "150">></object>
</body>
</html>
nb: per eseguire la pagina html con opzione Run in JCreator, salvare tale pagina web nella stessa
cartella del bytecode (classes).
Gli Eventi
Quando l’utente di una GUI digita caratteri o usa il mouse o un componente dell’interfaccia grafica,
il gestore delle finestre di Java invia una comunicazione al programma per segnalare che si è
verificato un evento.
Esistono classi d’ascolto di eventi (event listener) per permettere ad un programma di indicare
quali eventi gradisce ricevere.
Ogni programma dovrà creare un oggetto per ognuna delle classi cui è interessato; tali oggetti
prendono il nome di ascoltatori (oggetto di una classe di ascolto).
La classe di ascolto deve implementare almeno una interfaccia di ascolto (interfacce di tipo
listener).
Un ascoltatore di eventi è un oggetto di una classe di ascolto che implementa almeno una interfaccia
di ascolto. Tali interfacce sono contenute nel package java.awt.event che deve essere importato.
Per creare un ascoltatore bisogna conoscere l’origine dell’evento che può essere l’intera applet o
una sua parte. Per origine dell’evento si intende il contenitore o il componente che può generare
l’evento (ad esempio un pulsante è l’origine dell’evento tipo “clic su pulsante”).
Eventi del mouse
Esempio con gestione eventi del mouse:
// ClickMe.java
import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
// classe di ascolto
public class ClickMe extends JApplet implements MouseListener { // tipo di evento ad esempio
// pressione del mouse
private Spot spot = null;
private static final int RADIUS = 7;
public void init() {
addMouseListener(this); // per collegare ascoltatore all’origine dell’evento: tutta l’applet
}
public void paint(Graphics g) {
//draw a black border and a white background
g.setColor(Color.white);
g.fillRect(0, 0, getSize().width - 1, getSize().height - 1);
//oppure g.fillRect(0, 0, getWidth() - 1, getHeight()- 1);
g.setColor(Color.black);
g.drawRect(0, 0, getSize().width - 1, getSize().height - 1);
//oppure g. drawRect(0, 0, getWidth() - 1, getHeight()- 1);
//draw the spot
g.setColor(Color.red);
if (spot != null) {
g.fillOval(spot.x - RADIUS, spot.y - RADIUS, RADIUS * 2, RADIUS * 2);
}
}
public void mousePressed(MouseEvent event) {
if (spot == null) { spot = new Spot(RADIUS); }
spot.x = event.getX();
spot.y = event.getY();
repaint();
}
public void mouseClicked(MouseEvent event) {}
public void mouseReleased(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
// tipo evento: pressione del mouse
// altri metodi dell’interfaccia di ascolto
// per evitare di scrivere tali segnature
// di metodi si usa classe Adapter che
// implementa interfaccia MouseListener
}
// Spot.java
public class Spot {
public int size;
public int x, y;
public Spot(int intSize) {
size = intSize;
x = -1;
y = -1;
}
}
Nel codice HTML le dimensioni obbligatorie non saranno nulle:
•
con codice più datato (IE):
<object code ="GuiA.class" width= "200" height= "100">></object>
•
con codice HTML che carica ed esegue Applet con "Java Plug in" per consentire al browser
di usare un interprete Java esterno (più aggiornato) e adatta anche a Mozilla – FireFox ed
altri browser che non supportano il tag <object>:
<html>
<head><title>Uso Eventi</title></head>
<body>
<p>Carica ed esegue Applet con uso di Java Plug-in (anche per NN versioni precedenti alla 6):
<p>appare uno spot rosso nel punto dove fai click col mouse
<p><object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
width="200" height="100">
<param name="code" value="ClickMe.class">
<param name="type" value="application/x-java-applet;version=1.6">
<comment><embed type="application/x-java-applet" width="200" height="100"
code="ClickMe.class">
</embed>
</comment>
</object>
</body>
</html>
NB: getWidth() e getHeight() per recupero dimensioni senza creare oggetto Dimension con
getSize()
Esempio con gestione eventi del mouse con adattatore (classe di raccordo Adapter) che evita di
dover scrivere tutte le segnature dei metodi dell'interfaccia di ascolto :
// Pallini.java versione Applet
import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Pallini extends JApplet{
private int xP,yP;
public void init() {
MiaClasseAscoltoMouse A1 = new MiaClasseAscoltoMouse ();
addMouseListener (A1); // lega la classe di ascolto all’origine dell’evento: cioè
// tutta l’applet (è sottinteso this : manca oggetto origine)
}
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillOval(xP,yP,20,20);
}
public void test() {
// per test in ambiente JCreator
int x = getLocationOnScreen().x;
// ritorna l’ascissa del punto
int y = getLocationOnScreen().y;
// ritorna l’ordinata del punto
System.out.println( "punto (" + xP + "," + yP +")" );
}
// classe interna cioè innestata non statica
private class MiaClasseAscoltoMouse extends MouseAdapter {
public void mousePressed (MouseEvent e) {
xP = e.getX();
// accede alla variabili istanza xP e yP della classe esterna
yP = e.getY();
// recupera gli attributi dell’oggetto di tipo Point “puntato” dal mouse
// cioè le coordinate x ed y
repaint();
test(); // per visualizzare coordinate
}
}
}// fine classe Pallini
Con codice HTML:
<html>
<head><title>Uso Classe Adapter</title></head>
<body>
Se premi con il mouse (all'interno di una zona) compare un pallino rosso <br>
<object code ="Pallini.class" width = "500" height = "400"></object>
</body>
</html>
NB: per estrarre coordinate sullo schermo getLocationOnScreen() della classe java.awt.Component può
essere invocato per recuperare le coordinate del punto in alto a sinistra ad esempio dell’applet; il metodo
ritorna infatti un oggetto di tipo Point con attributi x ed y ed è applicabile al componente corrente
/**
* @(#)Pallini.java
*
* Pallini application
*
* @author classi
* @version 1.00 2011/4/14
*/
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class Pallini extends JPanel{
private int x,y;
private JFrame f ;
public Pallini() {
f= new JFrame();
f.setContentPane(this);
MiaClasseAscoltoMouse A1 = new MiaClasseAscoltoMouse ();
addMouseListener (A1); // lega la classe di ascolto all’origine dell’evento: cioè tutta
// l’applicazione (this è sottinteso)
f.setTitle("Sposta e Premi Mouse");
f.setLocation(300,300);
f.setSize(320,300);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public void paintComponent(Graphics g) {
// super.paintComponent(g); // senza ricostruzione dello sfondo: non aggiorna
g.setColor(Color.red);
g.fillOval(x,y,20,20);
}
private class MiaClasseAscoltoMouse extends MouseAdapter { // classe interna
public void mousePressed (MouseEvent e) {
x = e.getX();
// accede alla variabili istanza x e y della classe
y = e.getY();
repaint();
}
}
public static void main(String[] args) {
new Pallini();
}
}// fine applicazione Pallini
Eventi di azione
(Interfaces ActionListener, Classes ActionEvent)
Sono generati quando si premono bottoni, si selezionano voci di menù, si preme invio mentre si
scrive in un campo di testo. In awt sono generati da componenti delle classi Button, TextField, List
e MenuItem
Molti controlli Swing oltre a JButton generano eventi che possono essere catturati da un
actionListener cioè sono sorgente di eventi ActionEvent
Eventi di azione sono provocati dall'utente che agisce su un componente (click su un
pulsante); vale per gli oggetti istanza delle classi JButton, JCheckBox, JComboBox,
JRadioButton (controlli derivati da AbstractButton) e JTextField.
I seguenti eventi ad esempio notificano un evento azione:
•
•
•
Quando si premere INVIO in un campo di testo
Quando si seleziona una checkbox, un radiobutton o una voce in un combobox
Quando si seleziona una voce di un menu o si clicca su un bottone
Esempio di struttura di applicazione con gestione eventi generati4 da interazione con interfaccia
grafica:
un pulsante (parte della GUI) è origine dell’evento (di azione)
tutta la classe è ascoltatore dell’evento (di azione)
esiste un solo metodo nell’interfaccia
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class NomeClasse implements ActionListener {
// classe ascoltatore
// con interfaccia per eventi di azione
private JFrame f;
private Container c;
private JPanel p;
private JButton b;
public NomeClasse(){
// costruttore
f = new JFrame ("Cambio di colore");
c = f.getContentPane();
p = new JPanel();
b = new JButton("Premi");
b.addActionListener (this);
// lega la classe di ascolto cioè l’applicazione stessa
// all’origine dell’evento cioè il pulsante
b.setBackground (Color.red);
p.add(b);
c.add(p);
f.setLocation(200,200);
f.setSize(250,70);
f.setBackground(Color.white);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // senza esplicita gestione di eventi di finestra
}
4
Altre applicazioni a eventi in Java: applicazioni embedded basate su interrupt (ad esempio i driver di dispositivo) ed
applicazioni distribuite basate su scambio asincrono di eventi (ad esempio quelle di network management)
// implemento il metodo dell’interfaccia di ascolto
public void actionPerformed (ActionEvent e) { // unico metodo da ridefinire
b.setBackground (Color.cyan);
// cambia colore di sfondo del bottone
}
public static void main (String [] args) {
NomeClasse o = new NomeClasse ();
}
}// fine applicazione
Eventi – metodi utili
Object getSource()
restituisce la componente su cui si è verificato l’evento e si può
scoprire con “instanceof” a quale classe appartiene.
getSelectedObjects()[0]
ritorna array (length 1) con label o null se non selezionato;
usato con operatore di cast (String); in alternativa, per classe
Checkbox, anche getText()
ActionEvent:
String getActionCommand() se l’evento è generato su un TextField restituisce la stringa
contenuta nel TextField in alternativa a getText()
KeyEvent:
char getChar()
char getKeyChar()
int getKeyCode()
restituisce il carattere associato al tasto che ha generato l’evento
restituisce il numero corrispondente (ad esempio il tasto ESC è 27)
MouseEvent:
int getX(), int getY()
restituiscono le coordinate del cursore
Definizione e Registrazione di Listeners
Definizione, due possibilità
•
implementando il Listener
class MyXXXListener implements XXXListener {
// definizione dei metodi definiti da XXXListener
}
•
estendendo l’adapter
class MyXXXListener extends XXXAdapter {
// override i metodi definiti da XXXAdapter
}
Registrazione:
•
•
ogni event source ha un metodo per registrare un corrispondente listener
addXXXListener (XXXListener listenerObject)
È possibile installare uno stesso ascoltatore, ad esempio, per diversi bottoni di una toolbar  il
vantaggio risiede nel fatto che i diversi bottoni hanno lo stesso ascoltatore (invece che più
ascoltatori separati che fanno la stessa cosa)
Esercizio: pulsanti con stessa classe di ascolto e stesso metodo actionPerformed()
// esempio di Applet con gestione eventi della GUI
// Uso di due pulsanti
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.applet.*;
public class Pulsanti extends JApplet {
JTextField T = new JTextField (30);
JButton B1 = new JButton("sinistro");
JButton B2 = new JButton("destro");
JFrame f1 = new JFrame("Pulsanti");
public void init() {
f1.setSize (400, 200);
f1.setLocation (50,50);
f1.setResizable(true); // con mouse ridimensionabile
f1.setLayout(new GridLayout (1,3,50,0));
Container c = f1.getContentPane(); // recupera il "muro grezzo"
B1.addActionListener (new Ascolta());
B2.addActionListener (new Ascolta());
c.add(B1);
c.add(T);
c.add(B2);
f1.setVisible(true);
}
private class Ascolta implements ActionListener {
public void actionPerformed (ActionEvent e) {
String Bottone = e.getActionCommand(); // testo mostrato da pulsante
if (Bottone.equals ("sinistro") )
T.setText("pulsante sinistro");
else
T.setText("pulsante destro");
}
}
} // fine applet
Problema: scrivere un ascoltatore (listener) che alla pressione di bottoni diversi mostri il contenuto
della JTextField inserita nella finestra istanza dell'applicazione MyFrame
→ L’ascoltatore deve aver accesso al riferimento a quel JTextField di quella particolare istanza
Prima soluzione: si può utilizzare una classe interna come ActionListener
Tecnica accettabile se l’ascoltatore “fà poco” altrimenti la classe cresce sensibilmente in dimensioni
Svantaggio: si accorpano due classi che rappresentano due aspetti concettualmente diversi
Seconda soluzione: si può progettare l’ascoltatore prevedendo un costruttore che prende in
ingresso il riferimento alla finestra contenente il bottone. La classe resta esterna ma può accedere a
tutti gli oggetti della finestra (a patto che questi non siano privati)
Un Listener per N Controlli
Primo caso: uso classe Listener interna cioè innestata non statica
public class MyFrame extends JFrame {
// ….....
JButton up= new JButton(“Up”);
JButton down= new JButton(“Down”);
JButton random= new JButton(“Random”);
Listener ascoltatore = new Listener();
public MyFrame() { ...
up.addActionListener(ascoltatore);
down.addActionListener(ascoltatore);
random.addActionListener(ascoltatore);
// ….......
// componenti attivi della stessa natura
}
private class Listener implements ActionListener {
// classe interna
public void actionPerformed (ActionEvent e) {
Object src = e.getSource();
// si individua l’oggetto mittente della segnalazione
if (src == up) { codice associato alla pressione del bottone Up }
else if (src == down) { codice associato alla pressione del bottone Down }
else if (src == random) { codice associato alla pressione del bottone Random }
}
}
}
Se i componenti sono di diversa natura, ad esempio un pulsante ed un campo di testo, entrambi in
grado di generare un evento “di azione”, il seguente codice può essere utile ad intercettare il
mittente della segnalazione :
public void actionPerformed (ActionEvent evt){
Object src = evt.getSource();
// si individua il mittente della segnalazione
if (src instanceof JTextField) funzioneCampoDiTesto(); // scelta del giusto gestore dell'evento
else if (src instanceof JButton) funzionePulsante();
}
Quando si usano classi esterne, è possibile “capire” il componente che ha notificato l’evento
associando ai diversi componenti un diverso valore della proprietà actionCommand
nb:
but[i]=new JButton (mess[i]);
but[i].setToolTipText (mtool[i]);
but[i].setActionCommand (mtool[i] ); // per modificare la stringa identificativa dell’oggetto
// registrato (associato) al gestore d’evento
e.getActionCommand () ritorna String  default l’etichetta associata al bottone (mess[i])
Secondo caso: classe Listener esterna.
Nell’esempio seguente i possibili diversi valori della proprietà actionCommand sono memorizzati
come costanti della classe ascoltatore Listener esterna
public class MyFrame extends JFrame {
// …........
JButton up= new JButton(“Up”);
JButton down= new JButton(“Down”);
JButton random= new JButton(“Random”);
Listener ascolt = new Listener();
public MyFrame() {
// …......
up.addActionListener(ascolt);
up.setActionCommand(ascolt.UPOPT);
down.addActionListener(ascolt);
down.setActionCommand(ascolt.DOWNOPT);
random.addActionListener(ascolt);
random.setAction Command(ascolt.RANDOMOPT);
// …......
}
}
// classe esterna
public class Listener implements ActionListener {
public final static String UPOPT = “Up”;
// costanti
public final static String DOWNOPT = “Down”;
public final static String RANDOMOPT = “Random”;
public void actionPerformed(ActionEvent e) {
String com = e.getActionCommand();
// recupero della stringa-etichetta associata al bottone
if (com == UPOPT)
upOpt();
else if (com == DOWNOPT)
downOpt();
else if (com == RANDOMOPT)
randomOpt();
}
private void upOpt() { ... }
private void randomOpt(){ ... }
private void downOpt(){ ... }
}
Confronto soluzioni:
In senso assoluto, le prestazioni migliori si ottengono usando l'implementazione diretta
dell'interfaccia-ascoltatore, poiché non sono generate né classi né oggetti ulteriori, rispetto all'unica
concretizzazione del Tipo ascoltatore.
Le classi interne hanno il pregio di consentire una migliore gestione della struttura interna
dell'oggetto (comportamenti adatti in ambito OO), appesantendo il caricamento dell'applicazione di
quel (tanto o poco) necessario al ClassLoader per caricare e risolvere un certo numero di classi in
più, rispetto alla soluzione dell'implementazione diretta.
Quale che sia la scelta adottata, ciò che importa è la consapevolezza degli effetti.
Esercizi non risolti
Esercizio (non risolto): realizzare un'applicazione grafica con dimensione della finestra 200x200
pixel come da layout in Fig.1
Fig. 1: GUI da progettare
Fig. 2: Effetto che si vuole
premendo il pulsante Red
Alla pressione di ogni pulsante si vuole che lo sfondo cambi colore come da Fig.2
Esercizio (non risolto): realizzare un'applet EuroConvertitore implementando sia TextListener sia
FocusListener
Esercizio: progettare un pannello che sia maschera di input che consenta all’utente di :
•
•
•
inserire articoli (e relativo prezzo), sia in lire che in euro
avere sempre sott’occhio il totale, sia in lire che in euro
poter salvare su file, in qualunque momento, l’elenco degli ordini inseriti.
Di seguito realizzare l'applicazione di test che crea una finestra di dimensioni 300x300 pixel e permette di visualizzare
tale maschera col layout di figura
Esercizio: prenotazione di biglietto di sola andata
per una data destinazione con soluzione online
Progetto con array (senza soluzione)
Progettare un’applicazione in Java che presenti
all’utente una finestra (simile a quella in figura)
con la possibilità di gestire un array di interi;
la pressione di ogni bottone determinerà una
delle seguenti elaborazioni:
Reset
Riempimento con valori generati casualmente e visualizzazione nell’area di testo sulla destra
Riempimento con valori decrescenti
Ricerca del valore massimo scritto a fondo pagina
Ordinamento non decrescente (Sort)
Ricerca del valor medio scritto a fondo pagina
Ricerca della prima occorrenza di un numero digitato da Dialog box con scrittura a fondo pagina della
posizione o messaggio di avviso dell’esito negativo su Dialog box
Visualizzazione dei valori originari
Lettura da file di testo con Scanner, visualizzazione in area di testo, salvataggio di modifiche
// lettura da file con visualizzazione in area di testo
// modifica del testo
// salvataggio su file del contenuto dell'area di testo
import java.io.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class GUI {
private JTextArea ta = new JTextArea();
private String sl;
public void leggiFile() {
// LETTURA da file di testo
try {
FileReader fr = new FileReader("FileIni.txt");
Scanner sc = new Scanner(fr);
while(sc.hasNext()) {
ta.append(sc.nextLine());
ta.append("\n");
}
fr.close();
// chiusura File
} catch (IOException e) {}
}
public void scriviFile() {
// SCRITTURA su file di testo
try {
FileWriter fw = new FileWriter("FileOut.txt");
PrintWriter out = new PrintWriter(fw);
sl = ta.getText();
out.print(sl);
fw.close();
// chiusura File
} catch (IOException e) {}
// salva in String tutto il testo
}
public void visualizza(){
JFrame f = new JFrame("Finestra con area di testo");
Container c = f.getContentPane();
JPanel p = new JPanel();
JButton b1 = new JButton ("salva");
JButton b2 = new JButton ("cancella");
b1.addActionListener (new mioAscoltatore());
b2.addActionListener (new mioAscoltatore());
p.add (b1);
p.add (b2);
p.setPreferredSize(new Dimension(180, 35));
ta.setEditable (true);
JScrollPane listPane = new JScrollPane(ta);
listPane.setPreferredSize(new Dimension(180, 120));
c.setLayout(new FlowLayout());
c.setPreferredSize(new Dimension(280, 180));
c.add(p);
c.add(listPane);
f.pack();
f.setVisible(true);
}
// gestione eventi di azione
//Layout the content pane
// classe interna
class mioAscoltatore implements ActionListener {
public void actionPerformed (ActionEvent ev) {
String Bottone = ev.getActionCommand();
if (Bottone.equals ("salva") )
scriviFile();
else if (Bottone.equals ("cancella") )
ta.setText ("");
}
// testo mostrato da pulsante
}
} // fine class GUI
public class EsempioEventi {
public static void main(String[] args) {
GUI o = new GUI();
o.leggiFile();
o.visualizza();
}
} // fine applicazione che usa class GUI
Effetto alla pressione del bottone “cancella”:
Effetto di modifiche (uso Ctr C e Ctr V per copia/incolla):
Effetto alla pressione del bottone “salva” :
salvataggio su file di testo FileOut.txt
Testo : pagina iniziale
Modifica Modifica Modifica
Modifica Modifica Modifica
Modifica Modifica Modifica
Modifica Modifica Modifica
Modifica Modifica Modifica
Attività: migliorare il progetto prevedendo uso di dialog box
per scegliere il nome del file
Gestione Thread : scritta scorrevole che si modifica da campo di testo
Esercizio: realizzare un’applicazione con una scritta scorrevole che si modifica da campo di testo
con uso di contenitori/componenti Swing evitando sfarfallio.
Possibile soluzione: si possono inserire due PANNELLI (in un Container impilando in verticale); il
secondo per disegnare con interfaccia Runnable; gestione di evento di azione con interfaccia tipo
ActionListener associata al campo di testo (alla pressione di INVIO) per cancellare il testo stesso. Nella
colonna di destra le modifiche per gestire la possibilità che la scritta scorra per tutta la larghezza della
cornice anche se l'utente ridimensiona la finestra.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestoS implements ActionListener {
private String nome;
private JTextField t;
private MioPanel disegno;
private JPanel p;
private JFrame f ;
private Container c;
private JLabel l;
public TestoS() {
// costruttore
nome = "a tutti";
f = new JFrame ("Saluto");
c = f.getContentPane();
c.setLayout (new BoxLayout (c, BoxLayout.PAGE_AXIS));
// impila gli elementi in verticale
// nel Container
p = new JPanel();
l = new JLabel ("Digita il tuo nome");
t = new JTextField(nome, 10);
t.setForeground(Color.red);
// testo rosso
t.setBackground(Color.lightGray); // sfondo grigio chiaro per la casella di testo
t.addActionListener(this);
disegno = new MioPanel(t);
p.add(l);
p.add(t);
c.add(p);
c.add(disegno);
f.setSize(200,200);
// con f.pack() bisogna ingrandire la finestra per vedere il “disegno”
f.setLocation(0,0);
// se non se ne impostano le dimensioni
f.setResizable(false);
f.setResizable(true);
f.setVisible(true);
Thread runner = new Thread (disegno);
runner.start();
// richiama il metodo run() del “thread” disegno
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
t.setText("");
// alla pressione di INVIO
}
public static void main(String [] args) {
new TestoS();
}
} // fine applicazione TestoS
// classe esterna
class MioPanel extends JPanel implements Runnable {
private String nome;
private JTextField testo;
private int Xpos;
private String nome;
private JTextField testo;
private int Xpos;
public MioPanel (JTextField t) {
testo = t;
setForeground(Color.black); // scrive in nero
}
public MioPanel (JTextField t) {
testo = t;
setForeground(Color.black);
// scrive in nero
}
// larghezza scelta come
// massimo valore x nello spostamento [*]
public void run () {
while (true) {
for (Xpos =0; Xpos<getWidth(); Xpos++) {
// metodo obbligatorio per eseguire il thread
public void run () {
while (true) {
for (Xpos =0; Xpos<150; Xpos++) {
repaint();
try{
Thread.sleep(80);
}catch(InterruptedException ie) { return;}
}
repaint();
try{
Thread.sleep(80);
}catch(InterruptedException ie) {return;}
}
}
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
nome = testo.getText();
g.drawString("Ciao " + nome, Xpos, 50); // scelta dell'ordinata in modo da vedere meglio la scritta
}
}
All'inizio la scritta è Ciao a tutti
nb: l'uso di una tela (oggetto di classe che estende Canvas) disegnando con metodo paint() causa maggior
effetto "flicker" o sfarfallio.
Confronto: scritta scorrevole che si modifica da campo di testo (unico thread associato al main)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SenzaThread implements ActionListener {
private String nome;
private JTextField t;
private MioPanel disegno;
private JPanel p;
private JFrame f ;
private Container c;
private JLabel l;
public SenzaThread() {
// costruttore
nome = "a tutti";
f = new JFrame ("Saluto");
c = f.getContentPane();
c.setLayout (new BoxLayout (c, BoxLayout.PAGE_AXIS)); // impila gli elementi in verticale
p = new JPanel();
l = new JLabel ("Digita il tuo nome");
t = new JTextField(nome, 10);
t.setForeground(Color.red);
// testo rosso
t.setBackground(Color.lightGray); // sfondo grigio chiaro per la casella di testo
t.addActionListener(this);
disegno = new MioPanel(t);
p.add(l);
p.add(t);
c.add(p);
c.add(disegno);
f.setSize(200,200);
// con fpack bisogna ingrandire la finestra per vedere il "disegno"
f.setLocation(0,0);
// se non se ne impostano le dimensioni
f.setResizable(true);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); // deve essere posta prima del ciclo di disegno
while(true)
disegno.go();
// senza craere thread
}
public void cancellaNome() {
t.setText("");
}
public void actionPerformed(ActionEvent e) {
cancellaNome();
// alla pressione di INVIO
}
public static void main(String [] args) {
new SenzaThread();
}
}
// classe esterna
class MioPanel extends JPanel {
private String nome;
private JTextField testo;
private int Xpos;
public MioPanel (JTextField t) {
testo = t;
}
public void go () {
// servizio richiesto
for (Xpos =0; Xpos<getWidth(); Xpos++) {
// ascissa massima
// in funzione della larghezza del pannello
setForeground(Color.black);
// scrive in nero
repaint();
try{
Thread.sleep(80);
}catch(InterruptedException ie) {return;}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
nome = testo.getText();
g.drawString("Ciao " + nome, Xpos,50);
}
}
// scelta dell'ordinata in modo da vedere meglio la scritta
Esempio d'uso JComboBox, eventi di azione, più pannelli e threads
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Pannelli implements ActionListener {
private JLabel l;
private JComboBox cbx;
private String[] nome = {"produttore", "consumatore"};
private JTextField t;
private MioPanel disegno;
private JPanel p1, p2;
private JFrame f ;
private Container c;
public Pannelli() {
// costruttore
f = new JFrame ("Uso threads");
c = f.getContentPane();
//c.setLayout (new BoxLayout (c, BoxLayout.PAGE_AXIS)); // impila gli elementi in verticale in c
c.setLayout(new GridLayout(3,1)); // unica colonna con stesso effetto
p1 = new JPanel();
p2 = new JPanel();
l = new JLabel ("Scegli");
cbx = new JComboBox();
for (int k = 0; k < nome.length; k++)
cbx.addItem (nome[k]);
cbx.setEditable (false);
cbx.addActionListener (this);
cbx.setForeground(Color.red); // testo rosso
cbx.setBackground(Color.lightGray); // sfondo grigio chiaro per combobox
cbx.setToolTipText("Seleziona una voce");
t = new JTextField (nome[0],7);
t.setEditable (false);
disegno = new MioPanel(t);
p1.add(l);
p1.add(cbx);
p2.add(t);
p2.setBackground(Color.yellow); // per evidenziare le dimensioni del secondo pannello
c.add(p1);
c.add(p2);
c.add(disegno);
f.setSize(200,200);
// con fpack bisogna ingrandire la finestra per vedere "disegno"
f.setLocation(300, 100);
// se non se ne impostano le dimensioni
f.setResizable(false);
f.setVisible(true);
Thread runner = new Thread (disegno);
runner.start();
// richiama il metodo run() del “thread” disegno
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
t.setText ("" +((JComboBox) e.getSource()).getSelectedItem()); // alla pressione di INVIO
}
public static void main(String [] args) {
new Pannelli();
}
}
// classe esterna
class MioPanel extends JPanel implements Runnable{
private String nome;
private JTextField testo;
private int Xpos;
public MioPanel (JTextField t) {
testo = t;
setForeground(Color.black);
}
// scrive in nero
public void run () {
// metodo obbligatorio per eseguire thread
while (true) {
for (Xpos =0; Xpos<getWidth(); Xpos++) {
// ascissa massima
// in funzione della larghezza del pannello
repaint();
try{
Thread.sleep(80);
}catch(InterruptedException ie) {return;}
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int raggio = 50;
nome = testo.getText();
g.setColor(Color.blue);
g.drawString(nome, Xpos,50);
if (nome.equals ("produttore")){
g.setColor(Color.red);
g.fillOval(Xpos,5,raggio/2,raggio/2);
}
}
}
// x,y dell'angolo in alto a sinistra,
// larghezza, altezza
JTextField e documento: eventi swing
Associato ad ogni campo di testo c’è un documento che gestisce il testo presente e ad ogni modifica del
contenuto questo documento genera un DocumentEvent per segnalare l'avvenuto cambiamento.Tale evento
dev'essere gestito da un opportuno DocumentListener
L'interfaccia DocumentListener dichiara tre metodi:
void insertUpdate(DocumentEvent e);
void removeUpdate(DocumentEvent e);
void changedUpdate(DocumentEvent e);
• Il terzo non è mai chiamato da un JtextField, serve solo per altri tipi di componenti
• L'oggetto DocumentEvent passato come parametro non ha nessuna utilità nel nostro esempio.
Nel nostro caso l'azione da svolgere in caso di inserimento o rimozione di caratteri è identica, quindi i due
metodi
void insertUpdate(DocumentEvent e);
void removeUpdate(DocumentEvent e);
saranno identici (purtroppo vanno comunque implementati entrambi)
Anche metodo il changedUpdate(DocumentEvent e) è inutile, dato che JTextField non lo chiama ma va
comunque formalmente implementato.
import javax.swing.event.*;
import java.awt.*;
import javax.swing.*;
class Es12Panel extends JPanel implements DocumentListener{
JTextField txt1, txt2;
public Es12Panel(){
super();
txt1 = new JTextField("Scrivere qui il testo", 25);
txt2 = new JTextField(25); txt2.setEditable(false);
txt1.getDocument().addDocumentListener(this); // ricava il documento di cui il campo di testo txt1 fa parte, e gli
// associa come listener il pannello
add(txt1);
add(txt2);
}
public void insertUpdate(DocumentEvent e){
txt2.setText(txt1.getText());
}
public void removeUpdate(DocumentEvent e){
txt2.setText(txt1.getText());
}
public void changedUpdate(DocumentEvent e){ }
}
public class DocumentP{
public static void main(String [] args){
JFrame f = new JFrame ("Testo");
Container c = f.getContentPane();
Es12Panel guiP = new Es12Panel();
guiP.setBackground(Color. lightGray);
// sfondo del pannello colorato
c.add(guiP);
// aggiunge il pannello
f.setSize(300,100);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
}
ADT
JList (da Tutorial Sun)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ListDemo extends JPanel implements ListSelectionListener {
private JList list;
private DefaultListModel listModel; // in javax.swing
private static final String hireString = "Hire";
private static final String fireString = "Fire";
private JButton fireButton;
private JTextField employeeName;
public ListDemo() {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("Debbie Scott");
listModel.addElement("Scott Hommel");
listModel.addElement("Sharon Zakhour");
//Create the list and put it in a scroll pane.
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setSelectedIndex(0);
list.addListSelectionListener(this);
list.setVisibleRowCount(5);
JScrollPane listScrollPane = new JScrollPane(list);
JButton hireButton = new JButton(hireString);
HireListener hireListener = new HireListener(hireButton);
hireButton.setActionCommand(hireString);
hireButton.addActionListener(hireListener);
hireButton.setEnabled(false);
fireButton = new JButton(fireString);
fireButton.setActionCommand(fireString);
fireButton.addActionListener(new FireListener());
employeeName = new JTextField(10);
employeeName.addActionListener(hireListener);
employeeName.getDocument().addDocumentListener(hireListener);
String name = listModel.getElementAt( list.getSelectedIndex()).toString();
//Create a panel that uses BoxLayout.
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.add(fireButton);
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(new JSeparator(SwingConstants.VERTICAL));
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(employeeName);
buttonPane.add(hireButton);
buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
add(listScrollPane, BorderLayout.CENTER);
add(buttonPane, BorderLayout.PAGE_END);
}
class FireListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//This method can be called only if there's a valid selection
//so go ahead and remove whatever's selected.
int index = list.getSelectedIndex();
listModel.remove(index);
int size = listModel.getSize();
if (size == 0) {
fireButton.setEnabled(false);
//Nobody's left, disable firing.
} else {
if (index == listModel.getSize()) {
//Select an index.
//removed item in last position
index--;
}
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
}
}
}
//This listener is shared by the text field and the hire button.
class HireListener implements ActionListener, DocumentListener {
private boolean alreadyEnabled = false;
private JButton button;
public HireListener(JButton button) {
this.button = button;
}
//Required by ActionListener
public void actionPerformed(ActionEvent e) {
String name = employeeName.getText();
//User didn't type in a unique name...
if (name.equals("") || alreadyInList(name)) {
Toolkit.getDefaultToolkit().beep();
employeeName.requestFocusInWindow();
employeeName.selectAll();
return;
}
int index = list.getSelectedIndex(); //get selected index
if (index == -1) { //no selection, so insert at beginning
index = 0;
} else {
//add after the selected item
index++;
}
listModel.insertElementAt(employeeName.getText(), index);
//If we just wanted to add to the end, we'd do this:
//listModel.addElement(employeeName.getText());
//Reset the text field.
employeeName.requestFocusInWindow();
employeeName.setText("");
//Select the new item and make it visible.
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
}
//This method tests for string equality. You could certainly
//get more sophisticated about the algorithm. For example,
//you might want to ignore white space and capitalization.
protected boolean alreadyInList(String name) {
return listModel.contains(name);
}
//Required by DocumentListener
public void insertUpdate(DocumentEvent e) {
enableButton();
}
//Required by DocumentListener.
public void removeUpdate(DocumentEvent e) {
handleEmptyTextField(e);
}
//Required by DocumentListener.
public void changedUpdate(DocumentEvent e) {
if (!handleEmptyTextField(e)) {
enableButton();
}
}
private void enableButton() {
if (!alreadyEnabled) {
button.setEnabled(true);
}
}
private boolean handleEmptyTextField(DocumentEvent e) {
if (e.getDocument().getLength() <= 0) {
button.setEnabled(false);
alreadyEnabled = false;
return true;
}
return false;
}
}
//This method is required by ListSelectionListener.
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
if (list.getSelectedIndex() == -1) {
//No selection, disable fire button.
fireButton.setEnabled(false);
} else {
//Selection, enable the fire button.
fireButton.setEnabled(true);
}
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("ListDemo");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new ListDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Inserimento: automaticamente ordinato
Cancellazione della voce selezionata:
prima…
dopo ….
Esercizio: Disegno di un auto in altra finestra alla pressione di un pulsante (evento della GUI)
Con codice HTML:
<html>
<head>
<title>Disegno di un Auto come evento </title>
</head>
<body>
<object code ="Autoe.class" width = "350" height ="70" >
</object>
</body>
</html>
// Applet Autoe.java
// esempio di Applet con gestione eventi della GUI: creazione di eventi personalizzati
// Uso canvas
import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Autoe extends JApplet {
Auto A;
public void init() {
JButton B = new JButton ("Disegna un auto");
GestiscePulsante A1 = new GestiscePulsante(); // crea ascoltatore
B.addActionListener (A1);
// lega la classe di ascolto all’origine dell’evento: cioè
// il pulsante B
add(B);
}
public void Disegna() {
JFrame f1 = new JFrame("Disegna auto");
A = new Auto();
f1.setSize (300, 200);
f1.setLocation (50,50);
f1.setResizable(true); // con mouse ridimensionabile
Container c = f1.getContentPane(); // recupera il "muro grezzo"
c.add(A);
f1.setVisible(true);
}
// definizione classe d'ascolto interna cioè innestata non statica
private class GestiscePulsante implements ActionListener{ // interfaccia per eventi di azione
public void actionPerformed (ActionEvent e) { // unico metodo da ridefinire
Disegna();
}
}
}
// fine classe d'ascolto
class Auto extends Canvas {
// classe esterna per disegnare auto
public void paint(Graphics g) {
Font f = new Font("Times Roman", Font.BOLD, 20);
// tipo, aspetto, dimensione carattere
g.setFont(f);
g.fillOval(120, 220, 60,60); // una ruota piena
g.fillOval(320, 220, 60,60); // altra ruota piena
g.setColor(Color.blue);
// carrozzeria blu
g.drawRect(50, 150, 400, 70);
g.drawLine(170,150,200,100);
g.drawLine(330,150,300,100);
g.drawLine(300,100,200,100);
g.setColor(Color.yellow);
// luci gialle
g.fillRect(50, 170, 20, 30);
g.setColor(Color.red);
// luci rosse
g.fillRect(430, 150, 20, 20);
g.setColor(Color.cyan);
// testo cyan
g.drawString("Automobile", 200, 350);
}
}
Classi innestate e interne: definizione
Una classe innestata non è altro che una classe che viene definita all’interno di un’altra classe.
Il vantaggio di implementare una classe all’interno di un’altra, riguarda principalmente il risparmio di
codice. Infatti, la classe innestata ha accesso alle variabili di istanza della classe in cui è innestata.
N.B. : se compiliamo una classe che contiene una classe innestata, saranno creati due file:
"nomeClasseEsterna.class" e "nomeClasseEsterna$nomeClasseinnestata.class".
N.B. : fino alla versione 1.3 di Java, il termine “classe innestata” non era stato ancora adottato. Si parlava
invece di “classe interna” (“inner class”).
Dalla versione 1.4 in poi, la Sun ha deciso di sostituire il termine “classe interna”, con il termine “classe
innestata” o classe annidata (“nested class”). Il termine “classe interna” deve ora essere utilizzato solo per
le classi innestate che non sono dichiarate statiche. In realtà la stragrande maggior parte delle volte si
utilizzano classi interne.
Leggere testo di input con applicazioni GUI e il package swing
Esempio di Applet che usa una semplice finestra modale:
// da eseguire con appletviewer da linea di comando > appletviewer Finestre.html
// oppure con opportune selezioni nel Plug-in (da Pannello di controllo)
// oppure in ambiente JCreator
import javax.swing.*;
import java.awt.*;
import java.applet.*;
public class Finestre extends JApplet {
String nome="";
public void init () {
nome = JOptionPane.showInputDialog("Inserisci il tuo nome: ");
}
public void paint(Graphics g) {
g.drawString("Ciao " + nome, 10, 50);
}
}
Con codice HTML (file Finestre.html ):
<html>
<head>
<title>Dialog box per input </title>
</head>
<body>
<object code ="Finestre.class" width = "300" height = "100">
</object>
</body>
</html>
nb: per eseguire la pagina html con programma appletviewer, inserito come tools in JCreator,
impostare come opzioni:
Per scoprire le potenzialità di swing5 eseguire la demo in file compresso seguendo percorso
C:\Programmi\Java\jdk1.6.0_21\demo\jfc\SwingSet2\SwingSet2.jar
o lanciare Launch SwingSet3 (richiede Java 6)
5
SWING http://java.sun.com/docs/books/tutorial/uiswing/index.html
Esempio senza apparente gestione di eventi
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class AppIcone extends JFrame {
private JButton btnIcone;
private JLabel testo;
private Icon[] figure = { new ImageIcon ("../src/IMG/Inverno.gif"),
new ImageIcon ("../src/IMG/Estate.gif"),
new ImageIcon ("../src/IMG/Ninfee.gif") };
// percorso relativo alla sottocartella classes in cui è memorizzato il bytecode
// se nella stessa cartella ./nomeImage
public AppIcone () {
Container cnt = getContentPane(); // di default con gestore di layout tipo BorderLayout
btnIcone = new JButton (figure[1]);
// immagine se il mouse è al di fuori della finestra
// di default setRolloverEnabled (true)
// abilitazione del riconoscimento del trascinamento del mouse (roll over)
btnIcone.setRolloverIcon (figure[0]); // definizione dell’icona da usare durante lo scorrimento del mouse
btnIcone.setPressedIcon (figure[2]); // definizione dell’icona da usare a seguito di click sul mouse
btnIcone.setToolTipText ("Spendido inverno! Premi per vedere ninfee! ");
cnt.add (btnIcone, BorderLayout.CENTER);
testo = new JLabel("Effetto Roll-Over");
cnt.add (testo, BorderLayout.PAGE_END);
pack();
setVisible (true);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main(String args []){
AppIcone o = new AppIcone();
}
}
nb: salvando in stessa cartella il sorgente e la sottocartella che contiene le immagini IMG
Uso componente JColorChooser per visualizzare in finestra modale palette di colori
import javax.swing.*;
import java.awt.*; // per Color
class SceltaColore extends JFrame {
public void visualizza(){
JColorChooser c = new JColorChooser();
c.showDialog(this,"Palette", Color.white);
// visualizza finestra modale
pack();
setVisible(true);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main (String arg[]){
SceltaColore o = new SceltaColore();
o.visualizza();
}// fine main
}// fine classe
JFileChooser per visualizzare finestre modali per aprire e salvare file
class ScelteFile extends JFrame {
public void visualizza(){
JFileChooser fc = new JFileChooser();
fc.showOpenDialog(this); // apre finestra modale ... visualizza un JFileChooser per apertura file.
fc.showSaveDialog(null); // apre finestra modale ... visualizza un JFileChooser per salvataggio file.
pack();
setVisible(true);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main (String arg[]){
ScelteFile o = new ScelteFile0();
o.visualizza();
}// fine main
}// fine classe
APPENDICE: APPLET
Java si è diffuso storicamente, e trae forza, dal concetto di applet6 come piccola (almeno all’inizio
dei tempi) applicazione da eseguirsi dentro un browser Internet
· grafica portabile ed eseguibile ovunque
· modello di sicurezza “sandbox”
Una applet ("applicazioncina") è una applicazione non autonoma, ma pensata per far parte di una
pagina Internet
· porta dinamicità alle pagine HTML "statiche"
· viene eseguita dal browser, che quindi deve incorporare un interprete Java
e questo può causare un tempo di visualizzazione più alto
In quanto applicazione non autonoma, un'applet:
· non ha un main, perché la sua vita è dipendente dalla pagina in cui è visualizzata, eredita dalla
superclasse ed è public.
· non deve creare un frame principale, perché usa la finestra del browser che la ospita (in effetti,
Applet deriva direttamente da Panel e quindi è essa stessa un pannello)
· è organizzata intorno a 4 metodi standard:
· init(), che gioca il ruolo del costruttore
· start() e stop(), chiamati dal browser ogni volta che occorre avviare /fermare l'applet
· destroy(), invocato quando il browser viene chiuso.
Diagramma degli stati di un’applet
Esistono due versioni di Applet:
· la classe Applet dell'AWT standard (da Java 1.0 in poi)
· la classe JApplet di Swing (da Java 1.1.6 in poi)
Se si usano componenti Swing, occorre necessariamente usare JApplet infatti una Applet con
componenti Swing non viene disegnata correttamente
6
Da http://www33.brinkster.com/4binf/dispense/java/JavaApplet.pdf
// AppletSaluto.java
import java.awt.Graphics;
// importa solo la necessaria classe Graphics definita all’interno del package
// che implementa l’Interfaccia Utente detta Abstract Windowing Toolkit
public class AppletSaluto extends java.applet.Applet
{
// AppletSaluto è sottoclasse di Applet
public void paint(Graphics g) {
g.drawString("Ciao alla citta’!", 5, 25); // coordinate dell’angolo in basso
}
// a sinistra del testo
}
Con file HTML che fa riferimento al file bytecode dell’applet:
<object code="AppletSaluto.class" width="195"height="38"> </object>
Si ottiene il seguente effetto con uso di BROWSER (Internet Explorer recenti o FireFox Mozilla)
Ciao alla citta '!
cioè una scritta nella finestra del browser
(5, 25)
// SecondoApplet.java con passaggio di parametri
import java.awt.*;
import java.applet.*;
public class SecondoApplet extends Applet {
public void paint(Graphics g) {
String nome = getParameter ("Nome");
g.drawString("Ciao " + nome, 0, 50);
}
}
Con file HTML
<html>
<head><title> Saluto personalizzato</title></head>
<body>
<object code="SecondoApplet.class" width="195"height="38">
<param name="Nome" value="Nome_proprio">
</object>
</body>
</html>
Si ottiene il seguente effetto con uso di
BROWSER (Internet Explorer):
Ciao Nome_proprio
cioè un saluto personalizzato
nella finestra del browser
// esempio di applet con descrizione degli Stati (ridefinizione di metodi originali)
// da lanciare con appletviewer da linea di comando > appletviewer Stati.html oppure da browser7
// Notare l’assenza del metodo main() infatti definiamo Stati come sottoclasse di Applet che viene
// usata dalla classe principale predefinita AppletViewer al momento dell’esecuzione
// oppure dalla JVM integrata nel browser
import java.applet.*;
public class Stati extends Applet {
public Stati ()
{
// Stati è sottoclasse di Applet con costruttore Applet()
// costruttore
System.out.println("Invocato il costruttore di stati");
}
public void init ()
{
// richiamato unica volta: quando carica l'Applet
// cioè quando il browser lo preleva dal Web Server
super.init(); // metodo originale
System.out.println("Eseguito init()");
}
public void start () {
// richiamato ogni volta che si accede a pagina web
// invoca metodo paint(..)
super.start(); // metodo originale
System.out.println("Eseguito start()");
}
public void stop () {
// richiamato ogni volta che si esce da pagina web
// sia finestra iconizzata, sia non in primo piano
super.stop(); // metodo originale
System.out.println("Eseguito stop()");
}
public void destroy () {
// richiamato quando si esce dall'appletviewer o da browser
super.destroy(); // metodo originale
System.out.println("Eseguito destroy()");
}
}
Codice HTML salvato nel file Stati .html:
<html>
<head><title>Stati di un Applet </title></head>
<body>Lancia con appletviewer da linea di comando <P> &gt appletviewer Stati.html
<P><object code ="Stati.class" width = 10 height = 10 ></object>
<br>oppure seleziona da barra delle applicazioni: <em> Apri console</em>
</body>
</html>
7
Lanciando da browser aprire visualizzazione console (simbolo Plug-in Java che compare nella barra di sistema)
NB: da pannello di controllo (Java Plug-in) si deve scegliere l’opzione “Mostra Java nella barra di sistema” e
selezionare i browser in cui usare Java™ Plug-in come runtime Java predefinito
APPLET e SICUREZZA
Un'applet non può fare tutto quello che fa una applicazione. Poiché può essere scaricata dalla rete,
sarebbe troppo pericoloso permettere a un'applet di fare qualunque cosa ed è costretta a rispettare
un ben preciso modello di sicurezza ("sandbox")
– è eseguita in una "scatola" da cui non può uscire
– non può contaminare (o spiare) i dati del computer dell'utente
Un'applet di norma non può:
• accedere al file system locale (neppure per leggere un file)
• eseguire un altro programma
• ottenere informazioni sull'utente
• connettersi via rete a un computer diverso da quello da cui è stata scaricata8
• caricare la libreria Java, chiamare System.exit()
In molte situazioni, questi vincoli sono troppo rigidi e rischierebbero di rendere impossibile la
costruzioni di applet utili.
APPLET FIRMATE
Attraverso tecnologie di cifratura, un'applet può essere firmata, ossia a essa può essere allegato un
certificato che ne garantisce l'origine. A tali applet firmate, cui si attribuisce maggiore fiducia,
l'utente può consentire di svolgere alcune o tutte le operazioni sottoposte a vincolo.
Ogni browser può essere configurato per gestire le applet firmate.
POLITICHE DI SICUREZZA
A partire da Java 2, l'utente può decidere caso per caso quali politiche di sicurezza applicare, con
una granularità molto fine
Esiste il concetto di policy file, che elenca le politiche locali e si può stabilire che una certa applet,
proveniente da un ben preciso sito, ha diritti particolari. Un tale file può essere fornito da chi
sviluppa l'applet, o modificato dall'utente con lo strumento PolicyTool.
8
Per questo motivo si preferisce lavorare con applicazioni quando ci si connette a Internet e se ne usano le risorse.
Graphics
Un oggetto di tipo Graphics rappresenta essenzialmente una porzione di schermo in cui è possibile mostrare
testi, immagini, forme, in modo indipendente dalla piattaforma
Per disegnare su un oggetto GUI (di tipo contenitore), dobbiamo chiamare opportuni metodi sull’oggetto
Graphics dello stesso.
Esistono due modi:
•
•
ottenere l’oggetto Graphics con oggettoGUI.getGraphics()
modificare il metodo di disegno del contenitore cioè estendere la classe ereditando
da una classe Frame o Container o Panel (package awt) o JPanel (swing)
Non solo l'applet ha il metodo paint che può essere ridefinito, ma anche gli oggetti di tipo Component,
ovvero tutti i componenti GUI (del package awt)9, quindi per cambiare l'aspetto grafico di un qualsiasi
componente grafico basta ridefinirne10 il metodo paint.
Tra tutti i Component c'è la tela su cui è possibile disegnare, essa è un oggetto della classe Canvas.
Chi è abituato a programmare con altri linguaggi si aspetterà che nel metodo paint ci sia un’ inizializzazione
del device su cui si va a disegnare e poi una serie di istruzioni tipo drawLine, drawBox eccetera [ 1], ma
questo non è del tutto vero, ovvero nei Component e nelle applet non c'è nessun metodo grafico.
Il parametro g di tipo Graphics del metodo paint o paintComponent, infatti, contiene i metodi grafici usabili
da Java e rappresenta in qualche modo l'area (contesto grafico) in cui verranno disegnate le varie primitive.
I metodi paint (Graphics g) e paintComponent(Graphics g) non possono essere invocati direttamente.
Per disegnare un oggetto di tipo Graphics utilizzando ad esempio il metodo paint( ) della classe Component,
passando come parametro il contesto grafico di tipo Graphics, si crea una classe che estende il Frame dentro
il quale si vuole disegnare:
import java.awt.Frame;
import java.awt.Graphics;
public class SimpleGrafica extends Frame {
public void paint (Graphics g) {
g.drawRect(10, 10, 100, 75); // x, y, larghezza, altezza
}
}
Graphics è una classe che non può essere istanziata: nel metodo paint o paintComponent viene ricevuto
un’oggetto di tale classe come parametro e se ne possono usare i metodi oppure si può recuperare il
contesto grafico (di un contenitore: di tipo Frame o Container o Panel in awt o JPanel in swing) che possiede
tutti i metodi di disegno.
Per ottenere il contesto grafico ad esempio della finestra corrente usando il metodo getGraphics( ):
Graphics g = getGraphics();
nb: usando il metodo getGraphics() sarà necessario richiamare il metodo dispose() per deallocare l’oggetto
quando se ne termina l’uso.
[1] nel disegnare in ambiente Dev-Cpp:
int GraphDriver = DETECT,
GraphMode;
// rileva la più alta risoluzione possible tipicamente
// VGA (640 x 480) ed equivale a GraphDriver=0
// auto-detected cioè GraphMode=0 tipicamente VGAHI
int Xpixel= 640, Ypixel=480;
initgraph (&GraphDriver, &GraphMode, "", Xpixel, Ypixel);
setcolor(CYAN);
9
10
// Start Window con inizializzazione device
// funzione per settare il colore impostato per gli assi
Analogamente per gli oggetti di tipo JComponent (swing) esiste il metodo paintComponent
http://java.sun.com/products/jfc/tsc/articles/painting/index.html
GRAFICA BI-DIMENSIONALE IN JAVA
http://www.disi.unige.it/person/MagilloP/INTERF03/LEZGRAF/grajava.html
Esempio
Pannello con grafica personalizzato: ExDraw1.java.
La funzione paintComponent riempe un rettangolo
sfumato, vi disegna dentro un fumetto con scritto
grande "Ciao!", traccia con tratto spesso tre linee
alla base del fumetto.
Disegno diretto
Metodi per disegnare direttamente una figura. I
parametri sono interi esprimenti numero di pixel,
cioè le primitive vanno fornite direttamente in device space.












clearRect(x,y, width,height): pulisce il rettangolo indicato riempiendolo col colore di sfondo.
void draw/fillRect(x,y, width,height): Disegna rettangolo vuoto o pieno.
void draw/fillRoundRect(x,y, width,height, arcWidth,arcHeight): Disegna
rettangolo con angoli smussati, vuoto o pieno.
void draw/fill3DRect(x,y, width,height, arcWidth,arcHeight): Disegna rettangolo
con effetto di rilievo 3D, vuoto o pieno.
draw/fillOval(x,y, width,height): Disegna ellisse, vuoto o pieno.
draw/fillArc(x,y, width,height, startAngle,arcAngle): Disegna arco circolare o
ellittico, vuoto o pieno. Gli angoli sono in gradi, angolo positivo significa rotazione in senso antiorario,
negativo in senso orario. Centro dell'arco e' il centro del rettangolo di origine (x,y) e dimensioni width, height.
drawLine(x1,y1, x2,y2): Disegna segmento di retta tra (x1,y1) e (x2,y2).
draw/fillPolygon(arrayX, arrayY, n): Disegna poligono con n vertici definiti dai due array di x
e y.
drawPolyline(arrayX, arrayY, n): Disegna spezzata poligonale con n vertici definiti dai due
array di x e y.
drawString(stringa,x,y): Disegna stringa iniziando alle coordinate (x,y). La stringa si estende a
destra di x e sopra y, cioe' nelle ascisse maggiori di x e nelle ordinate MINORI di y.
drawImage(Image, x,y, ImageObserver): Disegna immagine alla posizione (x,y). Come image
observer si passa il componente stesso (this).
drawImage(Image, x,y, width,height, ImageObserver): disegna immagine alla posizione
(x,y), scalata alla larghezza ed altezza indicate.
Esempio per disegnare immagine che occupa tutta la componente:
Dimension d = getSize();
g.drawImage (image, 0,0, d.width,d.height, this);
Tutorial Sun
http://download.oracle.com/javase/tutorial/2d/TOC.html
APPENDICE: Gestione semplificata delle immagini
Le immagini memorizzate in file locali o su Internet possono essere lette in un'applicazione Java e
visualizzate da oggetti Graphics. A partire dal JDK 1.4 la lettura di un'immagine è molto semplice e non
richiede il recupero del "toolkit di default" nè la creazione di un oggetto di tipo MediaTracker per tracciare
le immagini nel componente assegnato né l'attesa se più di un'immagine deve essere caricata prima di poterla
disegnare.
Se l'immagine è memorizzata in un file locale si possono usare le seguenti linee di codice:
String filename= “nome del file comprensivo del percorso”
Image image = ImageIO.read(new File(filename));
In alternativa è possibile indicare un URL:
String urlname= “protocollo completo con nome risorsa”
Image image = ImageIO.read(new URL(urlname));
Se l'immagine non è disponibile, il metodo read genera un'eccezione IOException.
A questo punto la variabile image contiene un riferimento ad un oggetto che incapsula i dati dell'immagine.
È possibile visualizzare l'immagine col metodo drawImage della classe Graphics.
// Disegnare immagini su un pannello
import
import
import
import
import
java.awt.*;
java.awt.image.*;
java.io.*;
javax.imageio.ImageIO;
javax.swing.*;
public class ImmaginePannello extends JPanel{
private BufferedImage image;
// con atenzione alla bufferizzazione
public ImmaginePannello() {
try {
image = ImageIO.read(new File("immagini/verde.gif"));
// cartella immagini in sottocartella con bytecode
} catch (IOException e) {// handle exception. }
}
public void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, null);
}
public static void main(String [] args){
}
}
JFrame f = new JFrame("Visualizzazione Immagini");
ImmaginePannello p = new ImmaginePannello();
f.setContentPane(p);
f.setSize(300,210);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
// Disegnare su un pannello immagini recuperate da Internet
import
import
import
import
import
import
java.awt.*;
java.awt.image.*;
java.io.*;
java.net.URL;
javax.imageio.ImageIO;
javax.swing.*;
public class ImmagineURL extends JPanel{
private BufferedImage image;
public ImmagineURL() {
try {
image = ImageIO.read(new URL
("http://www.disi.unige.it/person/MoggiE/LI03/lez6/images/verde.gif"));
} catch (IOException ex) {
// handle exception
}
}
public void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, null);
}
public static void main(String [] args){
JFrame f = new JFrame("Visualizzazione Immagini");
ImmagineURL p = new ImmagineURL();
f.setContentPane(p);
f.setSize(300,250);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
}
Una galleria di immagini con Java
http://www.mrwebmaster.it/java/articoli/galleria-immagini-java_754.html
/**
* @(#)Immagini.java
*
* Immagini application
* una galleria di immagini con recupero di URL
*
* @author quarte
* @version 1.00 2011/4/9
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*
* la mini gallery necessita di alcune immagini
* salvate nell'omonima cartella con lo stesso percorso dei file .class
*
immagini/rosso.gif
*
immagini/blu.gif
*
immagini/verde.gif
*
immagini/rosa.gif
*
immagini/giallo.gif
*
immagini/azzurro.gif
*
immagini/viola.gif
*/
public class Immagini extends JPanel implements ActionListener {
//definiamone attributi e metodi
JLabel pic;
public Immagini() {
super(new BorderLayout()); // per rendere possibili allineamenti [*]
//definiamo i nomi da associare alle immagini
String[] coloPics = {
"Rosso", "Blu", "Verde", "Rosa", "Giallo", "Azzurro", "Viola" };
//creiamo la lista delle immagini
// si seleziona l'ultima voce
JComboBox coloList = new JcomboBox(coloPics);
coloList.setSelectedIndex(6);
coloList.addActionListener(this);
//definiamo le informazioni relative alle immagini
pic = new JLabel();
pic.setFont(pic.getFont().deriveFont(Font.BOLD));
pic.setHorizontalAlignment(JLabel.LEFT);
// allineamento [*]
updateLabel(coloPics[coloList.getSelectedIndex()]);
pic.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
//impostiamo la dimensione delle immagini
pic.setPreferredSize(new Dimension(200, 110+10));
//settiamo i bordi e i colori.
add(coloList, BorderLayout.PAGE_START);
add(pic, BorderLayout.PAGE_END);
setBorder(BorderFactory.createEmptyBorder(15,15,15,15));
}
// gestione eventi di azione
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox)e.getSource();
String nomePic = (String)cb.getSelectedItem();
updateLabel(nomePic);
}
// recupero immagine con controllo esistenza file
// apertura e lettura del contenuto della cartella
protected void updateLabel(String name) {
ImageIcon icon = createImageIcon("immagini/" + name + ".gif");
pic.setIcon(icon);
pic.setToolTipText("colore: " + name.toLowerCase());
if (icon != null) {
pic.setText(null);
}else{
pic.setText("Impossibile trovare la pagina");
}
}
//notifica nel caso l'immagine non sia nel percorso specificato
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = Immagini.class.getResource(path);
//nomeapplicazione..class.getResource(path)per recuperare l'URL cioè il percorso del file
if (imgURL != null) {
return new ImageIcon(imgURL);
}else{
System.err.println("Impossibile trovare il file: " + path);
return null;
}
}
//creazione dell'interfaccia
private static void InterfacciaGrafica() {
//setaggio della finestra
JFrame frame = new JFrame("MiniGallery");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new Immagini();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//mostriamo la finestra che contiene la GUI
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// creaiamo il visualizzatore e mostriamo la GUI
javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() {
InterfacciaGrafica();}});
}
} // fine applicazione
// in realtà sarebbe sufficiente mostrare la GUI senza creare oggetto runnable
Inserire immagini o disegnare con ImageIcon
è usata per piccole immagini su bottoni o etichette e per disegnare su
qualunque componente di tipo JComponent.
La classe javax.swing.ImageIcon
Risulta molto semplice inserire un'immagine di tipo ImageIcon in un bottone o etichetta: ad esempio per
inserirla in un componente di tipo JLabel basta il seguente codice:
ImageIcon icon = new ImageIcon("nome del file comprensivo del percorso");
JLabel label = new JLabel(icon);
// Inserire immagini di tipo ImageIcon in un componente di tipo JLabel
import java.awt.*;
import javax.swing.*;
public class ImageLabel{
private
private
private
private
ImageIcon icon;
JFrame f;
JLabel label;
JPanel p;
public ImageLabel() {
icon = new ImageIcon("immagini/verde.gif");
// immagine caricata da file in cartella immagini
// nella stessa sottocartella del bytecode
f = new JFrame("Visualizzazione Immagine");
label = new JLabel(icon);
p = new JPanel();
p.add(label);
f.setContentPane(p);
f.setSize(300,210);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main(String [] args){
new ImageLabel ();
}
}
nb: si può caricare, come per tutte le immagini, da URL
String url="http://www.disi.unige.it/person/MoggiE/LI03/lez6/images/verde.gif"
java.net.URL where = new URL(url);
ImageIcon anotherIcon = new ImageIcon(where);
Per disegnare su un componente di tipo JComponent si ricorre al metodo paintIcon con la seguente sintassi:
nomeImageIcon.paintIcon(Component c, Graphics g, int x, int y);
Altri metodi utili:
int w = nomeImageIcon.getIconWidth();
int h = nomeImageIcon.getIconHeight();
// Disegnare immagini di tipo ImageIcon in un componente di tipo JLabel (che è di tipo JComponent)
import java.awt.*;
import javax.swing.*;
public class ImageIconLabel{
private JFrame f;
private MyIcon disegno;
public ImageIconLabel() {
f = new JFrame("Visualizzazione Immagine");
disegno = new MyIcon();
f.setContentPane(disegno); // l'etichetta personalizzata è inserita sul muro grezzo
f.setSize(300,210);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main(String [] args){
new ImageIconLabel();
}
} // fine applicazione
//classe esterna
class MyIcon extends JLabel{ //oppure, più generico, estendendo dalla classe JComponent
private ImageIcon icon;
public MyIcon(){
}
}
icon = new ImageIcon("immagini/verde.gif");
// cartella immagini in sottocartella con bytecode
public void paintComponent(Graphics g) {
super.paintComponent(g);
icon.paintIcon(this, g, 5, 5); // disegno posizionato rispetto alla cornice
}
x = 5 pixel
y = 5 pixel
APPENDICE: Introduzione agli eventi e loro gestione
Un evento è un messaggio che il sistema genera in risposta a un’azione effettuata generalmente
dall’utente quando interagisce con l’applicazione.
Gli eventi vengono gestiti dal sistema, che effettua per prima cosa alcune operazioni predefinite, e
quindi passa il controllo a una procedura, detta procedura-evento, con la quale il programmatore
specifica il comportamento dell’applicazione in risposta all’evento. Si parla di modello a delega
quando il programmatore può decidere a quale ascoltatore “delegare” la gestione dell’evento.
Gli eventi più comuni sono quelli generati dal mouse o dalla tastiera.
Le procedure-evento
Una procedura-evento è una procedura specificamente associata a un dato oggetto e a un dato
evento che può interessare quell’oggetto. Le procedure-evento servono al programmatore per
specificare il comportamento dell’applicazione in risposta al verificarsi di un dato evento su un
certo oggetto.
Ambienti visuali: oggetti predefiniti
Gli oggetti predefiniti sono gli elementi di base di applicazioni visuali. Al contrario degli ambienti
OOP puri, nei quali il programmatore definisce gli oggetti come blocchi di codice e di dati correlati,
negli ambienti visuali gli oggetti sono entità preconfezionate, già pronte per l’uso. Queste entità
sono elementi reali, come caselle di testo o pulsanti di comando.
L’ambiente di sviluppo mette a disposizione apposite barre di pulsanti che servono per la creazione
degli oggetti. Ogni pulsante sulla barra rappresenta un tipo di oggetto predefinito disponibile.
Lo sviluppatore seleziona il pulsante corrispondente al tipo di oggetto che vuole creare e quindi lo
traccia su una finestra. Successivamente ne imposta le proprietà e infine scrive le procedure-evento
necessarie per far rispondere l’oggetto alle azioni dell’utente.
Schede di approfondimento
Ambienti visuali ed eventi da http://www.fermi.mn.it/inform/visual/indexb.htm
con approfondimento in http://www.fermi.mn.it/inform/visual/index.htm
Eventi e linguaggio Java: modello a delega
Nel linguaggio Java, quando l’utente di una interfaccia grafica (GUI) digita caratteri o usa il mouse
o un componente dell’interfaccia grafica, il gestore delle finestre di Java invia una comunicazione
al programma per segnalare che si è verificato un evento.
Oggetto
GUI
Genera evento
Oggetto
ascoltatore
Classe che
implementa
event
listener
Risposta a evento
Interfaccia:
metodi
per
rispondere
a evento
Esistono classi d’ascolto di eventi (event listener) per permettere ad un programma di indicare quali
eventi gradisce ricevere.
Ogni programma dovrà creare un oggetto per ognuna delle classi cui è interessato; tali oggetti
prendono il nome di ascoltatori (oggetto di una classe di ascolto).
La classe di ascolto deve implementare almeno una interfaccia di ascolto (interfacce di tipo
listener). Un ascoltatore di eventi è un oggetto di una classe di ascolto che implementa almeno una
interfaccia di ascolto.
Tali interfacce11 sono segmenti software predefiniti per gestire l’evento.
Per creare un ascoltatore bisogna conoscere l’origine dell’evento che può essere ad esempio l’intera
Applicazione o Applet (programma Java eseguibile da browser) o una sua parte.
Per origine dell’evento si intende il contenitore o il componente che può generare l’evento (ad
esempio un pulsante è l’origine dell’evento di azione tipo “clic su pulsante”).
11
Contenute nel package java.awt.event libreria che deve essere importata.
I passi, dunque, per gestire gli eventi programmando in Java sono i seguenti:
1.
Decidere quali eventi interessano l’applicazione o l’applet. Tale fase si traduce nella scelta
dell’interfaccia di ascolto da implementare
2.
Decidere qual è l’origine dell’evento: il componente o contenitore che può generare (notificare)
l’evento e creare tale oggetto GUI (ogni componente ad eccezione di LABEL o un contenitore
ad esempio tutto l’Applet).
3.
Creare una oggetto della classe di ascolto:
L’oggetto ascoltatore può essere ad esempio tutta l’Applet o tutta l’applicazione che
implementa (implements) la classe predefinita d’ascolto di quell’evento che ne definisce
l’interfaccia (metodi di risposta a quell’evento).
 L’oggetto ascoltatore può essere creato come istanza di una classe di ascolto definita
dall’utente che implementa (implements) la classe predefinita d’ascolto di quell’evento
che ne definisce l’interfaccia (metodi di risposta a quell’evento)

4.
Collegare all’origine dell’evento l’oggetto della classe d’ascolto di quell’evento cioè
registrare l’ascoltatore
5.
Implementare almeno un metodo dell’interfaccia per rispondere a quell’evento creando il
codice di gestione che serve. Se sono definiti più metodi di risposta nell’interfaccia, è necessario
scrivere le segnature dei metodi non usati oppure, in alternativa, creare l’oggetto ascoltatore
come istanza di una classe che eredita (extends) dalla classe Adapter relativa a quell’evento.
Dispense on-line: “Programmazione a oggetti in Java” Cabri-Zambonelli
http://www.sci.unich.it/~scozzari/ingsw/java_grafica.pdf
Leggere l’input con la classe Scanner
La classe Scanner
Sfortunatamente, la classe InputStream non possiede metodi comodi per la ricezione di dati
numerici e stringhe
Per ovviare a questo inconveniente, Java 5.0 ha introdotto la classe Scanner nel package util.
Un oggetto di tipo Scanner consente di leggere da qualsiasi flusso di ingresso (ad es. un file) senza
rendere necessaria la gestione di ecccezioni.
Si può usare anche per leggere dati in ingresso da tastiera ricevuti tramite l'oggetto System.in (di
tipo InputStream adatto per la lettura di flussi di byte)
Il metodo nextInt di Scanner
Prima di tutto si deve importare la classe Scanner all'interno del file .java che ne fa uso.
import java.util.Scanner;
All'interno del codice si deve creare un nuovo oggetto della classe Scanner
Scanner in = new Scanner(System.in);
Poi si possono invocarne i metodi.
Ad esempio per leggere un intero:
int number = in.nextInt();
Durante l’esecuzione del metodo nextInt il programma si ferma ed attende l’introduzione
dell’input da tastiera, che termina quando l’utente batte il tasto Invio
Il metodo nextInt restituisce un valore numerico di tipo int
Cosa succede se l’utente non digita un numero intero sulla tastiera (ad esempio, se scrive 55KZ) ?
Effetto senza cattura delle eccezioni:
Effetto con cattura delle eccezioni:
int intero = 0;
try { intero= s.nextInt(); } catch (Exception e) {
System.out.println("Errore: "+ e +" in input");
System.exit(0);
}
Altri metodi di Scanner
ATTENZIONE:
•
bisogna sempre importare la classe Scanner e
creare un oggetto di tipo Scanner
Leggere un numero in virgola mobile con separatore virgola
double price = in.nextDouble();
•
Leggere una intera riga fino alla pressione di Enter
String city = in.nextLine();
•
Leggere una parola fino al primo carattere di spaziatura: spazio, fine riga, tabulazione
String state = in.next();
•
Informare se esiste il token (blocco di testo categorizzato) successivo:
boolean b = in.hasNext();
Uso finestre di dialogo: di input, di allarme o di scelta multipla
La classe JOptionPane permette di creare facilmente una dialog box standard di tipo “pop
up” che consente all’utente di inserire dati o essere avvisato di qualcosa. Per informazioni sull’uso
di tale classe si consulti How to Make Dialogs, nella sezione del The Java Tutorial.
Una dialog box appare, di solito, come mostrato a lato, ma si possono
apportare modifiche al layout modificandone le proprietà con l’impostazione
di opportuni parametri dei metodi di tipo showXxxDialog
icon
message
input value
option buttons
Parametri: parentComponent, message, title, messageType, optionType, options, icon,
initialValue oltre a selectionValues(opzioni di scelta in dialoghi di tipo input)
parentComponent: il Componente che contiene la dialog box; se tale primo parametro è null imposta il Frame di
default usato come parent: la finestra di dialogo sarà centrata nello schermo e risulterà indipendente dal resto
dell'applicazione.
message: un messaggio descrittivo, di solito una stringa; con altre possibilità:
Object[] cioè un array di oggetti interpretato come una serie di messaggi memorizzati in uno stack
verticale.L’interpretazione è ricorsiva: ogni oggetto è interpretato a seconda del tipo
Component cioè un componente visualizzato nel dialog.
Icon inglobata in un JLabel e visualizzata nel dialog
altro cioè un’oggetto convertito in una stringa mediante il metodo toString. Il risultato è inglobato in
un JLabel e visualizzato nel dialog
title: il titolo della finestra di dialogo che appare nella cornice superiore; il valore di default dipende dal tipo di dialog
(la stringa “Input” per dialog in input, “Messaggio” per dialog in out, “Selezionare un’opzione” per dialog di conferma).
messageType : definisce lo stile del messaggio. Possibili valori, che prevedono relative icone di default, sono:
ERROR_MESSAGE
INFORMATION_MESSAGE
WARNING_MESSAGE
QUESTION_MESSAGE
PLAIN_MESSAGE
optionType: definisce il set dei bottoni di opzione (senza limiti) che appaiono in basso al dialog box:
DEFAULT_OPTION
YES_NO_OPTION
YES_NO_CANCEL_OPTION
OK_CANCEL_OPTION
options: una più dettagliata descrizione del set dei bottoni di opzione. Di solito un array di stringhe ma è previsto un
array di oggetti che possono essere di tipo:
Component cioè un componente aggiunto direttamente al bottone
Icon usata come label in un JButton
altro cioè un’oggetto convertito in una stringa mediante il metodo toString. Il risultato è usato come
label in un JButton
icon: una icona decorativa. Il valore di default è stabilito dal parametro messageType.
initialValue: la scelta di default (valore in input)
La classe JOptionPane mette a disposizione tre tipi di pannelli: Confirm Dialog, Input Dialog e Message
Dialog
• il primo tipo di pannello viene usato quando si deve chiedere all'utente di effettuare una scelta tra un
gruppo di possibilità;
• il secondo torna utile quando si debba richiedere l'inserimento di una stringa di testo
• mentre il terzo viene usato per informare l'utente.
JOptionPane fornisce un gruppo di metodi statici che permettono di creare facilmente questi pannelli
ricorrendo ad una sola riga di codice senza istanziare oggetti:
Alcuni metodi showInputDialog per finestra di dialogo in lettura:
static Object showInputDialog(Component parentComponent, Object message, String
title, int messageType, Icon icon, Object[] selectionValues, Object
initialSelectionValue)
Prompts the user for input in a blocking dialog where the initial selection, possible selections,
and all other options can be specified.
static String showInputDialog(Object message)
Shows a question-message dialog requesting input from the user.
static String showInputDialog(Object message, Object initialSelectionValue)
Shows a question-message dialog requesting input from the user, with the input value initialized
to initialSelectionValue.
JOptionPane.showInputDialog ("Come ti chiami?");
String nome;
nome = JOptionPane.showInputDialog ("Come ti chiami?", "Mario");
// initialValue è “Mario”
Tra i metodi showConfirmDialog per finestra di dialogo che chiede di confermare una
domanda tipo yes/no/cancel, il più semplice :
static int showConfirmDialog(Component parentComponent, Object message)
Brings up a dialog with the options Yes, No and Cancel; with the title, Select an Option.
JOptionPane.showConfirmDialog(null, "Conferma");
Alcuni metodi showMessageDialog per finestra di informazione:
static void showMessageDialog(Component parentComponent, Object message)
Brings up an information-message dialog titled "Message".
static void showMessageDialog(Component parentComponent, Object message, String
title, int messageType, Icon icon)
Brings up a dialog displaying a message, specifying all parameters.
JOptionPane.showMessageDialog(null, nome);
JOptionPane.showMessageDialog (null, "Icona personalizzata",
"Titolo del dialog", JOptionPane.INFORMATION_MESSAGE,
new ImageIcon ("JavaCup.gif"));
// icona (piccola immagine) personalizzata
Il metodo showOptionDialog Grand Unification dei metodi precedenti
static int showOptionDialog(Component parentComponent, Object message, String
title, int optionType, int messageType, Icon icon, Object[] options,
Object initialValue)
Brings up a dialog with a specified icon, where the initial choice is determined by the
initialValue parameter and the number of choices
Tutte le finestre di dialogo (dialogs) create sono modali cioè ogni metodo showXxxDialog blocca il
thread corrente fino a quando l’interazione con l’utente non è stata completata
Esempio di applicazione con test di alcuni metodi di tipo showXxxDialog tra cui:
•
finestra di dialogo in lettura con modifica del titolo di default della dialog box
static String showInputDialog (Component parentComponent, Object message, String title,
int messageType)
•
finestra di dialogo in scrittura con modifica del titolo di default della dialog box
static void showMessageDialog (Component parentComponent, Object message, String title,
int messageType)
•
uso del metodo che costituisce Grand Unification
static int showOptionDialog (Component parentComponent, Object message, String title,
int optionType, int messageType, Icon icon,
Object[] options, Object initialValue)
import javax.swing.*;
// per classi JOptionPane e ImageIcon
class Dialog {
private String input;
public String getInput(){
// uso finestra di dialogo in lettura
input=JOptionPane.showInputDialog("Digita la stringa");
// per stesso effetto .... ma con titolo "Lettura" ... invece di "Input"
input=JOptionPane.showInputDialog(null,"Digita la stringa", "Lettura",
JOptionPane.QUESTION_MESSAGE);
// Mostra una finestra di dialogo che chiede all’utente di selezionare una stringa
Object[] possibleValues = { "prima", "seconda" };
Object sel_input = JOptionPane.showInputDialog(null, "Scegli", "Lettura",
JOptionPane.INFORMATION_MESSAGE, null,
possibleValues, possibleValues[0]);
input = sel_input.toString();
return input;
}
// oppure con casting
input = (String) sel_input;
public void visualizza(String testo){
// uso finestra di dialogo in scrittura
JOptionPane.showMessageDialog(null, testo, null, JOptionPane.PLAIN_MESSAGE ); // senza icona
JOptionPane.showMessageDialog(null, testo);
// icona di tipo "Informazione"
// finestra di dialogo più flessibile
Object[] options = { "OK", "CANCELLA" };
JoptionPane.showOptionDialog (null, testo, "Informazione", JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE, null, options,
options[0]);
// icona di default
JoptionPane.showOptionDialog (null, testo, "Informazione", JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE,
new ImageIcon ("JavaCup.gif"), options, options[0]);
}
public static void main (String arg[]){
Dialog o = new Dialog();
String messaggio = "Inserita: " + o.getInput();
o.visualizza(messaggio);
}// fine main
}// fine applicazione
JOptionPane.showMessageDialog (null,
"Icona personalizzata",
"Titolo del dialog",
JOptionPane.INFORMATION_MESSAGE,
new ImageIcon("JavaCup.gif")); // icona personalizzata
JButton b1 = new JButton("Bottone 1");
// Component come messaggio
JOptionPane.showMessageDialog (null, b1,
null, JOptionPane.INFORMATION_MESSAGE );
ImageIcon img = new ImageIcon("JavaCup.gif");
// icona come messaggio
JOptionPane.showMessageDialog (null, img, null, JOptionPane.QUESTION_MESSAGE );
JOptionPane.showConfirmDialog(null,
"Conferma");
JLabel labelIcon = new JLabel(new ImageIcon("JavaCup.gif"));
// icona - logo come etichetta
Object[] options = {labelIcon, b1, b2};
JOptionPane.showOptionDialog (null, "Scegli", "Senza effetto",
JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE, null, options,
options[0]);
Object[] options1 = {img, b1, b2};
// icona - logo in bottone che premuto chiude dialog
JOptionPane.showOptionDialog (null, "Scegli bottone",
"Senza effetto", JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE,
new ImageIcon ("JavaCup.gif"), options1, options1[0]);
// icona personalizzata
NB: personalizzazione del set di bottoni di opzione posti in basso
Per permettere opzioni di scelta in input, con metodo showInputDialog, volendo personalizzare l’icona ad esempio col
logo di Java (immagine JavaCup.gif di dimensioni 16x16, nella stessa cartella), il titolo:
Object[] possibleValues = { "uno", "due" ,"tre"};
JOptionPane.showInputDialog (null, "Messaggio",
"Titolo", JOptionPane.INFORMATION_MESSAGE,
new ImageIcon ("JavaCup.gif"), possibleValues, possibleValues[0]);
…. con modifica del Look & Feel
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
} catch (Exception e) { }
// stile CDE/Motif. Scelta disponibile su qualunque piattaforma
Look & Feel : insieme delle due proprietà che caratterizzano un ambiente a finestre:
•
•
l'aspetto dei componenti (ovvero la loro sintassi) – specifiche di visualizzazione
la maniera in cui essi reagiscono alle azioni degli utenti (la loro semantica) – specifiche di
interazione
La natura multipiattaforma di java ha spinto i progettisti di Swing a separare le problematiche di disegno
grafico dei componenti da quelle inerenti al loro contenuto informativo, con la sorprendente conseguenza di
permettere agli utenti di considerare il Look & Feel come una proprietà del componente da impostare a
piacere. La distribuzione standard del JDK comprende di base due alternative: Metal e Motif.
La prima definisce un Look & Feel multipiattaforma, progettato per risultare familiare agli utenti di ogni
piattaforma; la seconda implementa una vista familiare agli utenti Unix. Le distribuzioni di java per
Windows e Mac includono anche un L&F che richiama quello della piattaforma ospite.
Per impostare da programma un particolare look & feel è sufficiente chiamare il metodo
UIManager.setLookAndFeel(String className)
passando come parametro il nome di un l&f installato nel sistema.
Un’applicazione che crea una finestra in cui si apre una dialog box modale che risulta centrata rispetto a
quest’ultima:
import javax.swing.*;
import java.awt.*;
// per Container
class DialogF extends JFrame {
public void visualizza(){
// per aprire una finestra
// nel punto x,y con larghezza 400, altezza 200
setBounds(100,100,400,200);
Container cont=getContentPane();
cont.setLayout(null);
setVisible(true);
String nome;
nome = JOptionPane.showInputDialog (cont,"Come ti chiami?", "Mario");
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main (String arg[]){
DialogF o = new DialogF();
o.visualizza();
}// fine main
}// fine applicazione
La stessa applicazione (che crea una finestra in cui si apre una dialog box modale che risulta
centrata rispetto a quest’ultima) con modifica del Look & Feel
import javax.swing.*;
import java.awt.*;
// per Container
class DialogF extends JFrame {
public void visualizza(){
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
} catch (Exception e) { }
// stile CDE/Motif. Scelta disponibile su qualunque piattaforma
// per aprire una finestra
// nel punto x,y con larghezza 400, altezza 200
setBounds (100,100,400,200);
Container cont=getContentPane();
cont.setLayout(null);
setVisible(true);
String nome;
nome = JOptionPane.showInputDialog (cont,"Come ti chiami?", "Mario");
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
public static void main (String arg[]){
DialogF o = new DialogF();
o.visualizza();
}// fine main
}// fine applicazione
nb:
Due parole sui metodi per visualizzare o nascondere i frames :
setVisible(true) per rendere visibile il frame che non lo è per default - deprecato show()
setVisible(false) ovviamente per nasconderlo - deprecato hide()
Per scegliere la posizione iniziale si può utilizzare il metodo setBounds(int, int, int, int); con argomenti
nell'ordine di digitazione x ed y dell'angolo superiore sinistro e dimensioni larghezza ed altezza del frame
Progetto di un pannello che sia maschera di input
/**
* @(#)Maschera.java
*
* Maschera classe che crea il pannello consentendo di:
*
inserire articoli (e relativo prezzo), sia in lire che in euro
*
avere sempre sott’occhio il totale, sia in lire che in euro
*
poter salvare su file, in qualunque momento, l’elenco degli ordini inseriti.
*
* @author classe quarta
* @version 1.00 2011/4/9
*/
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Maschera extends JPanel {
JTextField nome, prezzo, totale;
JTextArea elenco;
JRadioButton lire, euro;
ButtonGroup grp;
JButton save, inserisci;
Box boxRadio, riga1, riga2, riga3, riga4;
// Costruzione del primo Box orizzontale in cui collocare le due etichette
public Maschera(){
super();
JLabel etichetta1 = new JLabel("Descrizione articolo");
JLabel etichetta2 = new JLabel("Prezzo");
riga1 = new Box(BoxLayout.X_AXIS);
riga1.add(etichetta1);
riga1.add(Box.createHorizontalStrut(80)); // spazio fisso indivisibile di 80 pixel
riga1.add(etichetta2);
// Costruzione del secondo Box orizzontale in cui collocare i due campi di testo
nome = new JTextField(15);
prezzo = new JTextField(7);
prezzo.setHorizontalAlignment(JTextField.RIGHT);
riga2 = new Box(BoxLayout.X_AXIS);
riga2.add(nome);
riga2.add(prezzo);
// Costruzione del terzo Box orizzontale con altre etichette
riga3 = new Box(BoxLayout.X_AXIS);
riga3.add(new JLabel("Articoli inseriti"));
riga3.add(Box.createHorizontalStrut(80));
riga3.add(new JLabel("Valuta"));
//Costruzione del Box verticale per bottoni e totale
// l’area di testo
elenco = new JTextArea(6,12);
elenco.setEditable(false);
// non modificabile
elenco.setBackground(Color.cyan);
// i bottoni radio
lire = new JradioButton("Lire",true); // default
euro = new JRadioButton("Euro");
grp = new ButtonGroup();
grp.add(lire);
grp.add(euro);
//Costruzione del Box verticale per bottoni e totale
// il Box verticale vero e proprio
boxRadio = new Box(BoxLayout.Y_AXIS);
boxRadio.add(lire); boxRadio.add(euro);
boxRadio.add(Box.createVerticalStrut(20));
boxRadio.add(new JLabel("Totale"));
totale = new JTextField("0", 5);
// totale inizialmente a zero
totale.setHorizontalAlignment(JTextField.RIGHT);
boxRadio.add(totale);
// Costruzione del quarto Box orizzontale per area di testo e Box verticale
riga4 = new Box(BoxLayout.X_AXIS);
riga4.add(elenco);
riga4.add(Box.createHorizontalStrut(30));
riga4.add(boxRadio);
// Assemblaggio dei vari blocchi
add(riga1);
add(riga2);
inserisci = new JButton("Aggiungi articolo");
add(inserisci);
add(riga3);
add(riga4);
save = new JButton("Salva");
save.setEnabled(false); // inizialmente disabilitato
add(save);
// Creazione e registrazione dei listener
inserisci.addActionListener (new InsertListener(nome, prezzo, totale,elenco, lire, save)); // in modo anonimo
CurrencyListener c = new CurrencyListener(prezzo, totale);
lire.addActionListener(c); // unico listener per i due radio-button
euro.addActionListener(c); // unico listener per i due radio-button
save.addActionListener (new SaveListener(elenco, totale,lire, save));
}
} // fine classe che estende JPanel
class InsertListener implements ActionListener {
JTextField nome, prezzo, totale;
JTextArea elenco;
JRadioButton lire;
JButton save;
public InsertListener (JTextField n, JTextField p, JTextField t, JTextArea e, JRadioButton l, JButton s){
nome=n;
prezzo=p;
totale=t;
elenco=e;
lire=l;
save=s;
}
public void actionPerformed(ActionEvent e){
save.setEnabled(true);
double tot = Double.parseDouble(totale.getText());
double prz = Double.parseDouble(prezzo.getText());
totale.setText(Double.toString(prz + tot));
elenco.append (nome.getText() + " " + prezzo.getText() +(lire.isSelected() ? " ITL" : " EUR") + "\n");
nome.setText("");
prezzo.setText("");
nome.requestFocus();
}
} // fine classe ascoltatore per inserimento nuovi articoli
class CurrencyListener implements ActionListener {
JTextField prezzo, totale;
public final double CAMBIO = 1936.27;
public CurrencyListener(JTextField p,JTextField t){
prezzo=p; totale=t;
}
public void actionPerformed(ActionEvent e){
double tot = Double.parseDouble(totale.getText());
String p = prezzo.getText();
if (p.equals("")) p="0";
double price = Double.parseDouble(p);
if (e.getActionCommand().equals("Lire")) {
// erano Euro, vanno convertiti in lire
tot *= CAMBIO;
price *= CAMBIO;
// elimina la parte frazionaria di un numero reale,
tot = Math.rint(tot); // arrotondandolo
price = Math.rint(price);
}
else { // erano Lire, da convertire in Euro
tot /= CAMBIO;
price /= CAMBIO;
tot = Math.rint(tot*100)/100;
price = Math.rint(price*100)/100;
// Arrotondamento alla IIª cifra decimale: si sposta la virgola, si arrotonda e si rimette la virgola dov'era
}
totale.setText (Double.toString(tot));
prezzo.setText(price==0.0 ? "" :
Double.toString(price)); // Estetica: un prezzo di 0.0 non viene indicato, si mette le stringa vuota.
}
} // fine classe ascoltatore per conversione valuta
class SaveListener implements ActionListener {
JTextField totale;
JTextArea elenco;
JRadioButton lire;
JButton save;
public SaveListener(JTextArea e, JTextField t, JRadioButton l, JButton s){
elenco=e;
totale=t;
lire=l;
save=s;
}
public void actionPerformed(ActionEvent e){
double tot = Double.parseDouble(totale.getText());
try {
FileWriter f = new FileWriter("ELENCO.txt");
PrintWriter out = new PrintWriter(f);
out.print(elenco.getText());
out.println();
out.print("Totale: " + totale.getText() +(lire.isSelected() ? " ITL" : " EUR") + "\n");
out.println();
out.close();
} catch (IOException ex) { System.err.println(ex); }
save.setEnabled(false);
}
} // fine classe ascoltatore per salvataggio su file
Di seguito la possibile classe di test cou scrittura su file
senza gestione dell'a capo in Blocco note
/**
* @(#)TestMaschera.java
*
* TestMaschera application
*
* @author quarte
* @version 1.00 2011/4/15
*/
import java.awt.*;
import javax.swing.*;
class TestMaschera {
public static void main(String [] args){
JFrame f = new Jframe("Acquisti");
Container c = f.getContentPane();
Maschera guiP = new Maschera();
guiP.setBackground(Color. lightGray);
c.add(guiP);
// sfondo del pannello colorato
// aggiunge il pannello
f.setSize(300,300);
f.setVisible(true);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
}
Ogni volta si riscrive sul file senza aggiungere:
Menu
/**
* @(#)Menu.java
*
* Menu application
*
* @author Sun
* @version 1.00 2011/5/4
*/
// http://download.oracle.com/javase/tutorial/uiswing/components/menu.html
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Menu {
//Where the GUI is created
JFrame f = new JFrame("Finestra con menu");
JMenuBar menuBar;
JMenu menu, submenu;
JMenuItem menuItem;
JRadioButtonMenuItem rbMenuItem;
JCheckBoxMenuItem cbMenuItem;
public Menu() {
//Create the menu bar.
menuBar = new JMenuBar();
//Build the first menu.
menu = new JMenu("Un menu");
menuBar.add(menu);
//a group of JMenuItems
menuItem = new JMenuItem("Solo testo");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.CTRL_MASK));
// modifica per Ctr A
//menuItem.getAccessibleContext().setAccessibleDescription("This doesn't really do anything"); // non appare 1.5
menu.add(menuItem);
menuItem = new JMenuItem("Sia testo sia icona", new ImageIcon("middle.gif"));
//menuItem.setMnemonic(KeyEvent.VK_B); // non appare 1.5
menu.add(menuItem);
menuItem = new JMenuItem(new ImageIcon("middle.gif")); // immagine nella stessa cartella del bytecode
menu.add(menuItem);
//a group of radio button menu items
menu.addSeparator();
ButtonGroup group = new ButtonGroup();
rbMenuItem = new JRadioButtonMenuItem("Un radio button come voce di menu");
rbMenuItem.setSelected(true);
group.add(rbMenuItem);
menu.add(rbMenuItem);
rbMenuItem = new JRadioButtonMenuItem("Un altro");
group.add(rbMenuItem);
menu.add(rbMenuItem);
//a group of check box menu items
menu.addSeparator();
cbMenuItem = new JCheckBoxMenuItem("Una check box come voce di menu");
menu.add(cbMenuItem);
cbMenuItem = new JCheckBoxMenuItem("Un'altra");
menu.add(cbMenuItem);
//a submenu
menu.addSeparator();
submenu = new JMenu("Un sottomenu");
menuItem = new JMenuItem("Una voce del sottomenu");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK)); // per Alt
submenu.add(menuItem);
menuItem = new JMenuItem("Un altra voce");
submenu.add(menuItem);
menu.add(submenu);
//Build second menu in the menu bar.
menu = new JMenu("Un altro menu");
menu.setToolTipText ("Senza voci");
menuBar.add(menu);
Container c= f.getContentPane();
f.setSize(400,300);
f.setJMenuBar(menuBar);
f.setVisible(true);
}
public static void main (String args[]){
new Menu();
}
}