5. Interfacce grafiche utente
Qui intendiamo mostrare come costruire interfacce grafiche utente con Java. Per prima cosa, esamineremo le classi di base che ci consentono di costruire un'interfaccia grafica utente. Inizialmente, non useremo alcun strumento di generazione automatica. Successivamente useremo JBuilder, uno strumento di sviluppo Borland/Inprise che facilita lo sviluppo di applicazioni Java e, in particolare, la costruzione di interfacce grafiche utente.
5.1. Nozioni di base sulle interfacce grafiche
5.1.1. Una finestra semplice
Consideriamo il seguente codice:
// imported classes
import javax.swing.*;
import java.awt.*;
// the form class
public class form1 extends JFrame {
// the manufacturer
public form1() {
// window title
this.setTitle("Mon premier formulaire");
// window dimensions
this.setSize(new Dimension(300,100));
}//manufacturer
// test function
public static void main(String[] args) {
// the form is displayed
new form1().setVisible(true);
}
}//class
L'esecuzione del codice sopra riportato visualizza la seguente finestra:

Un'interfaccia utente grafica estende generalmente la classe base JFrame:
public class form1 extends JFrame {
La classe base JFrame definisce una finestra di base con pulsanti di chiusura, ingrandimento/riduzione a icona, dimensioni regolabili, ecc., e gestisce gli eventi su questi oggetti grafici. Qui specializziamo la classe base impostando il titolo, la larghezza (300 pixel) e l'altezza (100 pixel). Ciò avviene nel suo costruttore:
// le constructeur
public form1() {
// titre de la fenêtre
this.setTitle("Mon premier formulaire");
// dimensions de la fenêtre
this.setSize(new Dimension(300,100));
}//constructeur
Il titolo della finestra viene impostato dal metodo setTitle e le sue dimensioni dal metodo setSize. Questo metodo accetta come parametro un oggetto Dimension (width, height), dove width e height sono la larghezza e l'altezza della finestra espresse in pixel.
Il metodo main avvia l'applicazione grafica come segue:
new form1().setVisible(true);
Viene quindi creato un form di tipo form1 (new form1()) e visualizzato (setVisible(true)), dopodiché l'applicazione ascolta gli eventi che si verificano sul form (clic, movimenti del mouse, ecc.) ed esegue quelli gestiti dal form. In questo caso, il nostro form non gestisce alcun evento oltre a quelli gestiti dalla classe base JFrame (clic sui pulsanti di chiusura, ingrandimento/riduzione a icona, ridimensionamento della finestra, spostamento della finestra, ecc.).
Quando si testa questo programma eseguendolo da una finestra DOS utilizzando:
per eseguire il file form1.class, si nota che quando si chiude la finestra visualizzata, non si "riprende il controllo" della finestra DOS, come se il programma non fosse terminato. Questo è effettivamente il caso. Il programma si esegue come segue:
- Inizialmente, viene avviato un primo thread di esecuzione per eseguire il metodo main
- quando questo metodo crea il form e lo visualizza, viene creato un secondo thread per gestire specificamente gli eventi relativi al form
- dopo questa creazione, e nel nostro esempio, il thread del metodo main termina, lasciando solo il thread di esecuzione della GUI.
- Quando la finestra viene chiusa, scompare ma non interrompe il thread in cui era in esecuzione
- Per ora, siamo costretti a interrompere questo thread premendo Ctrl-C nella finestra DOS da cui è stato avviato il programma.
Verifichiamo l'esistenza di due thread distinti: uno in cui viene eseguito il metodo main e l'altro in cui viene eseguita la finestra dell'interfaccia grafica:
// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
// the form class
public class form1 extends JFrame {
// the manufacturer
public form1() {
// window title
this.setTitle("Mon premier formulaire");
// window dimensions
this.setSize(new Dimension(300,100));
}//manufacturer
// test function
public static void main(String[] args) {
// follow-up
System.out.println("Début du thread main");
// the form is displayed
new form1().setVisible(true);
// follow-up
System.out.println("Fin du thread main");
}//hand
}//class
L'esecuzione produce i seguenti risultati:

Possiamo notare che il thread principale è terminato mentre la finestra è ancora visualizzata. La chiusura della finestra non termina il thread in cui era in esecuzione. Per arrestare questo thread, premere nuovamente Ctrl-C nella finestra DOS.
Per concludere questo esempio, si notino i pacchetti importati:
- javax.swing per la classe JFrame
- java.awt per la classe Dimension
5.1.2. Gestione di un evento
Nell'esempio precedente, dovremmo gestire noi stessi la chiusura della finestra in modo che, quando ciò avviene, l'applicazione si arresti, cosa che attualmente non avviene. Per farlo, dobbiamo creare un oggetto che "ascolti" gli eventi che si verificano sulla finestra e rilevi l'evento "chiusura della finestra". Questo oggetto è chiamato "listener" o gestore di eventi. Esistono diversi tipi di listener per i vari eventi che possono verificarsi sui componenti di un'interfaccia utente grafica. Per il componente JFrame, il listener si chiama WindowListener ed è un'interfaccia che definisce i seguenti metodi (vedere la documentazione Java)
Riepilogo dei metodi | ||
void | windowActivated(WindowEvent e) La finestra diventa la finestra attiva | |
void | windowClosed(WindowEvent e) La finestra è stata chiusa | |
void | windowClosing(WindowEvent e) L'utente o il programma ha richiesto la chiusura della finestra | |
void | windowDeactivated(WindowEvent e) La finestra non è più la finestra attiva | |
void | windowDeiconified(WindowEvent e) La finestra passa dallo stato ridotto a quello normale | |
void | windowIconified(WindowEvent e) La finestra passa dallo stato normale allo stato ridotto a icona | |
void | windowOpened(WindowEvent e) La finestra diventa visibile per la prima volta | |
Ci sono quindi sette eventi che possono essere gestiti. Tutti gli handler ricevono un oggetto WindowEvent come parametro, che per ora ignoreremo. L'evento di interesse in questo caso è la chiusura della finestra, che deve essere gestita dal metodo windowClosing. Per gestire questo evento, possiamo creare un oggetto WindowListener utilizzando una classe anonima come segue:
// création d'un gestionnaire d'événements
WindowListener win=new WindowListener(){
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){System.exit(0);}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
};//définition win
Il nostro gestore di eventi che implementa l'interfaccia WindowListener deve definire tutti e sette i metodi di questa interfaccia. Poiché vogliamo gestire solo la chiusura della finestra, definiamo solo il codice per il metodo windowClosing. Quando si verificano gli altri eventi, ne saremo avvisati ma non intraprenderemo alcuna azione. Cosa faremo quando ci verrà notificato che la finestra si sta chiudendo (windowClosing)? Termineremo l'applicazione:
public void windowClosing(WindowEvent e){System.exit(0);}
Qui abbiamo un oggetto in grado di gestire gli eventi della finestra in generale. Come lo associamo a una finestra specifica? La classe JFrame ha un metodo addWindowListener(WindowListener win) che ci permette di associare un gestore di eventi "window" a una data finestra. Quindi qui, nel costruttore della finestra, scriveremo:
// création d'un gestionnaire d'événements
WindowListener win=new WindowListener(){
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){System.exit(0);}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
};//définition win
// ce gestionnaire d'événements va gérer les évts de la fenêtre courante
this.addWindowListener(win);
Il programma completo è il seguente:
// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// the form class
public class form2 extends JFrame {
// the manufacturer
public form2() {
// window title
this.setTitle("Mon premier formulaire");
// window dimensions
this.setSize(new Dimension(300,100));
// creation of an event manager
WindowListener win=new WindowListener(){
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){System.exit(0);}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
};//definition win
// this event handler will manage the events of the current window
this.addWindowListener(win);
}//manufacturer
// test function
public static void main(String[] args) {
// the form is displayed
new form2().setVisible(true);
}//hand
}//class
Il pacchetto java.awt.event contiene l'interfaccia WindowListener. Quando eseguiamo questo programma e chiudiamo la finestra che è apparsa, nella finestra DOS in cui è stato avviato il programma vediamo che l'esecuzione del programma è terminata, cosa che prima non accadeva.
Nel nostro programma, la creazione dell'oggetto responsabile della gestione degli eventi della finestra è un po' macchinosa, poiché siamo costretti a definire metodi anche per eventi che non vogliamo gestire. In questo caso, invece di utilizzare l'interfaccia WindowListener, possiamo utilizzare la classe WindowAdapter. Questa classe implementa l'interfaccia WindowListener con sette metodi vuoti. Derivando dalla classe WindowAdapter e ridefinendo solo i metodi che ci interessano, otteniamo lo stesso risultato dell'interfaccia WindowListener ma senza dover definire i metodi che non ci interessano. La sequenza
- che definisce il gestore di eventi
- associare il gestore alla finestra
può essere eseguita come segue nel nostro esempio:
// création d'un gestionnaire d'événements
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//définition win
// ce gestionnaire d'événements va gérer les évts de la fenêtre courante
this.addWindowListener(win);
Qui utilizziamo una classe anonima che estende la classe WindowAdapter e sovrascrive il suo metodo windowClosing. Il programma diventa quindi:
// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// the form class
public class form2 extends JFrame {
// the manufacturer
public form2() {
// window title
this.setTitle("Mon premier formulaire");
// window dimensions
this.setSize(new Dimension(300,100));
// creation of an event manager
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//definition win
// this event handler will manage the events of the current window
this.addWindowListener(win); }//manufacturer
// test function
public static void main(String[] args) {
// the form is displayed
new form2().setVisible(true);
}//hand
}//class
Produce gli stessi risultati del programma precedente, ma è più semplice da scrivere.
5.1.3. Un modulo con un pulsante
Ora aggiungiamo un pulsante alla nostra finestra:
// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// the form class
public class form3 extends JFrame {
// a button
JButton btnTest=null;
Container conteneur=null;
// the manufacturer
public form3() {
// window title
this.setTitle("Formulaire avec bouton");
// window dimensions
this.setSize(new Dimension(300,100));
// creation of an event manager
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//definition win
// this event handler will manage the events of the current window
this.addWindowListener(win);
// retrieve the window container
conteneur=this.getContentPane();
// select a layout manager for components in this container
conteneur.setLayout(new FlowLayout());
// create a button
btnTest=new JButton();
// we set the wording
btnTest.setText("Test");
// add the button to the container
conteneur.add(btnTest);
}//manufacturer
// test function
public static void main(String[] args) {
// the form is displayed
new form3().setVisible(true);
}//hand
}//class
Una finestra JFrame dispone di un contenitore in cui è possibile inserire componenti grafici (pulsanti, caselle di controllo, elenchi a discesa, ecc.). È possibile accedere a questo contenitore tramite il metodo getContentPane della classe JFrame:
Container conteneur=null;
..........
// on récupère le conteneur de la fenêtre
conteneur=this.getContentPane();
Qualsiasi componente viene inserito nel contenitore utilizzando il metodo add della classe Container. Pertanto, per inserire il componente C nell'oggetto contenitore sopra indicato, scriviamo:
Dove viene posizionato questo componente nel contenitore? Esistono vari gestori di layout dei componenti denominati XXXLayout, dove XXX può essere Border, Flow, ecc. Ogni gestore di layout ha le proprie caratteristiche. Ad esempio, il gestore FlowLayout dispone i componenti in una riga a partire dalla parte superiore del modulo. Quando una riga è piena, i componenti vengono inseriti nella riga successiva. Per associare un gestore di layout a una finestra JFrame, utilizzare il metodo setLayout della classe JFrame nella forma seguente:
Quindi, nel nostro esempio, per associare un gestore FlowLayout alla finestra, abbiamo scritto:
// on choisit un gestionnaire de mise en forme des composants dans ce conteneur
conteneur.setLayout(new FlowLayout());
È possibile scegliere di non utilizzare un gestore di layout e scrivere:
In questo caso, è necessario specificare le coordinate esatte del componente all'interno del contenitore nel formato (x,y,width,height), dove (x,y) sono le coordinate dell'angolo superiore sinistro del componente all'interno del contenitore. Questo è il metodo che useremo più spesso d'ora in poi.
Ora sappiamo come i componenti vengono aggiunti al contenitore (add) e dove vengono posizionati (setLayout). Non resta che identificare i
componenti che possono essere posizionati in un contenitore. Qui, posizioniamo un pulsante modellato dalla classe javax.swing.JButton:
JButton btnTest=null;
..........
// on crée un bouton
btnTest=new JButton();
// on fixe son libellé
btnTest.setText("Test");
// on ajoute le bouton au conteneur
conteneur.add(btnTest);
Quando si esegue questo programma, viene visualizzata la seguente finestra:

Se si ridimensiona il modulo sopra riportato, il gestore di layout del contenitore viene automaticamente chiamato per riposizionare i componenti:

Questo è il vantaggio principale dei gestori di layout: mantenere un layout coerente dei componenti al variare delle dimensioni del contenitore. Utilizziamo il gestore di layout null per vedere la differenza. Il pulsante viene ora posizionato nel contenitore utilizzando le seguenti istruzioni:
// on choisit un gestionnaire de mise en forme des composants dans ce conteneur
conteneur.setLayout(null);
// on crée un bouton
btnTest=new JButton();
// on fixe son libellé
btnTest.setText("Test");
// on fixe son emplacement et ses dimensions
btnTest.setBounds(10,20,100,20);
// on ajoute le bouton au conteneur
conteneur.add(btnTest);
Qui, posizioniamo esplicitamente il pulsante nel punto (10,20) del modulo e ne impostiamo le dimensioni a 100 pixel di larghezza e 20 pixel di altezza. La nuova finestra appare così:

Se ridimensioniamo la finestra, il pulsante rimane nella stessa posizione.

Se facciamo clic sul pulsante Test, non succede nulla. Questo perché non abbiamo ancora associato un gestore di eventi al pulsante. Per scoprire quali tipi di gestori di eventi sono disponibili per un determinato componente, possiamo cercare nella definizione della sua classe i metodi addXXXListener, che ci consentono di associare un gestore di eventi al componente. La classe javax.swing.JButton estende la classe javax.swing.AbstractButton, che contiene i seguenti metodi:
Riepilogo dei metodi | ||
void | addActionListener(ActionListener l) | |
void | addChangeListener(ChangeListener l) | |
void | addItemListener(ItemListener l) | |
In questo caso, è necessario consultare la documentazione per determinare quale gestore di eventi gestisca il clic sul pulsante. Si tratta dell'interfaccia ActionListener. Questa interfaccia definisce un solo metodo:
Riepilogo dei metodi | ||
void | actionPerformed(ActionEvent e) | |
Il metodo riceve un parametro ActionEvent, che per ora ignoreremo. Per gestire il clic sul pulsante btntest nel nostro programma, dobbiamo prima associargli un listener di eventi:
btnTest.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt){
btnTest_clic(evt);
}
}//anonymous class
);//evt manager
Qui, il metodo actionPerformed chiama il metodo btnTest_clic, che definiamo come segue:
public void btnTest_clic(ActionEvent evt){
// console monitoring
System.out.println("clic sur bouton");
}//btnTest_click
Ogni volta che l'utente fa clic sul pulsante Test, viene visualizzato un messaggio nella console. Ciò è illustrato nella seguente esecuzione:

Il programma completo è il seguente:
// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// the form class
public class form4 extends JFrame {
// a button
JButton btnTest=null;
Container conteneur=null;
// the manufacturer
public form4() {
// window title
this.setTitle("Formulaire avec bouton");
// window dimensions
this.setSize(new Dimension(300,100));
// creation of an event manager
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//definition win
// this event handler will manage the events of the current window
this.addWindowListener(win);
// retrieve the window container
conteneur=this.getContentPane();
// select a layout manager for components in this container
conteneur.setLayout(null);
// create a button
btnTest=new JButton();
// we set the wording
btnTest.setText("Test");
// determine its location and dimensions
btnTest.setBounds(10,20,100,20);
// we associate it with an event manager
btnTest.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt){
btnTest_clic(evt);
}
}//anonymous class
);//evt manager
// add the button to the container
conteneur.add(btnTest);
}//manufacturer
public void btnTest_clic(ActionEvent evt){
// console monitoring
System.out.println("clic sur bouton");
}//btnTest_click
// test function
public static void main(String[] args) {
// the form is displayed
new form4().setVisible(true);
}//hand
}//class
5.1.4. Gestori di eventi
I principali componenti Swing che tratteremo sono finestre (JFrame), pulsanti (JButton), caselle di controllo (JCheckBox), pulsanti di opzione (JButtonRadio), elenchi a discesa (JComboBox), elenchi (JList), barre di scorrimento (JScrollBar), etichette (JLabel), campi di testo a riga singola (JTextField) o campi di testo a più righe (JTextArea), menu (JMenuBar) e voci di menu (JMenuItem).
Le tabelle seguenti elencano alcuni gestori di eventi e gli eventi a cui sono associati.
Gestore | Componenti | Metodo di registrazione | Evento |
ActionListener | JButton, JCheckbox, JButtonRadio, JMenuItem | public void addActionListener(ActionListener) | Fare clic sul pulsante, sulla casella di controllo, sul pulsante di opzione o sulla voce di menu |
JTextField | |||
ItemListener | JComboBox, JList | public void addItemListener(ItemListener) | L'elemento selezionato è cambiato |
InputMethodListener | JTextField, JTextArea | public void addMethodInputListener(InputMethodListener) | Il testo nel campo di immissione è cambiato o il cursore di immissione si è spostato |
CaretListener | JTextField, JTextArea | public void addCaretListener(CaretListener) | Il cursore di immissione ha cambiato posizione |
AdjustmentListener | JScrollBar | public void addAdjustmentListener(AdjustmentListener) | Il valore del cursore di scorrimento è cambiato |
MouseMotionListener | public void addMouseMotionListener(MouseMotionListener) | il mouse si è spostato | |
WindowListener | JFrame | public void addWindowListener(WindowListener) | evento finestra |
MouseListener | public void addMouselistener(MouseListener) | eventi del mouse (clic, ingresso/uscita dall'area di un componente, pulsante premuto, rilascio) | |
FocusListener | public void addFocusListener(FocusListener) | eventi di focus (ottenuto, perso) | |
KeyListener | public void addKeyListener(KeyListener) | evento tastiera (tasto digitato, premuto, rilasciato) |
Componente | Metodo per la registrazione dei gestori di eventi |
JButton | public void addActionListener(ActionListener) |
JCheckbox | public void addItemListener(ItemListener) |
JCheckboxMenuItem | public void addItemListener(ItemListener) |
JComboBox | public void addItemListener(ItemListener) public void addActionListener(ActionListener) |
Container | public void addContainerListener(ContainerListener) |
JComponent | public void addComponentListener(ComponentListener) public void addFocusListener(FocusListener) public void addKeyListener(KeyListener) public void addMouseListener(MouseListener) public void addMouseMotionListener(MouseMotionListener) |
JFrame | public void addWindowListener(WindowListener) |
JList | public void addItemListener(ItemListener) |
JMenuItem | public void addActionListener(ActionListener) |
JPanel | come contenitore |
JScrollPane | come contenitore |
JScrollBar | public void addAdjustmentListener(AdjustmentListener) |
JTextComponent | public void addInputMethodListener(InputMethodListener) public void addCaretListener(CaretListener) |
JTextArea | come JTextComponent |
JTextField | come JTextComponent public void addActionListener(ActionListener) |
Tutti i componenti, eccetto quelli di tipo TextXXX, derivano dalla classe JComponent e quindi dispongono anche dei metodi associati a tale classe.
5.1.5. Metodi di gestione degli eventi
La tabella seguente elenca i metodi che i vari gestori di eventi devono implementare.
Interfaccia | Metodi |
ActionListener | public void actionPerformed(ActionEvent) |
AdjustmentListener | public void adjustmentValueChanged(AdjustmentEvent) |
ComponentListener | public void componenteNascosto(EventoComponente) public void componenteSpostato(EventoComponente) public void componenteRidimensionato(EventoComponente) public void componenteMostrato(EventoComponente) |
AscoltatoreContenitore | public void componenteAggiunto(EventoContenitore) public void componenteRimosso(EventoContenitore) |
AscoltatoreFocus | public void focusGained(FocusEvent) public void focusPerso(FocusEvent) |
AscoltatoreElemento | public void itemStateChanged(ItemEvent) |
KeyListener | public void keyPressed(KeyEvent) public void keyReleased(KeyEvent) public void keyTyped(KeyEvent) |
MouseListener | public void mouseClicked(MouseEvent) public void mouseEntered(MouseEvent) public void mouseExited(MouseEvent) public void mousePressed(MouseEvent) public void mouseReleased(MouseEvent) |
Ascoltatore di movimento del mouse | public void mouseDragged(MouseEvent) public void mouseMoved(MouseEvent) |
Ascoltatore di testo | public void textValueChanged(TextEvent) |
InputMethodListener | public void InputMethodTextChanged(InputMethodEvent) public void caretPositionChanged(InputMethodEvent) |
CaretListener | public void caretUpdate(CaretEvent) |
WindowListener | public void windowActivated(WindowEvent) public void finestraChiusa(EventoFinestra) public void finestraChiudendosi(EventoFinestra) public void finestraDisattivata(EventoFinestra) public void windowDeiconified(WindowEvent) public void finestraIconizzata(WindowEvent) public void finestraAperta(EventoFinestra) |
5.1.6. Classi adattatori
Come abbiamo visto con l'interfaccia WindowListener, esistono classi denominate XXXAdapter che implementano le interfacce XXXListener con metodi vuoti. Un gestore di eventi derivato da una classe XXXAdapter può quindi implementare solo un sottoinsieme dei metodi dell'interfaccia XXXListener, in particolare quelli richiesti dall'applicazione.
Supponiamo di voler gestire i clic del mouse su un componente Frame f1. Potremmo associarvi un gestore di eventi utilizzando:
e scrivere:
public class gestionnaireSouris implements MouseListener{
// we write the 5 methods of the MouseListener interface
// mouseClicked, ..., mouseReleased)
}// end of class
Dato che vogliamo gestire solo i clic del mouse, è meglio scrivere:
public class gestionnaireSouris extends MouseAdapter{
// we write a single method that handles mouse clicks
public void mouseClicked(MouseEvent evt){
…
}
}// end of class
La tabella seguente elenca le classi di adattamento per i vari gestori di eventi:
Gestore di eventi | Adattatore |
ComponentListener | ComponentAdapter |
Ascoltatore contenitore | Adattatore contenitore |
AscoltatoreFocus | AdattatoreFocus |
KeyListener | KeyAdapter |
Ascoltatore del mouse | Adattatore del mouse |
AscoltatoreMovimentoMouse | Adattatore movimento del mouse |
AscoltatoreFinestra | AdattatoreFinestra |
5.1.7. Conclusione
Abbiamo appena presentato i concetti di base della creazione di interfacce grafiche utente in Java:
- creazione di una finestra
- creazione di componenti
- associazione dei componenti alla finestra tramite un gestore di layout
- associare gestori di eventi ai componenti
Ora, invece di costruire interfacce utente grafiche "a mano" come abbiamo appena fatto, useremo JBuilder, uno strumento di sviluppo Java di Borland/Inprise, versione 4 e successive. Useremo componenti della libreria java.swing, attualmente raccomandata da Sun, il creatore di Java.
5.2. Creazione di un'interfaccia utente grafica con JBuilder
5.2.1. Il nostro primo progetto JBuilder
Per familiarizzare con JBuilder, creiamo un'applicazione molto semplice: una finestra vuota.
- Avvia JBuilder e seleziona File/Nuovo progetto. Apparirà quindi la prima pagina di una procedura guidata:

- Compilare i seguenti campi:
Nome del progetto | start Questo creerà un file di progetto denominato start.jpr nella cartella specificata nel campo "Nome directory progetto" |
Percorso principale | Specificare la cartella in cui si troverà la cartella del progetto che si sta per creare. |
Nome directory progetto | Specificare il nome della cartella in cui verranno inseriti tutti i file di progetto. Questa cartella verrà creata nella directory specificata nel campo "Percorso radice" |
I file sorgente (.java, .html, ...), i file di destinazione (.class, ...) e i file di backup possono essere collocati in directory diverse. Se si lasciano vuoti i relativi campi, verranno collocati nella stessa directory del progetto.
Fare clic su [Avanti]
- Una schermata conferma le scelte effettuate nel passaggio precedente

Fare clic su [Avanti]
- Una nuova schermata ti chiede di descrivere il tuo progetto:

Fai clic su [Fine]
- Verifica che l'opzione Visualizza/Progetto sia selezionata. Dovresti vedere la struttura del tuo progetto nel riquadro di sinistra.

- Ora creiamo un'interfaccia utente grafica in questo progetto. Selezionare l'opzione File/Nuovo/Applicazione:

Nel campo Classe, inserisci il nome della classe da creare. In questo caso, abbiamo utilizzato lo stesso nome del progetto.
Fare clic su [Avanti]
- Viene visualizzata la seguente schermata:

Interfaccia | interfaceStart Questo è il nome della classe corrispondente alla finestra che verrà creata |
Titolo | Questo è il testo che apparirà nella barra del titolo della finestra |
Si noti che sopra abbiamo specificato che la finestra deve essere centrata sullo schermo all'avvio dell'applicazione.
Fare clic su [Fine]
- È qui che JBuilder si rivela utile.
- Genera i file sorgente .java per le due classi che abbiamo denominato: la classe dell'applicazione e la classe GUI. Questi due file compaiono nella struttura del progetto nella finestra a sinistra

- Per accedere al codice generato per le due classi, è sufficiente fare doppio clic sul file .java corrispondente. Torneremo sul codice generato più avanti.
- Assicurati che l'opzione "Visualizza/Struttura" sia selezionata. Ciò ti consente di visualizzare la struttura della classe attualmente selezionata (fai doppio clic sul file .java). Ecco, ad esempio, la struttura della classe "début":

Qui apprendiamo:
-
le librerie importate (import)
-
l'esistenza di un costruttore start()
-
che esiste un metodo statico main()
-
che esiste un attributo packFrame
Qual è il vantaggio di poter accedere alla struttura di una classe?
-
Si ottiene una panoramica della stessa. Ciò è utile se la classe è complessa.
-
È possibile accedere al codice di un metodo cliccandoci sopra nella finestra della struttura della classe. Anche in questo caso, ciò è utile se la classe ha centinaia di righe. Non è necessario scorrere ogni riga per trovare il codice che si sta cercando.
Il codice generato da JBuilder è già utilizzabile. Fai clic su Esegui/Esegui progetto oppure premi F9 e vedrai la finestra che hai richiesto:

Inoltre, si chiude correttamente quando si fa clic sul pulsante di chiusura della finestra. Abbiamo appena creato la nostra prima interfaccia utente grafica. Possiamo salvare il nostro progetto utilizzando l'opzione File/Chiudi progetti:

Facendo clic su Tutti, verranno selezionati tutti i progetti nella finestra sopra. Facendo clic su OK li chiuderai. Se sei abbastanza curioso da navigare, utilizzando Esplora risorse, fino alla cartella del progetto (quella specificata nella procedura guidata all'inizio della configurazione del progetto), troverai lì i seguenti file:

Nel nostro esempio, abbiamo specificato che tutti i file (sorgente .java, output .class, backup .jpr) dovessero trovarsi nella stessa cartella del progetto .jpr.
5.2.2. File generati da JBuilder per un'interfaccia grafica
Diamo ora un'occhiata ai file sorgente .java generati da JBuilder. È importante sapere come leggere ciò che viene generato, poiché il più delle volte dovremo aggiungere codice a ciò che è già presente. Iniziamo aprendo il nostro progetto: File/Apri progetto e selezioniamo il progetto debut.jpr. Vedremo il progetto che abbiamo creato in precedenza.
5.2.2.1. La classe principale
Esaminiamo la classe début.java facendo doppio clic sul suo nome nella finestra che mostra l'elenco dei file di progetto. Abbiamo il seguente codice:
import javax.swing.UIManager;
import java.awt.*;
public class début {
boolean packFrame = false;
/**Building the application*/
public début() {
interfaceDébut frame = new interfaceDébut();
//Validate frames with predefined sizes
//Compact frames with preferred size information - e.g. from their layout
if (packFrame) {
frame.pack();
}
else {
frame.validate();
}
//Center window
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
}
/**Main method*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
e.printStackTrace();
}
new début();
}
}
Commentiamo il codice generato:
- La funzione main imposta l'aspetto della finestra (setLookAndFeel) e crea un'istanza della classe début.
- Viene quindi eseguito il costruttore début(). Esso crea un'istanza frame della classe window (new interfaceDébut()). Questa istanza viene costruita ma non visualizzata.
- La finestra viene quindi ridimensionata in base alle informazioni disponibili per ciascuno dei suoi componenti (frame.validate). Inizia quindi la sua esistenza indipendente visualizzandosi e rispondendo agli input dell'utente.
- La finestra è centrata sullo schermo perché lo abbiamo richiesto durante la configurazione della finestra con la procedura guidata.
Vediamo cosa succederebbe se riducessimo il codice di début.java al minimo indispensabile, come abbiamo fatto all'inizio del capitolo. Creiamo una nuova classe. Selezioniamo File/Nuova Classe:

Assegnate alla nuova classe il nome "start2" e fate clic su [Fine]. Nel progetto compare un nuovo file:

Il file début2.java è ridotto alla sua forma più semplice:
Completiamo la classe come segue:
public class début2 {
// main function
public static void main(String args[]){
// creates the
new interfaceDébut().show(); // or new interfaceDébut.setVisible(true);
}//hand
}//class start2
La funzione main crea un'istanza della finestra interfaceDébut e la visualizza (show). Prima di eseguire il nostro progetto, dobbiamo specificare che la classe contenente la funzione main da eseguire è ora la classe début2. Fare clic con il tasto destro del mouse sul progetto début.jpr e selezionare l'opzione Proprietà, quindi la scheda Esecuzione:
21

Qui è indicato che la classe principale è début (1). Fare clic sul pulsante (2) per selezionare una classe principale diversa:

Seleziona "début2" e clicca su [OK].

Fare clic su [OK] per confermare la scelta, quindi eseguire il progetto selezionando Esegui/Esegui progetto oppure premendo F9. Si otterrà la stessa finestra della classe "start", con la differenza che non sarà centrata poiché in questo caso non è stato richiesto. D'ora in poi non presenteremo più la classe principale generata da JBuilder poiché fa sempre la stessa cosa: creare una finestra. D'ora in poi ci concentreremo sulla classe della finestra.
5.2.2.2. La classe window
Diamo ora un'occhiata al codice generato per la classe interfaceDébut:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class interfaceDébut extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
/**Building the frame*/
public interfaceDébut() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(borderLayout1);
this.setSize(new Dimension(400, 300));
this.setTitle("Ma première interface graphique avec Jbuilder");
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
}
5.2.2.2.1. Librerie importate
Queste sono le librerie java.awt, java.awt.event e javax.swing. Le prime due erano le uniche disponibili per la creazione di interfacce utente grafiche nelle prime versioni di Java. La libreria javax.swing è più recente. In questo caso, è necessaria per la finestra JFrame utilizzata in questo esempio.
5.2.2.2.2. Gli attributi
JPanel è un tipo di contenitore in cui è possibile inserire componenti. BorderLayout è uno dei gestori di layout disponibili per posizionare i componenti all'interno del contenitore. In tutti i nostri esempi, non useremo un gestore di layout e posizioneremo noi stessi i componenti in una posizione specifica all'interno del contenitore. Per farlo, useremo il gestore di layout null.
5.2.2.2.3. Il costruttore della finestra
/**Building the frame*/
public interfaceDébut() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(borderLayout1);
this.setSize(new Dimension(400, 300));
this.setTitle("Ma première interface graphique avec Jbuilder");
}
- Il costruttore inizia dichiarando che gestirà gli eventi sulla finestra (enableEvents), quindi chiama il metodo jbInit.
- Viene ottenuto il contenitore (JPanel) della finestra (JFrame) (getContentPane)
- Viene impostato il gestore di layout (setLayout)
- Viene impostata la dimensione della finestra (setSize)
- Viene impostato il titolo della finestra (setTitle)
5.2.2.2.4. Il gestore di eventi
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
Il costruttore aveva indicato che la classe avrebbe gestito gli eventi della finestra. Il metodo processWindowEvent svolge questo compito. Inizia passando il WindowEvent ricevuto alla sua classe padre (JFrame); poi, se l'evento è WINDOW_CLOSING — attivato cliccando sul pulsante di chiusura della finestra — l'applicazione viene terminata.
5.2.2.2.5. Conclusione
Il codice per la classe della finestra differisce da quello presentato nell'esempio all'inizio del capitolo. Se stessimo utilizzando un generatore di codice Java diverso da JBuilder, probabilmente avremmo un codice ancora diverso. In pratica, accetteremo il codice generato da JBuilder per costruire la finestra, in modo da poterci concentrare esclusivamente sulla scrittura dei gestori di eventi per l'interfaccia grafica utente.
5.2.3. Disegnare una GUI
5.2.3.1. Un esempio
Nell'esempio precedente non abbiamo inserito alcun componente nella finestra. Creiamo ora una finestra con un pulsante, un'etichetta e un campo di immissione:

I campi sono i seguenti:
N. | nome | tipo | ruolo |
1 | lblInput | JLabel | un'etichetta |
2 | txtInput | JTextField | un campo di immissione |
3 | cmdDisplay | JButton | per visualizzare il contenuto del campo di testo txtSaisie in una finestra di dialogo |
Seguendo la stessa procedura del progetto precedente, compila il progetto interface2.jpr senza aggiungere per ora alcun componente alla finestra.

Nella finestra sopra riportata, seleziona la classe interface2.java. A destra di questa finestra è presente una cartella a schede:

La scheda Source consente di accedere al codice sorgente della classe interface2.java. La scheda Design consente di costruire visivamente la finestra. Selezionare questa scheda. Ora è visibile il contenitore della finestra, che ospiterà i componenti inseriti al suo interno. Al momento è vuoto. La finestra a sinistra mostra la struttura della classe:

questo | rappresenta la finestra |
contentPane | il suo contenitore, nel quale inseriremo i componenti, nonché la modalità di layout per questi componenti all'interno del contenitore (BorderLayout per impostazione predefinita) |
borderLayout1 | un'istanza del gestore di layout |
Seleziona questo oggetto. La finestra delle proprietà apparirà quindi sulla destra:

Alcune di queste proprietà meritano di essere segnalate:
background | per impostare il colore di sfondo della finestra |
foreground | per impostare il colore del testo e dei pulsanti nella finestra |
JMenuBar | per associare un menu alla finestra |
titolo | per assegnare un titolo alla finestra |
resizable | per impostare il tipo di finestra |
font | per impostare il carattere del testo nella finestra |
Con questo oggetto ancora selezionato, è possibile ridimensionare il contenitore visualizzato sullo schermo trascinando i punti di ancoraggio attorno al contenitore:

Ora siamo pronti per trascinare i componenti nel contenitore sopra. Prima di farlo, cambieremo il gestore di layout. Selezionare l'oggetto contentPane nella finestra della struttura:

Quindi, nella finestra delle proprietà di questo oggetto, seleziona la proprietà layout e scegli il valore null tra le opzioni disponibili:

L'assenza di un gestore di layout ci consentirà di posizionare liberamente i componenti all'interno del contenitore. È ora il momento di selezionarli.
Quando il pannello Design è selezionato, i componenti sono disponibili in una cartella a schede nella parte superiore della finestra di progettazione:

Per costruire l'interfaccia utente grafica, disponiamo di componenti Swing (1) e componenti AWT (2). In questo caso, useremo i componenti Swing. Nella barra dei componenti in alto, selezionate un componente JLabel (3), un componente JTextField (4) e un componente JButton (5), e posizionateli nel contenitore della finestra Design.

Ora personalizziamo ciascuno di questi tre componenti:
- l'etichetta (JLabel) jLabel1
Selezionare il componente per aprire la finestra delle Proprietà. Nella finestra delle Proprietà, modificare le seguenti proprietà: nome: lblSaisie, testo: Saisie
- il campo di testo (JTextField) jTextfield1
Seleziona il componente per aprire la finestra delle proprietà. Nella finestra, modifica le seguenti proprietà: nome: txtSaisie, testo: lascia vuoto
- il pulsante (JButton): nome: cmdAfficher, testo: Visualizza
Ora abbiamo la seguente finestra:

e la seguente struttura:

Possiamo eseguire (F9) il nostro progetto per dare una prima occhiata alla finestra in azione:

Chiudere la finestra. Dobbiamo ancora scrivere la procedura associata al clic sul pulsante Mostra. Selezionare il pulsante per accedere alla finestra delle Proprietà. Questa finestra presenta due schede: Proprietà ed Eventi. Selezionare Eventi.

La colonna di sinistra della finestra elenca i possibili eventi per il pulsante. Un clic su un pulsante corrisponde all'evento actionPerformed. La colonna di destra contiene il nome della procedura chiamata quando si verifica l'evento corrispondente. Clicca sulla cella a destra dell'evento actionPerformed:

JBuilder genera un nome predefinito per ogni gestore di eventi nel formato ComponentName_EventName, in questo caso cmdDisplay_actionPerformed. È possibile eliminare il nome predefinito e inserirne uno diverso. Per accedere al codice del gestore cmdDisplay_actionPerformed, è sufficiente fare doppio clic sul suo nome sopra. Si verrà quindi reindirizzati automaticamente al riquadro del codice sorgente della classe, posizionati sullo scheletro del codice del gestore di eventi:
Non resta che completare questo codice. In questo caso, vogliamo visualizzare una finestra di dialogo contenente il contenuto del campo txtSaisie:
void cmdAfficher_actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(),
"Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
}
JOptionPane è una classe della libreria javax.swing. Consente di visualizzare messaggi accompagnati da un'icona o di richiedere informazioni all'utente. In questo caso, stiamo utilizzando un metodo statico della classe:

parentComponent | l'oggetto contenitore "parent" della finestra di dialogo: in questo caso, this. |
message | un oggetto da visualizzare. In questo caso, il contenuto del campo di immissione |
titolo | il titolo della finestra di dialogo |
messageType | il tipo di messaggio da visualizzare. Determina l'icona che verrà visualizzata nella casella accanto al messaggio. Valori possibili: INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE |
Eseguiamo la nostra applicazione (F9):


5.2.3.2. Il codice della classe della finestra
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;
public class interface2 extends JFrame {
JPanel contentPane;
JLabel lblSaisie = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmdAfficher = new JButton();
/**Building the frame*/
public interface2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
lblSaisie.setText("Saisie");
lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(304, 129));
this.setTitle("Saisies & boutons - 1");
txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
cmdAfficher.setText("Afficher");
cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
contentPane.add(lblSaisie, null);
contentPane.add(txtSaisie, null);
contentPane.add(cmdAfficher, null);
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void cmdAfficher_actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
}
}
5.2.3.2.1. Gli attributi
JPanel contentPane;
JLabel lblSaisie = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmdAfficher = new JButton();
Qui abbiamo il contenitore di componenti JPanel e i tre componenti.
5.2.3.2.2. Il costruttore
/**Building the frame*/
public interface2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
lblSaisie.setText("Saisie");
lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(304, 129));
this.setTitle("Saisies & boutons - 1");
txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
cmdAfficher.setText("Afficher");
cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
contentPane.add(lblSaisie, null);
contentPane.add(txtSaisie, null);
contentPane.add(cmdAfficher, null);
}
Il costruttore di interface2 è simile al costruttore dell'interfaccia grafica che abbiamo studiato in precedenza. Le differenze si trovano nel metodo jbInit: il codice di costruzione della finestra dipende dai componenti che vi sono inseriti. Possiamo riutilizzare il codice jbInit aggiungendo i nostri commenti:
private void jbInit() throws Exception {
// the window itself (size, title)
this.setSize(new Dimension(304, 129));
this.setTitle("Saisies & boutons - 1");
// the component container
contentPane = (JPanel) this.getContentPane();
// no formatting manager for this container
contentPane.setLayout(null);
// label lblSaisie (label, position, size)
lblSaisie.setText("Saisie");
lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
// input field (position, size)
txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
// display button (label, position, size)
cmdAfficher.setText("Afficher");
cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
// button event manager
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
// add the 3 components to the container
contentPane.add(lblSaisie, null);
contentPane.add(txtSaisie, null);
contentPane.add(cmdAfficher, null);
}//jbInit
Due punti meritano di essere sottolineati:
- questo codice avrebbe potuto essere scritto a mano. Ciò significa che JBuilder non è indispensabile per creare un'interfaccia utente grafica.
- il modo in cui è impostato il gestore di eventi per il pulsante cmdAfficher. Il gestore di eventi per il componente cmdAfficher avrebbe potuto essere dichiarato utilizzando `cmdAfficher.addActionListener(new handler())`, dove `handler` sarebbe una classe con un metodo pubblico `actionPerformed` incaricato di gestire il clic sul pulsante Mostra. In questo caso, JBuilder utilizza un'istanza di una classe anonima come gestore:
new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
Viene creata una nuova istanza dell'interfaccia ActionListener con il metodo actionPerformed definito al momento. Questo metodo chiama semplicemente un metodo della classe interface2. Tutto questo è solo una soluzione alternativa per definire le procedure di gestione degli eventi per i componenti della finestra all'interno della stessa classe della finestra stessa. Potremmo farlo in modo diverso:
il che fa sì che il metodo actionPerformed venga cercato in this, ovvero nella classe della finestra. Questo secondo metodo sembra più semplice, ma il primo presenta un vantaggio: consente di utilizzare gestori diversi per pulsanti diversi, mentre il secondo metodo non lo permette. In quest'ultimo caso, l'unico metodo actionPerformed deve gestire i clic provenienti da pulsanti diversi e quindi deve prima identificare quale pulsante ha attivato l'evento prima di poter iniziare l'elaborazione.
5.2.3.2.3. Gestori di eventi
Vediamo quelli che abbiamo già trattato:
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
// click on View button
void cmdAfficher_actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
}
5.2.3.3. Conclusione
Dai due progetti studiati, possiamo concludere che una volta che l'interfaccia utente grafica è stata realizzata con JBuilder, il compito dello sviluppatore è quello di scrivere i gestori di eventi per gli eventi che desidera gestire per quell'interfaccia utente grafica.
5.2.4. Richiesta di assistenza
Con Java, spesso è necessario ricorrere all'aiuto, in particolare a causa dell'elevato numero di classi disponibili. Ecco alcuni suggerimenti per trovare informazioni su una classe. Selezionare l'opzione Aiuto/Argomenti della guida dal menu.

La schermata della Guida presenta generalmente due finestre:
- quella di sinistra, dove si inserisce ciò che si sta cercando. Presenta tre schede: Indice, Indice analitico e Ricerca.
- la finestra a destra, che mostra i risultati della ricerca
È disponibile una guida su come utilizzare il sistema di aiuto di JBuilder. Nella guida di JBuilder, selezionare l'opzione Aiuto/Utilizzo della guida. Qui verrà spiegato come utilizzare il sistema di aiuto. Ad esempio, verranno mostrati i diversi componenti del visualizzatore della guida:

Diamo un'occhiata più da vicino alle pagine Indice e Indice analitico.
5.2.4.1. Guida: Indice

5.2.4.1.1. Indice: Introduzione a Java
Qui troverai le nozioni di base su Java, ma non solo, come dimostra l'elenco degli argomenti trattati in questa sezione:

5.2.4.1.2. Indice: Tutorial
Se selezioniamo l'opzione Tutorial nell'indice qui sopra, la finestra a destra mostra un elenco dei tutorial disponibili:

I tutorial di base sono particolarmente utili per iniziare a utilizzare JBuilder. Oltre a quelli mostrati sopra, ce ne sono molti altri e, quando si desidera sviluppare un'applicazione, può essere utile verificare prima se esiste un tutorial che possa essere d'aiuto.
5.2.4.1.3. Contenuti: Il JDK
Selezionando l'opzione Java 2 JDK 1.3, si ha accesso a tutte le librerie JDK. In genere, questo non è il posto giusto dove cercare se si hanno bisogno di informazioni su una classe specifica e non si sa in quale libreria si trovi. Tuttavia, questa opzione è utile se si è interessati a ottenere una panoramica delle librerie Java.
5.2.4.2. Aiuto: Indice
Selezionare la scheda Indice nel riquadro sinistro della finestra Aiuto. Questa opzione consente, ad esempio, di trovare la guida relativa a una classe. Supponiamo, ad esempio, di voler conoscere i metodi dei campi di immissione JTextField di Swing. Digitare JTextField nel campo di ricerca:
![]()
La Guida restituirà le voci dell'indice che iniziano con il testo digitato:

Basta fare doppio clic sulla voce che ti interessa, in questo caso la classe JTextField. La guida relativa a questa classe apparirà quindi nella finestra a destra:

Viene quindi fornita una descrizione completa della classe.
5.2.5. Alcuni componenti Swing
Presenteremo ora varie applicazioni che utilizzano i componenti Swing più comuni per esplorarne i metodi e le proprietà principali. Per ciascuna applicazione, presenteremo l'interfaccia grafica e il codice pertinente, in particolare quello dei gestori di eventi.
5.2.5.1. Componenti JLabel e JTextField
Abbiamo già incontrato questi due componenti. JLabel è un componente di testo e JTextField è un componente campo di immissione. I loro due metodi principali sono
String getText() | per recuperare il contenuto del campo di immissione o il testo dell'etichetta |
void setText(String text) | per impostare il testo nel campo o nell'etichetta |
Gli eventi comunemente utilizzati per JTextField sono i seguenti:
actionPerformed | indica che l'utente ha confermato (premendo Invio) il testo inserito |
caretUpdate | indica che l'utente ha spostato il cursore di immissione |
inputMethodChanged | indica che l'utente ha modificato il campo di immissione |
Ecco un esempio che utilizza l'evento caretUpdate per tenere traccia delle modifiche in un campo di immissione:

No. | tipo | nome | ruolo |
1 | JTextField | txtInput | campo di immissione |
2 | JTextField | txtControl | visualizza il testo di 1 in tempo reale |
3 | JButton | cmdClear | per cancellare i campi 1 e 2 |
4 | JButton | cmdExit | per uscire dall'applicazione |
Il codice relativo a questa applicazione è il seguente:
import java.awt.*;
....
public class Cadre1 extends JFrame {
JPanel contentPane;
JTextField txtSaisie = new JTextField();
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JTextField txtControle = new JTextField();
JButton CmdEffacer = new JButton();
JButton CmdQuitter = new JButton();
/**Building the frame*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
....
txtSaisie.addCaretListener(new javax.swing.event.CaretListener() {
public void caretUpdate(CaretEvent e) {
txtSaisie_caretUpdate(e);
}
});
...
CmdEffacer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
CmdEffacer_actionPerformed(e);
}
});
...
CmdQuitter.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
CmdQuitter_actionPerformed(e);
}
});
....
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_caretUpdate(CaretEvent e) {
// the input cursor has moved
txtControle.setText(txtSaisie.getText());
}
void CmdQuitter_actionPerformed(ActionEvent e) {
// quit the application
System.exit(0);
}
void CmdEffacer_actionPerformed(ActionEvent e) {
// delete the contents of the input field
txtSaisie.setText("");
}
}
Ecco un esempio di esecuzione:

5.2.5.2. Componente JComboBox


Un componente JComboBox è un elenco a discesa combinato con un campo di immissione: l'utente può selezionare un elemento da (2) o digitare del testo in (1). Per impostazione predefinita, i JComboBox non sono modificabili. È necessario chiamare esplicitamente il metodo setEditable(true) per renderli modificabili. Per ulteriori informazioni sulla classe JComboBox, digitare JComboBox nell'indice della guida.
L'oggetto JComboBox può essere creato in diversi modi:
new JComboBox() | crea una casella combinata vuota |
new JComboBox (Object[] items) | crea una casella combinata contenente un array di oggetti |
new JComboBox(Vector items) | come sopra, ma con un vettore di oggetti |
Potrebbe sembrare sorprendente che una casella combinata possa contenere oggetti quando solitamente contiene stringhe. Visivamente, è proprio così. Se una JComboBox contiene un oggetto obj, visualizza la stringa obj.toString(). Ricordiamo che ogni oggetto ha un metodo toString ereditato dalla classe Object, che restituisce una stringa che "rappresenta" l'oggetto.
I metodi utili della classe JComboBox sono i seguenti:
void addItem(Object anObject) | aggiunge un oggetto alla casella combinata |
int getItemCount() | restituisce il numero di elementi nel menu a tendina |
Object getItemAt(int i) | restituisce l'i-esimo oggetto nella casella combinata |
void insertItemAt(Object anObject, int i) | Inserisce unOggetto nella posizione i nel menu a discesa |
int getSelectedIndex() | restituisce l'indice dell'elemento selezionato nella casella combinata |
Object getSelectedItem() | restituisce l'elemento selezionato nella casella combinata |
void setSelectedIndex(int i) | seleziona l'elemento i nella casella combinata |
void setSelectedItem(Object anObject) | seleziona l'oggetto specificato nella casella combinata |
void removeAllItems() | cancella la casella combinata |
void removeItemAt(int i) | rimuove l'elemento numero i dalla casella combinata |
void removeItem(Object anObject) | rimuove l'oggetto specificato dalla casella combinata |
void setEditable(boolean val) | rende la casella combinata modificabile (val=true) o meno (val=false) |
Quando viene selezionato un elemento dall'elenco a discesa, viene attivato l'evento actionPerformed, che può quindi essere utilizzato per rilevare la modifica nella selezione all'interno della casella combinata. Nell'applicazione seguente, utilizziamo questo evento per visualizzare l'elemento selezionato dall'elenco.

Mostriamo solo il codice rilevante per la finestra.
public class Cadre1 extends JFrame {
JPanel contentPane;
JComboBox jComboBox1 = new JComboBox();
JLabel jLabel1 = new JLabel();
/**Building the frame*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// treatment - fill the combo
String[] infos={"un","deux","trois","quatre"};
for(int i=0;i<infos.length;i++)
jComboBox1.addItem(infos[i]);
}
/**Initialize component*/
private void jbInit() throws Exception {
....
jComboBox1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jComboBox1_actionPerformed(e);
}
});
....
}
void jComboBox1_actionPerformed(ActionEvent e) {
// a new element has been selected - it is displayed
JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
}
}
5.2.5.3. Componente JList
Il componente JList di Swing è più complesso rispetto alla sua controparte nella libreria AWT. Esistono due differenze importanti:
- Il contenuto dell'elenco è gestito da un oggetto separato dall'elenco stesso. In questo caso, useremo un oggetto DefaultListModel, che funziona come un Vector ma notifica anche all'oggetto JList ogni volta che il suo contenuto cambia, in modo che la visualizzazione dell'elenco si aggiorni di conseguenza.
- Per impostazione predefinita, l'elenco non è scorrevole. È necessario inserire l'elenco all'interno di un contenitore ScrollPane, che abilita lo scorrimento.
Nel codice sorgente, un elenco può essere definito come segue:
// the vector of list values
DefaultlistModel valeurs=new DefaultListModel();
// the list itself, to which we associate the vector of its values
JList jList1 = new JList(valeurs);
// the scrolling container in which the list is placed to obtain a scrolling list
JScrollPane jScrollPane1 = new JScrollPane(jList1);
Per includere l'elenco jList1 nel contenitore jScrollPane1, il codice generato da JBuilder procede in modo diverso:
- dichiarazione del contenitore negli attributi della finestra
- Quindi, nel codice jbInit, l'elenco viene aggiunto al contenitore
Per aggiungere valori all'elenco JList1 sopra riportato, è sufficiente aggiungerli al suo array di valori:
e vedrai quindi la seguente finestra:

Come è stata realizzata questa interfaccia?
- Selezionare un componente JScrollPane dalla pagina "Swing Containers" dei componenti e trascinarlo nella finestra, ridimensionandolo alle dimensioni desiderate
- Seleziona un componente JList dalla pagina "Swing" dei componenti e rilascialo nel contenitore JScrollPane, dove occuperà l'intero spazio.
Il codice generato da JBuilder deve essere leggermente modificato per ottenere il seguente codice:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
DefaultListModel valeurs=new DefaultListModel();
JList jList1 = new JList(valeurs);
JScrollPane jScrollPane1 = new JScrollPane();
JLabel jLabel2 = new JLabel();
/**Building the frame*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// treatment
// include the list in the scrollPane
// init list
for(int i=0;i<10;i++)
valeurs.addElement(""+i);
}
/**Initialize component*/
private void jbInit() throws Exception {
....
// the jList1 list is associated with the jcrollPane1 container
jScrollPane1.getViewport().add(jList1, null);
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
....
}
}
Esploriamo ora i metodi principali della classe JList cercando JList nell'indice della guida. L'oggetto JList può essere creato in vari modi:

Un metodo semplice è quello che abbiamo utilizzato: creare un DefaultListModel V vuoto e poi associarlo alla lista da creare utilizzando new JList(V). Il contenuto della lista non è gestito dall’oggetto JList ma dall’oggetto contenente i valori della lista. Se il contenuto è stato costruito utilizzando un oggetto DefaultListModel basato sulla classe Vector, i metodi della classe Vector possono essere utilizzati per aggiungere, inserire e rimuovere elementi dalla lista. Un elenco può supportare la selezione singola o multipla. Ciò viene impostato dal metodo setSelectionMode:

È possibile determinare la modalità di selezione corrente utilizzando getSelectionMode:
![]()
È possibile ottenere gli elementi selezionati utilizzando i seguenti metodi:

Sappiamo come associare un vettore di valori a un elenco utilizzando il costruttore JList(DefaultListModel). Viceversa, possiamo ottenere l'oggetto DefaultListModel da un JList in questo modo:

Ora sappiamo abbastanza per scrivere la seguente applicazione:

I componenti di questa finestra sono i seguenti:
No. | tipo | nome | ruolo |
1 | JTextField | txtInput | campo di immissione |
2 | JList | jList1 | elenco contenuto in un contenitore jScrollPane1 |
3 | JList | jList2 | elenco contenuto in un contenitore jScrollPane2 |
4 | JButton | cmd1To2 | trasferisce gli elementi selezionati dall'elenco 1 all'elenco 2 |
5 | JButton | cmd2To1 | fa l'opposto |
6 | JButton | cmdRaz1 | cancella la lista 1 |
7 | JButton | cmdRaz2 | cancella la lista 2 |
L'utente digita del testo nel campo (1) e lo invia. Questo attiva l'evento actionPerformed sul campo di immissione, che viene utilizzato per aggiungere il testo inserito all'elenco 1. Ecco il codice per questa prima funzione:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmd1To2 = new JButton();
JButton cmd2To1 = new JButton();
DefaultListModel v1=new DefaultListModel();
DefaultListModel v2=new DefaultListModel();
JList jList1 = new JList(v1);
JList jList2 = new JList(v2);
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JButton cmdRaz1 = new JButton();
JButton cmdRaz2 = new JButton();
JLabel jLabel4 = new JLabel();
/**Building the frame*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**Initialize component*/
private void jbInit() throws Exception {
...
txtSaisie.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtSaisie_actionPerformed(e);
}
});
...
// Jlist1 is placed in the jScrollPane1 container
jScrollPane1.getViewport().add(jList1, null);
// Jlist2 is placed in the jScrollPane2 container
jScrollPane2.getViewport().add(jList2, null);
...
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_actionPerformed(ActionEvent e) {
// the input text has been validated
// we recover it free of its start and end spaces
String texte=txtSaisie.getText().trim();
// if it's empty, we don't want it
if(texte.equals("")){
// error msg
JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
"Erreur",JOptionPane.WARNING_MESSAGE);
// end
return;
}//if
// if it is not empty, it is added to the values in list 1
v1.addElement(texte);
// and empty the input field
txtSaisie.setText("");
}/// txtSaisie_actionperformed
}//class
Il codice per trasferire gli elementi selezionati da un elenco all'altro è il seguente:
void cmd1To2_actionPerformed(ActionEvent e) {
// transfer items selected in list 1 to list 2
transfert(jList1,jList2);
}//cmd1To2
void cmd2To1_actionPerformed(ActionEvent e) {
// transfer selected items in jList2 to jList1
transfert(jList2,jList1);
}//cmd2TO1
private void transfert(JList L1, JList L2){
// transfer items selected in list 1 to list 2
// retrieve the array of indices of the elements selected in L1
int[] indices=L1.getSelectedIndices();
// anything to do?
if (indices.length==0) return;
// we retrieve the values of L1
DefaultListModel v1=(DefaultListModel)L1.getModel();
// and L2
DefaultListModel v2=(DefaultListModel)L2.getModel();
for(int i=indices.length-1;i>=0;i--){
// the values selected in L1 are added to L2
v2.addElement(v1.elementAt(indices[i]));
// l1 elements copied into L2 must be deleted from L1
v1.removeElementAt(indices[i]);
}//for
}//transfer
Il codice associato ai pulsanti Raz è molto semplice:
void cmdRaz1_actionPerformed(ActionEvent e) {
// empty list 1
v1.removeAllElements();
}//cmd Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// empty list 2
v2.removeAllElements();
}///cmd Raz2
5.2.5.4. Caselle di controllo JCheckBox, pulsanti di opzione JButtonRadio
Proponiamo di scrivere la seguente applicazione:

I componenti della finestra sono i seguenti:
N. | tipo | nome | ruolo |
1 | JButtonRadio | jButtonRadio1 jButtonRadio2 jButtonRadio3 | 3 pulsanti di opzione che fanno parte del gruppo buttonGroup1 |
2 | JCheckBox | jCheckBox1 jCheckBox2 jCheckBox3 | 3 caselle di controllo |
3 | JList | jList1 | un elenco in un contenitore jScrollPane1 |
4 | ButtonGroup | buttonGroup1 | componente non visibile - utilizzato per raggruppare i tre pulsanti di opzione in modo che, quando uno viene selezionato, gli altri vengano deselezionati. |
È possibile creare un gruppo di pulsanti di opzione come segue:
- Posizionare ciascun pulsante di opzione senza preoccuparsi di raggrupparli
- Inserire un componente Swing ButtonGroup nel contenitore. Questo componente è non visivo. Pertanto non appare nel window designer. Tuttavia, appare nella sua struttura:

In alto, nel ramo Altro, è possibile vedere gli attributi non visivi della finestra. Una volta creato un gruppo di pulsanti di opzione, è possibile associarvi ciascun pulsante di opzione. Per farlo, selezionare le proprietà del pulsante di opzione:

e nella proprietà buttonGroup del pulsante di opzione, inserisci il nome del gruppo in cui desideri inserire il pulsante di opzione, in questo caso buttonGroup1. Ripeti questo passaggio per tutti e 3 i pulsanti di opzione.
Il metodo principale per i pulsanti di opzione e le caselle di controllo è il metodo isSelected(), che indica se la casella di controllo o il pulsante è selezionato. Il testo associato al componente può essere recuperato utilizzando getText() e impostato utilizzando setText(String text). La casella di controllo o il pulsante di opzione possono essere selezionati utilizzando il metodo setSelected(boolean value).
Quando si fa clic su un pulsante di opzione o su una casella di controllo, viene attivato l'evento actionPerformed. Nel codice seguente, utilizziamo questo evento per tenere traccia delle modifiche nei valori dei pulsanti di opzione e delle caselle di controllo:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JRadioButton jRadioButton1 = new JRadioButton();
JRadioButton jRadioButton2 = new JRadioButton();
JRadioButton jRadioButton3 = new JRadioButton();
JCheckBox jCheckBox1 = new JCheckBox();
JCheckBox jCheckBox2 = new JCheckBox();
JCheckBox jCheckBox3 = new JCheckBox();
ButtonGroup buttonGroup1 = new ButtonGroup();
JScrollPane jScrollPane1 = new JScrollPane();
DefaultListModel valeurs=new DefaultListModel();
JList jList1 = new JList(valeurs);
/**Building the frame*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
jRadioButton1.setSelected(true);
jRadioButton1.setText("un");
jRadioButton1.setBounds(new Rectangle(57, 31, 49, 23));
jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheRadioButtons(e);
}
});
jRadioButton2.setBounds(new Rectangle(113, 30, 49, 23));
jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheRadioButtons(e);
}
});
jRadioButton2.setText("deux");
jRadioButton3.setBounds(new Rectangle(168, 30, 49, 23));
jRadioButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheRadioButtons(e);
}
});
jRadioButton3.setText("trois");
// radio buttons are grouped together
buttonGroup1.add(jRadioButton1);
buttonGroup1.add(jRadioButton2);
buttonGroup1.add(jRadioButton3);
// checkboxes
jCheckBox1.setText("A");
jCheckBox1.setBounds(new Rectangle(58, 69, 32, 17));
jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheCases(e);
}
});
jCheckBox2.setBounds(new Rectangle(112, 69, 40, 17));
jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheCases(e);
}
});
jCheckBox2.setText("B");
jCheckBox3.setText("C");
jCheckBox3.setBounds(new Rectangle(170, 69, 37, 17));
jCheckBox3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheCases(e);
}
});
....
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
...
}
private void afficheRadioButtons(ActionEvent e){
// displays the values of the 3 radio buttons
valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
}//afficheRadioButtons
void afficheCases(ActionEvent e) {
// displays checkbox values
valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
}//afficheCases
}//class
Ecco un esempio di esecuzione:

5.2.5.5. Componente JScrollBar
Creiamo la seguente applicazione:

No. | Tipo | nome | ruolo |
1 | JScrollBar | jScrollBar1 | una barra di scorrimento orizzontale |
2 | JScrollBar | jScrollBar2 | un cursore verticale |
3 | JTextField | txtvalueHS | visualizza il valore del cursore orizzontale 1 - permette anche di impostare questo valore |
4 | JTextField | txtVSvalue | visualizza il valore del cursore verticale 2 - permette anche di impostare questo valore |
- Un cursore JScrollBar consente all'utente di selezionare un valore da un intervallo di valori interi rappresentati dalla "barra" del cursore, lungo la quale si sposta un cursore.
- Per un cursore orizzontale, l'estremità sinistra rappresenta il valore minimo dell'intervallo, quella destra il valore massimo e il cursore il valore attualmente selezionato. Per un cursore verticale, il minimo è rappresentato dall'estremità superiore e il massimo da quella inferiore. La coppia (min,max) è impostata di default su (0,100).
- Facendo clic sulle estremità del cursore, il valore cambia di un incremento (positivo o negativo) a seconda dell'estremità cliccata, come definito dal parametro unitIncrement, il cui valore predefinito è 1.
- Cliccando su uno dei lati del cursore il valore cambia di un incremento (positivo o negativo) a seconda dell’estremità cliccata, noto come blockIncrement, il cui valore predefinito è 10.
- Questi cinque valori (min, max, value, unitIncrement, blockIncrement) possono essere recuperati utilizzando i metodi getMinimum(), getMaximum(), getValue(), getUnitIncrement() e getBlockIncrement(), che restituiscono tutti un numero intero, e possono essere impostati utilizzando i metodi setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc) e setBlockIncrement(int bInc)
Ci sono alcune cose da sapere quando si utilizzano i componenti JScrollBar. Innanzitutto, si trovano nella tavolozza dei componenti Swing:

Quando lo si trascina sul contenitore, per impostazione predefinita è verticale. È possibile renderlo orizzontale utilizzando la proprietà orientation riportata di seguito:

Nella finestra delle proprietà qui sopra, puoi vedere che hai accesso alle proprietà minimum, maximum, value, unitIncrement e blockIncrement della JScrollBar. Puoi quindi impostarle in fase di progettazione. Quando inserisci una barra di scorrimento nel contenitore, la sua "barra di scorrimento" non viene visualizzata:

È possibile risolvere questo problema aggiungendo un bordo al componente. Ciò avviene utilizzando la sua proprietà border, che può assumere vari valori:

Ecco un esempio di RaisedBevel:
![]()
Quando si fa clic sull'estremità superiore di un cursore verticale, il suo valore diminuisce. Ciò potrebbe sorprendere l'utente medio, che normalmente si aspetta di vedere il valore "aumentare". Risolviamo questo problema impostando unitIncrement e blockIncrement su valori negativi.
Come si monitorano le modifiche a un cursore? Quando il suo valore cambia, viene attivato l'evento adjustmentValueChanged. È sufficiente associare una procedura a questo evento per ricevere una notifica ogni volta che il valore della barra di scorrimento cambia.

Il codice pertinente per la nostra applicazione è il seguente:
....
public class cadreAppli extends JFrame {
JPanel contentPane;
JScrollBar jScrollBar1 = new JScrollBar();
Border border1;
JTextField txtValeurHS = new JTextField();
JScrollBar jScrollBar2 = new JScrollBar();
JTextField txtValeurVS = new JTextField();
TitledBorder titledBorder1;
/**Building the frame*/
public cadreAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
...
// a border for scrollbars
border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
// no border title
titledBorder1 = new TitledBorder("");
jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
jScrollBar1.setBorder(BorderFactory.createRaisedBevelBorder());
jScrollBar1.setAutoscrolls(true);
jScrollBar1.setBounds(new Rectangle(37, 17, 218, 20));
jScrollBar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
jScrollBar1_adjustmentValueChanged(e);
}
});
txtValeurHS.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtValeurHS_actionPerformed(e);
}
});
jScrollBar2.setBounds(new Rectangle(39, 51, 30, 27));
jScrollBar2.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
jScrollBar2_adjustmentValueChanged(e);
}
});
jScrollBar2.setAutoscrolls(true);
jScrollBar2.setUnitIncrement(-1);
jScrollBar2.setBorder(BorderFactory.createRaisedBevelBorder());
txtValeurVS.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtValeurVS_actionPerformed(e);
}
});
......
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
...
}
void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
// the value of scrollbar 1 has changed
txtValeurHS.setText(""+jScrollBar1.getValue());
}
void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
// scrollbar 2 value has changed
txtValeurVS.setText(""+jScrollBar2.getValue());
}
void txtValeurHS_actionPerformed(ActionEvent e) {
// set the horizontal scrollbar value
setValeur(jScrollBar1,txtValeurHS);
}
void txtValeurVS_actionPerformed(ActionEvent e) {
// set the vertical scrollbar value
setValeur(jScrollBar2,txtValeurVS);
}
private void setValeur(JScrollBar jS, JTextField jT){
// sets the scrollbar value jS with the field text jT
int valeur=0;
try{
valeur=Integer.parseInt(jT.getText());
jS.setValue(valeur);
}
catch (Exception e){
// error is displayed
afficher(""+e);
}//try-catch
}//setValeur
void afficher(String message){
// displays a message in a box
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//display
}
Ecco un esempio di esecuzione:

5.2.5.6. Componente JTextArea
Il componente JTextArea consente di inserire più righe di testo, a differenza del componente JTextField, in cui è possibile inserire solo una singola riga. Se questo componente viene inserito in un contenitore scorrevole (JScrollPane), si ottiene un campo di immissione testo scorrevole. Questo tipo di componente può essere presente, ad esempio, in un'applicazione di posta elettronica in cui il testo del messaggio da inviare viene digitato in un componente JTextArea. I metodi standard sono String getText() per recuperare il contenuto dell'area di testo, setText(String text) per impostare il testo nell'area di testo e append(String text) per aggiungere testo a quello già presente nell'area di testo. Si consideri la seguente applicazione:

No. | tipo | nome | ruolo |
1 | JTextArea | txtText | un'area di testo multilinea |
2 | JButton | cmdDisplay | visualizza il contenuto di 1 in una finestra di dialogo |
3 | JButton | cmdClear | cancella il contenuto di 1 |
4 | JTextField | txtAdd | testo aggiunto al testo in 1 quando convalidato premendo il tasto Invio. |
5 | JScrollPane | jScrollPane1 | contenitore scorrevole in cui è stata inserita la casella di testo 1 per creare una casella di testo scorrevole. |
Il codice pertinente è il seguente:
.....
public class cadreAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JButton cmdAfficher = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea txtTexte = new JTextArea();
JLabel jLabel2 = new JLabel();
JTextField txtAjout = new JTextField();
JButton cmdEffacer = new JButton();
/**Building the frame*/
public cadreAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
txtAjout.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtAjout_actionPerformed(e);
}
});
cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdEffacer_actionPerformed(e);
}
});
.......
jScrollPane1.getViewport().add(txtTexte, null);
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
........
}
void cmdAfficher_actionPerformed(ActionEvent e) {
// displays the contents of TextArea
afficher(txtTexte.getText());
}
void afficher(String message){
// displays a message in a box
JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
}// display
void cmdEffacer_actionPerformed(ActionEvent e) {
txtTexte.setText("");
}//cmdEffacer_actionPerformed
void txtAjout_actionPerformed(ActionEvent e) {
// add text
txtTexte.append(txtAjout.getText());
// raz addition
txtAjout.setText("");
}//
}
5.2.6. Eventi del mouse
Quando si disegna in un contenitore, è importante conoscere la posizione del mouse, ad esempio per visualizzare un punto quando viene cliccato. I movimenti del mouse attivano eventi nel contenitore all'interno del quale si muove. Ecco, ad esempio, quelli forniti da JBuilder per un contenitore JPanel:

mouseClicked | clic del mouse |
mouseDragged | il mouse si sta spostando, pulsante sinistro premuto |
mouseEntered | il mouse è appena entrato nell'area del contenitore |
mouseExited | il mouse ha appena lasciato l'area del contenitore |
mouseMoved | il mouse si sta muovendo |
mousePressed | Tasto sinistro del mouse premuto |
mouseReleased | Tasto sinistro del mouse rilasciato |
Ecco un programma che ti aiuterà a capire meglio quando si verificano i vari eventi del mouse:

N. | Tipo | nome | ruolo |
1 | JTextField | txtPosition | per visualizzare la posizione del mouse nel contenitore (eventualmente MouseMoved) |
2 | JList | lstDisplay | per visualizzare eventi del mouse diversi da MouseMoved |
3 | JButton | cmdClear | per cancellare il contenuto di 2 |
Quando si esegue questo programma, ecco cosa si ottiene con un clic:

Gli eventi vengono impilati a partire dall'inizio dell'elenco. Pertanto, lo screenshot sopra mostra che un clic attiva tre eventi, nel seguente ordine:
- MousePressed quando si preme il pulsante
- MouseReleased quando il pulsante viene rilasciato
- MouseClicked, che indica che la sequenza dei due eventi precedenti è considerata un clic. Potrebbe trattarsi di un doppio clic. Tuttavia, l'informazione clickCount=1 sopra riportata indica che si tratta di un clic singolo.
Ora, se clicchi sul pulsante, sposti il mouse e rilasci il pulsante:

Qui vediamo i tre eventi:
- MousePressed quando il pulsante viene premuto inizialmente
- MouseDragged quando si sposta il mouse tenendo premuto il pulsante
- MouseReleased quando si rilascia il pulsante
Nei due esempi sopra riportati, vediamo che un evento del mouse trasporta varie informazioni, comprese le coordinate del mouse (x,y), ad esempio (408,65) nella prima riga sopra.
Se procediamo in questo modo, scopriamo che l'evento MouseExited viene attivato non appena il mouse esce dal contenitore o si sposta su uno dei suoi componenti. In quest'ultimo caso, il contenitore riceve l'evento MouseExited e il componente riceve l'evento MouseEntered. Si verificherà il contrario quando il mouse lascerà il componente per tornare al contenitore.
Cosa succede durante un doppio clic?

Otteniamo esattamente gli stessi eventi di un singolo clic. L'unica differenza è che l'evento porta l'informazione clickCount=2 (vedi sopra), indicando che si è effettivamente verificato un doppio clic.
Il codice pertinente per questa applicazione è il seguente:
public class Cadre1 extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JTextField txtPosition = new JTextField();
JScrollPane jScrollPane1 = new JScrollPane();
DefaultListModel valeurs=new DefaultListModel();
JList lstAffichage = new JList(valeurs);
JButton cmdEffacer = new JButton();
/**Building the frame*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
contentPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
contentPane_mouseMoved(e);
}
public void mouseDragged(MouseEvent e) {
contentPane_mouseDragged(e);
}
});
contentPane.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(MouseEvent e) {
contentPane_mouseEntered(e);
}
public void mouseExited(MouseEvent e) {
contentPane_mouseExited(e);
}
public void mousePressed(MouseEvent e) {
contentPane_mousePressed(e);
}
public void mouseClicked(MouseEvent e) {
contentPane_mouseClicked(e);
}
public void mouseReleased(MouseEvent e) {
contentPane_mouseReleased(e);
}
});
cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdEffacer_actionPerformed(e);
}
});
jScrollPane1.getViewport().add(lstAffichage, null);
...............
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
.........
}
void contentPane_mouseMoved(MouseEvent e) {
txtPosition.setText("("+e.getX()+","+e.getY()+")");
}
void contentPane_mouseDragged(MouseEvent e) {
afficher(e);
}
void contentPane_mouseEntered(MouseEvent e) {
afficher(e);
}
void afficher(MouseEvent e){
// displays the event in the lstAffichage list
valeurs.insertElementAt(e,0);
}
void contentPane_mouseExited(MouseEvent e) {
afficher(e);
}
void contentPane_mousePressed(MouseEvent e) {
afficher(e);
}
void contentPane_mouseClicked(MouseEvent e) {
afficher(e);
}
void contentPane_mouseReleased(MouseEvent e) {
afficher(e);
}
void cmdEffacer_actionPerformed(ActionEvent e) {
// deletes the list
valeurs.removeAllElements();
}
}
5.2.7. Creazione di una finestra con un menu
Ora vediamo come creare una finestra con un menu utilizzando JBuilder. Creeremo la seguente finestra:


Creare un nuovo progetto partendo da una finestra vuota. Dall'elenco dei componenti "Swing Containers", selezionare il componente JMenuBar (vedere la Figura 1 qui sotto) e trascinarlo sulla finestra che si sta progettando.

Nella finestra di progettazione non viene visualizzato nulla, ma il componente JMenuBar compare nel pannello della struttura della finestra:

Fai doppio clic sull'elemento jMenuBar1 sopra per accedere al menu in modalità di progettazione:

1 | Inserisci una voce di menu |
2 | Inserisci un separatore |
3 | Inserisci un menu annidato |
4 | Rimuovere una voce di menu |
5 | Disabilitare una voce di menu |
6 | Voce di menu con casella di controllo |
7 | Attiva/disattiva il pulsante di opzione |
Per creare la tua prima voce di menu, digita "Opzioni A" nella casella A sopra, poi sotto nel seguente ordine: A1, A2, separatore, A3, A4.

Quindi accanto ad essa:

Utilizza lo strumento 3 per indicare che B3 è un sottomenu annidato.
Man mano che progettiamo il menu, la struttura logica della nostra finestra si evolve:

Se ora eseguiamo la nostra applicazione, vedremo una finestra vuota senza menu. Dobbiamo associare il menu creato alla nostra finestra. Per farlo, nella struttura della finestra, seleziona l'oggetto "this":

Avrai quindi accesso alle proprietà di questo:

Una di queste è JMenuBar, che serve a impostare il menu da associare alla finestra. Clicca nella cella a destra di JMenuBar. Verranno quindi visualizzati tutti i menu che hai creato. In questo caso, avremo solo jMenuBar1. Selezionalo.
Esegui l'applicazione (F9):

Ora abbiamo un menu, ma le opzioni non fanno ancora nulla. Le opzioni del menu sono trattate come componenti: hanno proprietà ed eventi. Nella struttura del menu, seleziona l'opzione jMenuItem1:

Ora hai accesso alle sue proprietà e ai suoi eventi:

Seleziona la pagina degli eventi e clicca sulla cella a destra dell'evento actionPerformed: questo è l'evento che si verifica quando clicchi su una voce di menu. Una procedura di gestione è fornita di default. Fai doppio clic su di essa per accedere al suo codice:

Scriveremo il seguente semplice codice:
void jMenuItem1_actionPerformed(ActionEvent e) {
afficher("L'option A1 a été sélectionnée");
}
void afficher(String message){
// displays a message in a box
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//display
Esegui l'applicazione e seleziona l'opzione A1 per visualizzare il seguente messaggio:

Il codice relativo a questa applicazione è il seguente:
.....
public class Cadre1 extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
JMenuBar jMenuBar1 = new JMenuBar();
JMenu jMenu1 = new JMenu();
JMenuItem jMenuItem1 = new JMenuItem();
JMenuItem jMenuItem2 = new JMenuItem();
JMenuItem jMenuItem3 = new JMenuItem();
JMenuItem jMenuItem4 = new JMenuItem();
JMenu jMenu2 = new JMenu();
JMenuItem jMenuItem5 = new JMenuItem();
JMenuItem jMenuItem6 = new JMenuItem();
JMenu jMenu3 = new JMenu();
JMenuItem jMenuItem7 = new JMenuItem();
JMenuItem jMenuItem8 = new JMenuItem();
JMenuItem jMenuItem9 = new JMenuItem();
/**Building the frame*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Initialize component*/
private void jbInit() throws Exception {
// the window is associated with a menu
this.setJMenuBar(jMenuBar1);
jMenu1.setText("Options A");
jMenuItem1.setText("A1");
jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jMenuItem1_actionPerformed(e);
}
});
jMenuItem2.setText("A2");
jMenuItem3.setText("A3");
jMenuItem4.setText("A4");
jMenu2.setText("Options B");
jMenuItem5.setText("B1");
jMenuItem6.setText("B2");
jMenu3.setText("B3");
jMenuItem7.setText("B31");
jMenuItem8.setText("B32");
jMenuItem9.setText("B4");
jMenuBar1.add(jMenu1);
jMenuBar1.add(jMenu2);
jMenu1.add(jMenuItem1);
jMenu1.add(jMenuItem2);
jMenu1.addSeparator();
jMenu1.add(jMenuItem3);
jMenu1.add(jMenuItem4);
jMenu2.add(jMenuItem5);
jMenu2.add(jMenuItem6);
jMenu2.add(jMenu3);
jMenu2.add(jMenuItem9);
jMenu3.add(jMenuItem7);
jMenu3.add(jMenuItem8);
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
....
}
void jMenuItem1_actionPerformed(ActionEvent e) {
afficher("L'option A1 a été sélectionnée");
}
void afficher(String message){
// displays a message in a box
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//display
}
5.3. Finestre di dialogo
5.3.1. Finestre di messaggio
Abbiamo già utilizzato la classe JOptionPane per visualizzare i messaggi. Pertanto, il codice seguente:
import javax.swing.*;
public class dialog1 {
public static void main(String arg[]){
JOptionPane.showMessageDialog(null,"Un message","Titre de la boîte",JOptionPane.INFORMATION_MESSAGE);
}
}
visualizza la seguente finestra di dialogo:

Quando questa finestra viene chiusa, scompare, ma il thread di esecuzione in cui era in esecuzione non viene interrotto. Questo fenomeno non si verifica normalmente. Le finestre di dialogo vengono utilizzate all'interno di un'applicazione che, a un certo punto, utilizza un'istruzione System.exit(n) per interrompere tutti i thread. Terremo presente questo aspetto negli esempi che seguiranno, tutti basati sullo stesso modello. In DOS, l'applicazione può essere interrotta con Ctrl-C. Con JBuilder, utilizzare l'opzione Esegui/Reimposta programma (Ctrl-F2). Inoltre, il primo argomento di showMessageDialog è qui nullo. Di solito non è così; in genere è this, dove this si riferisce alla finestra principale dell'applicazione.
5.3.2. Aspetto e funzionalità
L'aspetto della finestra di dialogo sopra riportata potrebbe essere diverso. È possibile configurare questo aspetto utilizzando la classe javax.swing.UIManager. Quando abbiamo commentato il codice generato da JBuilder per la nostra prima finestra, abbiamo incontrato un'istruzione su cui non ci siamo soffermati:
Il metodo setLookAndFeel della classe UIManager (UI = User Interface) consente di impostare l'aspetto delle interfacce grafiche. La classe UIManager dispone di un metodo che permette di determinare i possibili "aspetti" delle interfacce:
static UIManager.LookAndFeelInfo[] | getInstalledLookAndFeels() |
Il metodo restituisce un array di oggetti LookAndFeelInfo. Questa classe dispone di un metodo:
String | getClassName() |
che restituisce il nome della classe che "implementa" un determinato look and feel. Proviamo il seguente programma:
import javax.swing.*;
public class LookAndFeels {
// displays available looks and feels
public static void main(String[] args) {
// iste of installed look and feels
UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
// display
for(int i=0;i<lf.length;i++){
System.out.println(lf[i].getClassName());
}//for
}//hand
}//class
Produce i seguenti risultati:
javax.swing.plaf.metal.MetalLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel
Sembrano quindi esserci tre "aspetti" "diversi". Rivediamo il nostro programma di visualizzazione dei messaggi provando i diversi aspetti possibili:
import javax.swing.*;
public class LookAndFeel2 {
// displays available looks and feels
public static void main(String[] args) {
// list of installed look and feels
UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
// display
for(int i=0;i<lf.length;i++){
// appearance manager
try{
UIManager.setLookAndFeel(lf[i].getClassName());
}catch(Exception ex){
System.err.println(ex.getMessage());
}//catch
// message
JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
}//for
}//hand
}//class
L'esecuzione produce le seguenti visualizzazioni:
![]() | ![]() | ![]() |
corrispondenti, da destra a sinistra, ai "temi" Metal, Pattern, Windows.
5.3.3. Finestre di conferma
La classe JOptionPane dispone di un metodo showConfirmDialog per visualizzare finestre di dialogo di conferma con i pulsanti Sì, No e Annulla. Esistono diverse versioni sovraccaricate del metodo showConfirmDialog. Ne esamineremo una:
static int | showConfirmDialog(Component parentComponent, Object message, String title, int optionType) |
parentComponent | il componente padre della finestra di dialogo. Spesso la finestra o il valore null |
message | il messaggio da visualizzare |
titolo | il titolo della finestra di dialogo |
tipoOpzione | JOptionPane.YES_NO_OPTION: pulsanti Sì, No JOptionPane.YES_NO_CANCEL_OPTION: pulsanti Sì, No, Annulla |
Il risultato restituito dal metodo è:
JOptionPane.YES_OPTION | l'utente ha cliccato su Sì |
JOptionPane.NO_OPTION | l'utente ha cliccato su No |
JOptionPane.CANCEL_OPTION | l'utente ha cliccato su Annulla |
JOptionPane.CLOSED_OPTION | L'utente ha chiuso la finestra di dialogo |
Ecco un esempio:
import javax.swing.*;
public class confirm1 {
public static void main(String[] args) {
// displays confirmation boxes
int réponse;
affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_OPTION));
affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_CANCEL_OPTION));
}//hand
private static void affiche(int réponse){
// indicates the type of response
switch(réponse){
case JOptionPane.YES_OPTION :
System.out.println("Oui");
break;
case JOptionPane.NO_OPTION :
System.out.println("Non");
break;
case JOptionPane.CANCEL_OPTION :
System.out.println("Annuler");
break;
case JOptionPane.CLOSED_OPTION :
System.out.println("Fermeture");
break;
}//switch
}//poster
}//class
![]() | ![]() |
Sulla console vengono visualizzati i messaggi "No" e "Annulla".
5.3.4. Casella di immissione
La classe JOptionPane consente inoltre di inserire dati utilizzando il metodo showInputDialog. Anche in questo caso, sono disponibili diversi metodi sovraccaricati. Ne presentiamo uno:
static String | showInputDialog(Component parentComponent, Object message, String title, int messageType) |
Gli argomenti sono gli stessi che abbiamo già visto diverse volte. Il metodo restituisce la stringa digitata dall'utente. Ecco un esempio:
import javax.swing.*;
public class input1 {
public static void main(String[] args) {
// input
System.out.println("Chaîne saisie ["+
JOptionPane.showInputDialog(null,"Quel est votre nom","Saisie du nom",JOptionPane.QUESTION_MESSAGE )
+ "]");
}//hand
}//class
Visualizzazione della finestra di dialogo di immissione:

Output della console:
5.4. Caselle di selezione
Vedremo ora una serie di finestre di dialogo predefinite per la selezione dei file in Java 2:
JFileChooser | una finestra di dialogo per la selezione di un file dall'albero dei file |
JColorChooser | una finestra di dialogo per la scelta di un colore |
5.4.1. Finestra di dialogo di selezione JFileChooser
Realizzeremo la seguente applicazione:

I controlli sono i seguenti:
N. | Tipo | nome | ruolo |
0 | JScrollPane | jScrollPane1 | Contenitore scorrevole per casella di testo 1 |
1 | JTextArea all'interno di JScrollPane | txtText | testo digitato dall'utente o caricato da un file |
2 | JButton | btnSave | salva il testo di 1 in un file di testo |
3 | JButton | btnLoad | permette di caricare il contenuto di un file di testo in 1 |
4 | JButton | btnClear | cancella il contenuto di 1 |
Viene utilizzato un controllo non visivo: jFileChooser1. Questo viene selezionato dalla tavolozza dei contenitori Swing di JBuilder:

Trascinamo il componente nella finestra di progettazione, ma al di fuori del modulo. Esso appare nell'elenco dei componenti:

Forniremo ora il codice di programma pertinente per dare una panoramica:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
public class dialogues extends JFrame {
// frame components
JPanel contentPane;
JButton btnSauvegarder = new JButton();
JButton btnCharger = new JButton();
JButton btnEffacer = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea txtTexte = new JTextArea();
JFileChooser jFileChooser1 = new JFileChooser();
// file filters
javax.swing.filechooser.FileFilter filtreTxt = null;
//Building the frame
public dialogues() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
// other initializations
moreInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
// moreInit
private void moreInit(){
// window construction initializations
// filter *.txt
filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// do we accept f?
return f.getName().toLowerCase().endsWith(".txt");
}//accept
public String getDescription(){
// filter description
return "Fichiers Texte (*.txt)";
}//getDescription
};
// we add the filter
jFileChooser1.addChoosableFileFilter(filtreTxt);
// we also want to filter all files
jFileChooser1.setAcceptAllFileFilterUsed(true);
// set the start directory of the FileChooser box to the current directory
jFileChooser1.setCurrentDirectory(new File("."));
}
//Initialize component
private void jbInit() throws Exception {
.......................
}
//Replaced, so we can get out when the window is closed
protected void processWindowEvent(WindowEvent e) {
......................
}
}
void btnCharger_actionPerformed(ActionEvent e) {
// file selection using a JFileChooser object
// we set the initial filter
jFileChooser1.setFileFilter(filtreTxt);
// the selection box is displayed
int returnVal = jFileChooser1.showOpenDialog(this);
// did the user choose anything?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// put the file in the text field
lireFichier(jFileChooser1.getSelectedFile());
}//if
}//btnCharger_actionPerformed
// lireFichier
private void lireFichier(File fichier){
// displays the contents of the text file file in the text field
// delete the text field
txtTexte.setText("");
// some data
BufferedReader IN=null;
String ligne=null;
try{
// open file in read mode
IN=new BufferedReader(new FileReader(fichier));
// read the file line by line
while((ligne=IN.readLine())!=null){
txtTexte.append(ligne+"\n");
}//while
// close file
IN.close();
}catch(Exception ex){
// an error has occurred
txtTexte.setText(""+ex);
}//catch
}
// delete
void btnEffacer_actionPerformed(ActionEvent e) {
// delete the text box
txtTexte.setText("");
}
// save
void btnSauvegarder_actionPerformed(ActionEvent e) {
// saves the contents of the text box to a file
// we set the initial filter
jFileChooser1.setFileFilter(filtreTxt);
// the backup selection box is displayed
int returnVal = jFileChooser1.showSaveDialog(this);
// did the user choose anything?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// we write the contents of the text box to file
écrireFichier(jFileChooser1.getSelectedFile());
}//if
}
// lireFichier
private void écrireFichier(File fichier){
// writes the contents of the text box to file
// some data
PrintWriter PRN=null;
try{
// open file for writing
PRN=new PrintWriter(new FileWriter(fichier));
// write the contents of the text box
PRN.print(txtTexte.getText());
// close file
PRN.close();
}catch(Exception ex){
// an error has occurred
txtTexte.setText(""+ex);
}//catch
}
Non commenteremo il codice dei metodi btnEffacer_Click, lireFichier ed écrireFichier, poiché non introducono nulla di nuovo. Ci concentreremo sulla classe JFileChooser e su come utilizzarla. Questa classe è complessa, un po' "confusa". Qui useremo solo i seguenti metodi:
addChoosableFilter(FileFilter) | imposta i tipi di file disponibili per la selezione |
setAcceptAllFileFilterUsed(boolean) | indica se il tipo "Tutti i file" deve essere offerto per la selezione o meno |
File getSelectedFile() | il file (File) selezionato dall'utente |
int showSaveDialog() | metodo che visualizza la finestra di dialogo di salvataggio. Restituisce un risultato di tipo int. Il valore jFileChooser.APPROVE_OPTION indica che l'utente ha effettuato una selezione valida. In caso contrario, l'utente ha annullato la selezione oppure si è verificato un errore. |
setCurrentDirectory | per impostare la directory iniziale da cui l'utente inizierà a esplorare il file system |
setFileFilter(FileFilter) | per impostare il filtro attivo |
Il metodo showSaveDialog visualizza una finestra di dialogo di selezione simile alla seguente:

1 | elenco a discesa creato utilizzando il metodo addChoosableFilter. Contiene i cosiddetti filtri di selezione, rappresentati dalla classe FileFilter. Spetta allo sviluppatore definire questi filtri e aggiungerli all'elenco 1. |
2 | directory corrente, impostata dal metodo setCurrentDirectory se tale metodo è stato utilizzato; in caso contrario, la directory corrente sarà la cartella "Documenti" in Windows o la directory home in Unix. |
3 | Nome del file selezionato o digitato direttamente dall'utente. Sarà disponibile tramite il metodo getSelectedFile() |
4 | Pulsanti Salva/Annulla. Se viene utilizzato il pulsante Salva, il metodo showSaveDialog restituisce il risultato jFileChooser.APPROVE_OPTION |
Come vengono costruiti i filtri dei file nell'elenco a discesa 1? I filtri vengono aggiunti all'elenco 1 utilizzando il metodo:
addChoosableFilter(FileFilter) | imposta i tipi di file disponibili per la selezione |
della classe JFileChooser. Dobbiamo ancora capire la classe FileFilter. Si tratta in realtà della classe javax.swing.filechooser.FileFilter, che è una classe astratta, ovvero una classe che non può essere istanziata ma solo ereditata. È definita come segue:
FileFilter() | costruttore |
boolean accept(File) | indica se il file f corrisponde al filtro o meno |
String getDescription() | stringa di descrizione del filtro |
Facciamo un esempio. Vogliamo che l'elenco a discesa 1 offra un filtro per selezionare i file *.txt con la descrizione "File di testo (*.txt)".
- Dobbiamo creare una classe derivata dalla classe FileFilter
- Utilizzare il metodo booleano accept(File f) per restituire true se il nome del file f termina con .txt
- utilizzare il metodo String getDescription() per impostare la descrizione su "File di testo (*.txt)"
Questo filtro potrebbe essere definito nella nostra applicazione come segue:
javax.swing.filechooser.FileFilter filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// do we accept f?
return f.getName().toLowerCase().endsWith(".txt");
}//accept
public String getDescription(){
// filter description
return "Fichiers Texte (*.txt)";
}//getDescription
};
Questo filtro verrebbe aggiunto all'elenco dei filtri per l'oggetto jFileChooser1 utilizzando la seguente istruzione:
Tutto questo e alcune altre inizializzazioni vengono eseguite nel metodo moreInit, che viene eseguito quando viene creata la finestra (vedere il programma completo sopra). Il codice per il pulsante Salva è il seguente:
void btnSauvegarder_actionPerformed(ActionEvent e) {
// saves the contents of the text box to a file
// we set the initial filter
jFileChooser1.setFileFilter(filtreTxt);
// the backup selection box is displayed
int returnVal = jFileChooser1.showSaveDialog(this);
// did the user choose anything?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// we write the contents of the text box to file
écrireFichier(jFileChooser1.getSelectedFile());
}//if
}
La sequenza delle operazioni è la seguente:
- Impostiamo il filtro attivo su *.txt per consentire all'utente di cercare principalmente questo tipo di file. È presente anche il filtro "Tutti i file". È stato aggiunto nella procedura moreInit. Abbiamo quindi due filtri.
- Viene visualizzata la finestra di dialogo di selezione dei file. A questo punto, il controllo passa all'utente, che utilizza la finestra di dialogo per selezionare un file dal file system.
- Quando l'utente esce dalla finestra di selezione, controlliamo il valore restituito per verificare se dobbiamo salvare il contenuto della casella di testo. In tal caso, deve essere salvato nel file ottenuto tramite il metodo getSelectedFile.
Il codice associato al pulsante "Carica" è molto simile a quello del pulsante "Salva".
void btnCharger_actionPerformed(ActionEvent e) {
// file selection using a JFileChooser object
// we set the initial filter
jFileChooser1.setFileFilter(filtreTxt);
// the selection box is displayed
int returnVal = jFileChooser1.showOpenDialog(this);
// did the user choose anything?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// put the file in the text field
lireFichier(jFileChooser1.getSelectedFile());
}//if
}//btnCharger_actionPerformed
Ci sono due differenze:
- Per visualizzare la finestra di dialogo di selezione dei file, utilizziamo il metodo showOpenDialog invece del metodo showSaveDialog. La finestra di dialogo visualizzata è simile a quella visualizzata dal metodo showSaveDialog.
- Se l'utente ha selezionato correttamente un file, chiamiamo il metodo readFile anziché il metodo writeFile.
5.4.1.1. Finestre di dialogo di selezione JColorChooser e JFontChooser
Continuiamo l'esempio precedente aggiungendo due nuovi pulsanti:

No. | tipo | nome | ruolo |
6 | JButton | btnColor | per impostare il colore del testo della casella di testo |
7 | JButton | btnFont | per impostare il carattere della casella di testo |
Il componente JColorChooser, che visualizza una finestra di dialogo per la selezione del colore, è disponibile nell'elenco dei componenti Swing in JBuilder:

Trascinamo questo componente nella finestra di progettazione, ma al di fuori del modulo. Non è visibile nel modulo, ma è comunque presente nell'elenco dei componenti della finestra:

La classe JColorChooser è molto semplice. Visualizziamo la finestra di dialogo di selezione del colore utilizzando il metodo int showDialog:
static Color | showDialog(Component component, String title, Color initialColor) |
Component component | il componente padre del selettore di colore, in genere una finestra JFrame |
String titolo | il titolo nella barra del titolo della casella di selezione |
Colore intialColor | Il colore inizialmente selezionato nel selettore di colori |
Se l'utente seleziona un colore, il metodo restituisce un colore; altrimenti, restituisce null. Il codice associato al pulsante Colore è il seguente:
void btnCouleur_actionPerformed(ActionEvent e) {
// choice of text color using JColorChooser component
Color couleur;
if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
// set the color of the characters in the text box
txtTexte.setForeground(couleur);
}//if
}
La classe Color è definita in java.awt.Color. Qui sono definite diverse costanti, tra cui Color.BLACK per il colore nero. La finestra di dialogo di selezione visualizzata è la seguente

Curiosamente, la libreria Swing non fornisce una classe per la selezione dei font. Fortunatamente, sono disponibili risorse Java online. Cercando la parola chiave "JFontChooser", che sembra un nome plausibile per una classe del genere, troviamo diverse opzioni. L'esempio seguente ci darà l'opportunità di configurare JBuilder per l'utilizzo di pacchetti non inclusi nella sua configurazione iniziale.
Il pacchetto recuperato si chiama swingextras.jar ed è stato collocato nella cartella <jdk>\jre\lib\perso, dove <jdk> si riferisce alla directory di installazione del JDK utilizzato da JBuilder. Avrebbe potuto essere collocato in qualsiasi altro posto.
![]() | ![]() |
Diamo un'occhiata al contenuto del pacchetto SwingExtras.jar:

Contiene il codice sorgente Java per i componenti inclusi nel pacchetto. Contiene anche le classi stesse:

Da questo archivio, si noti che la classe JFontChooser è in realtà denominata com.lamatek.swingextras.JFontChooser. Se non si desidera scrivere il nome completo, sarà necessario includere quanto segue all'inizio del programma:
In che modo il compilatore e la Java Virtual Machine troveranno questo nuovo pacchetto? Nel caso dell'uso diretto del JDK, questo è già stato spiegato e il lettore può trovare i dettagli nella sezione sui pacchetti Java. Qui descriviamo in dettaglio il metodo da utilizzare con JBuilder. I pacchetti vengono configurati nel menu Options/Configure JDKs:

1 | Il pulsante Modifica (1) consente di indicare a JBuilder quale JDK utilizzare. In questo esempio, JBuilder era fornito in bundle con JDK 1.3.1. Quando è stato rilasciato JDK 1.4, è stato installato separatamente da JBuilder e abbiamo utilizzato il pulsante Modifica per indicare a JBuilder di utilizzare d'ora in poi JDK 1.4 specificandone la directory di installazione |
2 | Directory di base del JDK attualmente utilizzato da JBuilder |
3 | Elenco degli archivi Java (.jar) utilizzati da JBuilder. È possibile aggiungerne altri utilizzando il pulsante Aggiungi (4) |
4 | Il pulsante Aggiungi (4) consente di aggiungere nuovi pacchetti che JBuilder utilizzerà sia per la compilazione che per l'esecuzione dei programmi. Qui lo abbiamo utilizzato per aggiungere il pacchetto SwingExtras.jar (5) |
Ora JBuilder è configurato correttamente per utilizzare la classe JFontChooser. Tuttavia, per utilizzarla correttamente, dovremmo avere accesso alla definizione di questa classe. L'archivio swingextras.jar contiene file HTML che potrebbero essere estratti per l'uso. Ciò non è necessario. La documentazione Java inclusa nei file .jar è accessibile direttamente da JBuilder. Per farlo, configurare la scheda Documentazione (6) sopra. Appare la seguente nuova finestra:

Il pulsante Aggiungi ci permette di specificare che il file SwingExtras.jar debba essere analizzato per la documentazione. Una volta fatto questo, possiamo vedere che abbiamo effettivamente accesso alla documentazione di SwingExtras.jar. Questo offre diversi vantaggi:
- se si inizia a digitare l'istruzione import
vedrai che JBuilder fornisce un aiuto:

Il pacchetto com.lamatek è stato trovato.
- Ora, nel seguente programma:
Se premi F1 sulla parola chiave JFontChooser, vedrai la guida per questa classe:

Nella barra di stato 1 possiamo vedere che viene effettivamente utilizzato un file HTML contenuto nel pacchetto swingextras.jar. L'esempio riportato sopra è sufficientemente chiaro da permetterci di scrivere il codice per il pulsante Font nella nostra applicazione:
void btnPolice_actionPerformed(ActionEvent e) {
// choice of text font using JFontChooser component
jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
// change the font in the text box
txtTexte.setFont(jFontChooser1.getSelectedFont());
}//if
}
La finestra di dialogo di selezione visualizzata dal metodo showDialog sopra riportato è la seguente:

5.5. L'applicazione grafica Tax Claculation
Torniamo all'applicazione IMPOTS, di cui abbiamo già parlato due volte. Ora le aggiungeremo un'interfaccia utente grafica:

I controlli sono i seguenti
N. | Tipo | nome | ruolo |
1 | JRadioButton | rdYes | selezionato se sposato |
2 | JRadioButton | rdNo | Selezionato se non sposato |
3 | JSpinner | spinChildren | numero dei figli del contribuente Minimo=0, Massimo=20, Incremento=1 |
4 | JTextField | txtSalario | stipendio annuale del contribuente in F |
5 | JLabel | lblTaxes | importo delle imposte dovute |
6 | JTextField | txtStatus | campo messaggio di stato - non modificabile |
Il menu è il seguente:
opzione principale | opzione secondaria | nome | ruolo |
Imposte | |||
Inizializza | mnuInitialize | carica i dati necessari per il calcolo da un file di testo | |
Calcola | mnuCalculate | calcola l'imposta dovuta quando tutti i dati necessari sono presenti e corretti | |
Cancella | mnuClear | riporta il modulo allo stato iniziale | |
Esci | mnuExit | chiude l'applicazione |
Regole di funzionamento
- Il menu Calcola rimane disabilitato finché il campo dello stipendio è vuoto
- Se, una volta eseguito il calcolo, lo stipendio risulta errato, viene segnalato un errore:

Il programma è riportato di seguito. Utilizza la classe *impots* creata nel capitolo dedicato alle classi. Parte del codice generato automaticamente da JBuilder non è stata riportata qui.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.*;
import javax.swing.event.*;
public class frmImpots extends JFrame {
// window components
JPanel contentPane;
JMenuBar jMenuBar1 = new JMenuBar();
JMenu jMenu1 = new JMenu();
JMenuItem mnuInitialiser = new JMenuItem();
JMenuItem mnuCalculer = new JMenuItem();
JMenuItem mnuEffacer = new JMenuItem();
JMenuItem mnuQuitter = new JMenuItem();
JLabel jLabel1 = new JLabel();
JFileChooser jFileChooser1 = new JFileChooser();
JTextField txtStatus = new JTextField();
JRadioButton rdOui = new JRadioButton();
JRadioButton rdNon = new JRadioButton();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSalaire = new JTextField();
JLabel jLabel4 = new JLabel();
JLabel jLabel5 = new JLabel();
JLabel lblImpots = new JLabel();
JLabel jLabel7 = new JLabel();
ButtonGroup buttonGroup1 = new ButtonGroup();
JSpinner spinEnfants=null;
FileFilter filtreTxt=null;
// class attributes
double[] limites=null;
double[] coeffr=null;
double[] coeffn=null;
impots objImpots=null;
//Building the frame
public frmImpots() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// other initializations
moreInit();
}
// form initialization
private void moreInit(){
// calculate menu disabled
mnuCalculer.setEnabled(false);
// inhibited input zones
txtSalaire.setEditable(false);
txtSalaire.setBackground(Color.WHITE);
// status field
txtStatus.setBackground(Color.WHITE);
// spinner Children - between 0 and 20 children
spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
spinEnfants.setBounds(new Rectangle(137,60,40,27));
contentPane.add(spinEnfants);
// filter *.txt for selection box
filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// do we accept f?
return f.getName().toLowerCase().endsWith(".txt");
}//accept
public String getDescription(){
// filter description
return "Fichiers Texte (*.txt)";
}//getDescription
};
// add the *.txt filter
jFileChooser1.addChoosableFileFilter(filtreTxt);
// we also want to filter all files
jFileChooser1.setAcceptAllFileFilterUsed(true);
// set the box's start directory FileChooser
jFileChooser1.setCurrentDirectory(new File("."));
}//moreInit
//Initialize component
private void jbInit() throws Exception {
................
}
//Replaced, so we can get out when the window is closed
protected void processWindowEvent(WindowEvent e) {
.....................
}
void mnuQuitter_actionPerformed(ActionEvent e) {
// quit the application
System.exit(0);
}
void mnuInitialiser_actionPerformed(ActionEvent e) {
// load the data file
// selected with the JFileChooser1 selection box
jFileChooser1.setFileFilter(filtreTxt);
if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
return;
// process the selected file
try{
// dATA READING
lireFichier(jFileChooser1.getSelectedFile());
// create impots object
objImpots=new impots(limites,coeffr,coeffn);
// confirmation
txtStatus.setText("Données chargées");
// salary can be modified
txtSalaire.setEditable(true);
// no more chgt possible
mnuInitialiser.setEnabled(false);
}catch(Exception ex){
// problem
txtStatus.setText("Erreur : " + ex.getMessage());
// end
return;
}//catch
}
private void lireFichier(File fichier) throws Exception {
// data tables
ArrayList aLimites=new ArrayList();
ArrayList aCoeffR=new ArrayList();
ArrayList aCoeffN=new ArrayList();
String[] champs=null;
// open file in read mode
BufferedReader IN=new BufferedReader(new FileReader(fichier));
// read the file line by line
// they are of the limit form coeffr coeffn
String ligne=null;
int numLigne=0; // line number courannte
while((ligne=IN.readLine())!=null){
// one more line
numLigne++;
// break down the line into fields
champs=ligne.split("\\s+");
// 3 fields?
if(champs.length!=3)
throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
// we retrieve the three fields
aLimites.add(champs[0]);
aCoeffR.add(champs[1]);
aCoeffN.add(champs[2]);
}//while
// close file
IN.close();
// data transfer to bounded arrays
int n=aLimites.size();
limites=new double[n];
coeffr=new double[n];
coeffn=new double[n];
for(int i=0;i<n;i++){
limites[i]=Double.parseDouble((String)aLimites.get(i));
coeffr[i]=Double.parseDouble((String)aCoeffR.get(i));
coeffn[i]=Double.parseDouble((String)aCoeffN.get(i));
}//for
}
void mnuCalculer_actionPerformed(ActionEvent e) {
// tAX CALCULATION
// salary verification
int salaire=0;
try{
salaire=Integer.parseInt(txtSalaire.getText().trim());
if(salaire<0) throw new Exception();
}catch (Exception ex){
// error msg
txtStatus.setText("Salaire incorrect. Recommencez");
// focus on wrong field
txtSalaire.requestFocus();
// back to interface
return;
}
// no. of children
Integer InbEnfants=(Integer)spinEnfants.getValue();
// tAX CALCULATION
lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
// delete status msg
txtStatus.setText("");
}
void txtSalaire_caretUpdate(CaretEvent e) {
// the salary has changed - update the calculate menu
mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
}
void mnuEffacer_actionPerformed(ActionEvent e) {
// raz du formulaire
rdNon.setSelected(true);
spinEnfants.getModel().setValue(new Integer(0));
txtSalaire.setText("");
mnuCalculer.setEnabled(false);
lblImpots.setText("");
}
}
Qui abbiamo utilizzato un componente disponibile solo a partire da JDK 1.4, il JSpinner. Si tratta di uno spinner che, in questo caso, consente all'utente di impostare il numero di figli. Questo componente Swing non era disponibile nella barra dei componenti Swing di JBuilder 6 utilizzata per il test. Ciò non ne impedisce l'uso, anche se le cose sono un po' più complicate rispetto ai componenti disponibili nella barra dei componenti. Infatti, non è possibile trascinare il componente JSpinner sul modulo durante la fase di progettazione. È necessario farlo in fase di esecuzione. Diamo un'occhiata al codice che lo fa:
// spinner Children - between 0 and 20 children
spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
spinEnfants.setBounds(new Rectangle(137,60,40,27));
contentPane.add(spinEnfants);
La prima riga crea il componente JSpinner. Questo componente può essere utilizzato per vari scopi, non solo come spinner di numeri interi come in questo caso. L'argomento del costruttore JSpinner è un modello di spinner numerico che accetta quattro parametri (valore, min, max, incremento). Il componente ha la seguente forma:
![]()
valore | valore iniziale visualizzato nel componente |
min | valore minimo visualizzabile nel componente |
max | valore massimo visualizzabile nel componente |
incremento | valore di incremento del valore visualizzato quando si utilizzano le frecce su/giù del componente |
Il valore del componente si ottiene tramite il suo metodo getValue, che restituisce un tipo Object. Pertanto, è necessario un certo tipo di conversione per ottenere l'intero di cui abbiamo bisogno:
// nbre d'enfants
Integer InbEnfants=(Integer)spinEnfants.getValue();
// calcul de l'impôt
lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),
InbEnfants.intValue(),salaire));
Una volta definito il componente JSpinner, questo viene inserito nella finestra:
Innanzitutto, l'utente deve utilizzare l'opzione di menu Initialize, che crea un oggetto tax utilizzando il costruttore
della classe impots. Ricordiamo che questa è stata definita come esempio nel capitolo sulle classi. Se necessario, fare riferimento a quel capitolo. I tre array richiesti dal costruttore vengono popolati dal contenuto di un file di testo con il seguente formato:
12620.0 | 0 | 0 |
13190 | 0,05 | 631 |
15.640 | 0,1 | 1.290,5 |
24.740 | 0,15 | 2.072,5 |
31.810 | 0,2 | 3.309,5 |
39.970 | 0,25 | 4.900 |
48.360 | 0,3 | 6.898,5 |
55.790 | 0,35 | 9.316,5 |
92.970 | 0,4 | 12.106 |
127.860 | 0,45 | 16.754,5 |
151.250 | 0,50 | 23.147,5 |
172.040 | 0,55 | 30.710 |
195.000 | 0,60 | 39.312 |
0 | 0,65 | 49062 |
Ogni riga contiene tre numeri separati da almeno uno spazio. Questo file di testo viene selezionato dall'utente tramite un componente JFileChooser. Una volta creato l'oggetto *impots*, non resta che lasciare che l'utente inserisca le tre informazioni necessarie: stato civile, numero di figli, stipendio annuo, e chiamare il metodo calculate della classe impots. L'operazione può essere ripetuta più volte. L'oggetto *impots* viene creato una sola volta, quando si utilizza l'opzione *Initialize*.
5.6. Scrittura di applet
5.6.1. Introduzione
Una volta scritta un'applicazione con un'interfaccia utente grafica, è abbastanza facile convertirla in un'applet. Memorizzata sul computer A, può essere scaricata tramite un browser web dal computer B tramite Internet. L'applicazione originale viene così condivisa tra molti utenti, e questo è il principale vantaggio della conversione di un'applicazione in un'applet. Tuttavia, non tutte le applicazioni possono essere convertite in questo modo: per evitare di causare problemi all'utente che esegue un'applet nel proprio browser, l'ambiente dell'applet è limitato:
- un'applet non può leggere o scrivere sul disco dell'utente
- può comunicare solo con il computer da cui è stata scaricata dal browser.
Si tratta di restrizioni significative. Esse implicano, ad esempio, che un'applicazione che necessiti di leggere informazioni da un file o da un database debba richiederle tramite un'applicazione di inoltro situata sul server da cui è stata scaricata.
La struttura generale di una semplice applicazione web è la seguente:

- il client richiede un documento HTML al server web, solitamente utilizzando un browser. Questo documento può contenere un'applet che funzionerà come un'applicazione grafica autonoma all'interno del documento HTML visualizzato dal browser del client.
- Questa applet può avere accesso ai dati, ma solo a quelli situati sul server web. Non avrà accesso alle risorse del computer client su cui è in esecuzione, né a quelle di altri computer in rete diversi da quello da cui è stata scaricata.
5.6.2. La classe JApplet
5.6.2.1. Definizione
Un'applicazione può essere scaricata da un browser web se è un'istanza della classe java.applet.Applet o della classe javax.swing.JApplet. Quest'ultima deriva dalla prima, che a sua volta deriva dalla classe Panel, la quale a sua volta deriva dalla classe Container. Poiché un'istanza di Applet o JApplet è di tipo Container, può quindi contenere componenti (Component) quali pulsanti, caselle di controllo, elenchi, ecc. Ecco alcune note sul ruolo dei diversi metodi:
Metodo | Ruolo |
public void destroy(); | Distrugge l'istanza Applet |
public AppletContext getAppletContext(); | recupera il contesto di esecuzione dell'applet (il documento HTML in cui si trova, altre applet nello stesso documento, ecc.) |
public String getAppletInfo(); | restituisce una stringa contenente informazioni sull'applet |
public AudioClip getAudioClip(URL url); | carica il file audio specificato dall'URL |
public AudioClip getAudioClip(URL url, String name); | carica il file audio specificato da URL/nome |
public URL getCodeBase(); | restituisce l'URL dell'applet |
public URL getDocumentBase(); | restituisce l'URL del documento HTML contenente l'applet |
public Image getImage(URL url); | recupera l'immagine specificata dall'URL |
public Image getImage(URL url, String name); | recupera l'immagine specificata da URL/nome |
public String getParameter(String name); | recupera il valore del parametro "name" contenuto nel tag <applet> del documento HTML contenente l'applet. |
public void init(); | Questo metodo viene chiamato dal browser al primo avvio dell'applet |
public boolean isActive(); | stato dell'applet |
public void play(URL url); | Riproduce il file audio specificato dall'URL |
public void play(URL url, String name); | riproduce il file audio specificato da URL/nome |
public void resize(Dimension d); | imposta le dimensioni del frame dell'applet |
public void resize(int width, int height); | idem |
public final void setStub(AppletStub stub); | |
public void showStatus(String msg); | visualizza un messaggio nella barra di stato dell'applet |
public void start(); | questo metodo viene chiamato dal browser ogni volta che viene visualizzato il documento contenente l'applet |
public void stop(); | questo metodo viene chiamato dal browser ogni volta che il documento contenente l'applet viene abbandonato a favore di un altro (l'utente cambia l'URL) |
La classe JApplet ha introdotto diversi miglioramenti alla classe Applet, in particolare la possibilità di contenere componenti JMenuBar (ovvero menu), cosa che non era possibile con la classe Applet.
5.6.2.2. Esecuzione di un'applet: i metodi init, start e stop
Quando un browser carica un'applet, ne chiama tre dei suoi metodi:
init | Questo metodo viene chiamato quando l'applet viene caricata inizialmente. Dovrebbe quindi contenere le inizializzazioni necessarie per l'applicazione. |
start | Questo metodo viene chiamato ogni volta che il documento contenente l'applet diventa il documento corrente del browser. Pertanto, quando un utente carica un'applet, i metodi init e start verranno eseguiti in quest'ordine. Quando l'utente lascia il documento per visualizzarne un altro, verrà eseguito il metodo stop. Quando l'utente vi ritorna in seguito, verrà eseguito il metodo start. |
stop | Questo metodo viene chiamato ogni volta che l'utente esce dal documento contenente l'applet. |
Per molte applet, è necessario solo il metodo init. I metodi start e stop sono necessari solo se l'applicazione avvia attività (thread) che vengono eseguite in parallelo e in modo continuo, spesso all'insaputa dell'utente. Quando l'utente esce dal documento, la parte visibile dell'applicazione scompare, ma queste attività in background continuano a essere eseguite. Questo spesso non è necessario. Sfruttiamo quindi la chiamata del browser al metodo stop per interromperli. Se l'utente torna al documento, sfruttiamo la chiamata del browser al metodo start per riavviarli.
Prendiamo, ad esempio, un'applet che ha un orologio nella sua interfaccia grafica. Questo orologio è gestito da un'attività in background (thread). Quando l'utente esce dalla pagina dell'applet nel browser, non ha senso mantenere l'orologio in esecuzione poiché è diventato invisibile: nel metodo stop dell'applet, interromperemo il thread che gestisce l'orologio. Nel metodo start, lo riavviamo in modo che quando l'utente torna alla pagina dell'applet, trovi un orologio aggiornato.
5.6.3. Conversione di un'applicazione grafica in un'applet
Partiamo dal presupposto che questa conversione sia possibile, ovvero che rispetti le restrizioni di esecuzione delle applet. Un'applicazione viene avviata dal metodo *main* di una delle sue classi:
Un'applicazione di questo tipo viene convertita in un'applet come segue:
import java.applet.JApplet;
…
public class application extends JApplet{
…
public void init(){
…
}
…
}// end of class
Si notino i seguenti punti:
- La classe Application ora deriva dalla classe JApplet
- il metodo main è sostituito dal metodo init.
A titolo di esempio, rivediamo un'applicazione che abbiamo già studiato: la gestione delle liste.

Gli elementi di questa finestra sono i seguenti:
N. | Tipo | nome | ruolo |
1 | JTextField | txtInput | campo di immissione |
2 | JList | jList1 | elenco contenuto in un contenitore jScrollPane1 |
3 | JList | jList2 | elenco contenuto in un contenitore jScrollPane2 |
4 | JButton | cmd1To2 | trasferisce gli elementi selezionati dall'elenco 1 all'elenco 2 |
5 | JButton | cmd2To1 | fa l'opposto |
6 | JButton | cmdRaz1 | cancella la lista 1 |
7 | JButton | cmdRaz2 | cancella lista 2 |
Lo scheletro dell'applicazione era il seguente:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmd1To2 = new JButton();
JButton cmd2To1 = new JButton();
DefaultListModel v1=new DefaultListModel();
DefaultListModel v2=new DefaultListModel();
JList jList1 = new JList(v1);
JList jList2 = new JList(v2);
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JButton cmdRaz1 = new JButton();
JButton cmdRaz2 = new JButton();
JLabel jLabel4 = new JLabel();
/**Building the frame*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**Initialize component*/
private void jbInit() throws Exception {
...
txtSaisie.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtSaisie_actionPerformed(e);
}
});
...
// Jlist1 is placed in the jScrollPane1 container
jScrollPane1.getViewport().add(jList1, null);
// Jlist2 is placed in the jScrollPane2 container
jScrollPane2.getViewport().add(jList2, null);
...
}
/**Replaced, so we can get out when the window is closed*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//class
void cmdRaz1_actionPerformed(ActionEvent e) {
// empty list 1
v1.removeAllElements();
}//cmd Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// empty list 2
v2.removeAllElements();
}///cmd Raz2
Per convertire la classe dell'applicazione in un'applet, procedere come segue:
- modificare la precedente classe interfaceAppli in modo che non estenda più JFrame ma estenda invece JApplet:
- Rimuovere l'istruzione che imposta il titolo della finestra JFrame. Un JApplet non ha una barra del titolo
- Modifica il costruttore in un metodo init e, all'interno di questo metodo, rimuovi la gestione degli eventi della finestra (WindowListener, ...). Un'applet è un contenitore che non può essere ridimensionato o chiuso.
/**Building the frame*/
public init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
- Il metodo processWindowEvent deve essere rimosso o commentato
/**Replaced, so we can get out when the window is closed*/
//protected void processWindowEvent(WindowEvent e) {
// super.processWindowEvent(e);
// if (e.getID() == WindowEvent.WINDOW_CLOSING) {
// System.exit(0);
// }
// }
Ecco il codice completo dell'applet, esclusa la parte generata automaticamente da JBuilder
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class interfaceAppli extends JApplet {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmd1To2 = new JButton();
JButton cmd2To1 = new JButton();
DefaultListModel v1=new DefaultListModel();
DefaultListModel v2=new DefaultListModel();
JList jList1 = new JList(v1);
JList jList2 = new JList(v2);
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JButton cmdRaz1 = new JButton();
JButton cmdRaz2 = new JButton();
JLabel jLabel4 = new JLabel();
/**Building the frame*/
public void init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**Initialize component*/
private void jbInit() throws Exception {
//setIconImage(Toolkit.getDefaultToolkit().createImage(interfaceAppli.class.getResource("[Votre icône]")));
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(400, 308));
// this.setTitle("JList");
jScrollPane1.setBounds(new Rectangle(37, 133, 124, 101));
jScrollPane2.setBounds(new Rectangle(232, 132, 124, 101));
.............
}
void txtSaisie_actionPerformed(ActionEvent e) {
// the input text has been validated
// we recover it free of its start and end spaces
String texte=txtSaisie.getText().trim();
// if it's empty, we don't want it
if(texte.equals("")){
// error msg
JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
"Erreur",JOptionPane.WARNING_MESSAGE);
// end
return;
}//if
// if it is not empty, it is added to the values in list 1
v1.addElement(texte);
// and empty the input field
txtSaisie.setText("");
}
void cmd1To2_actionPerformed(ActionEvent e) {
// transfer items selected in list 1 to list 2
transfert(jList1,jList2);
}//cmd1To2
private void transfert(JList L1, JList L2){
// transfer items selected in list 1 to list 2
// retrieve the array of indices of the elements selected in L1
int[] indices=L1.getSelectedIndices();
// anything to do?
if (indices.length==0) return;
// we retrieve the values of L1
DefaultListModel v1=(DefaultListModel)L1.getModel();
// and L2
DefaultListModel v2=(DefaultListModel)L2.getModel();
for(int i=indices.length-1;i>=0;i--){
// the values selected in L1 are added to L2
v2.addElement(v1.elementAt(indices[i]));
// l1 elements copied into L2 must be deleted from L1
v1.removeElementAt(indices[i]);
}//for
}//transfer
private void affiche(String message){
// poster message
JOptionPane.showMessageDialog(this,message,
"Suivi",JOptionPane.INFORMATION_MESSAGE);
}// poster
void cmd2To1_actionPerformed(ActionEvent e) {
// transfer selected items in jList2 to jList1
transfert(jList2,jList1);
}//cmd2TO1
void cmdRaz1_actionPerformed(ActionEvent e) {
// empty list 1
v1.removeAllElements();
}//cmd Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// empty list 2
v2.removeAllElements();
}//cmd Raz2
}//class
È possibile compilare il codice sorgente di questa applet. Qui lo facciamo utilizzando il JDK, senza JBuilder.
E:\data\serge\Jbuilder\interfaces\JApplets\1>javac.bat interfaceAppli.java
E:\data\serge\Jbuilder\interfaces\JApplets\1>dir
12/06/2002 16:40 6 148 interfaceAppli.java
12/06/2002 16:41 527 interfaceAppli$1.class
12/06/2002 16:41 525 interfaceAppli$2.class
12/06/2002 16:41 525 interfaceAppli$3.class
12/06/2002 16:41 525 interfaceAppli$4.class
12/06/2002 16:41 525 interfaceAppli$5.class
12/06/2002 16:41 4 759 interfaceAppli.class
L'applicazione può essere testata utilizzando il programma AppletViewer del JDK, che consente di eseguire le applet, oppure un browser web. Per farlo, è necessario creare il documento HTML appli.htm, che conterrà l'applet:
<html>
<head>
<title>listes swing</title>
</head>
<body>
<applet
code="interfaceAppli.class"
width="400"
height="300">
</applet>
</body>
</html>
Questo è un documento HTML standard, fatta eccezione per la presenza del tag applet. È stato utilizzato con tre parametri:
code="interfaceAppli.class" | nome della classe Java compilata da caricare per eseguire l'applet |
width="400" | larghezza del frame dell'applet nel documento |
height="300" | altezza del riquadro dell'applet nel documento |
Una volta creato il file appli.htm, è possibile caricarlo utilizzando il programma appletviewer del JDK o un browser web. In una finestra DOS, digitare il seguente comando nella cartella contenente il file appli.htm:
**appletviewer appli.htm**
Si presume che la directory contenente l'eseguibile appletviewer.exe sia presente nel PATH della finestra DOS; in caso contrario, sarà necessario specificare il percorso completo dell'eseguibile appletviewer.exe. Apparirà la seguente finestra:

Interrompere l'esecuzione dell'applet utilizzando l'opzione Applet/Quit. Ora proviamo l'applet utilizzando un browser. Il browser deve utilizzare una Java 2 Virtual Machine per visualizzare i componenti Swing. Fino a poco tempo fa (2001), questo requisito rappresentava un problema perché Sun rilasciava JDK che i fornitori di browser erano lenti ad adottare. Alla fine, Sun ha risolto questo problema fornendo agli utenti un'applicazione chiamata "plugin Java", che permette a Internet Explorer e Netscape Navigator di utilizzare le JRE più recenti prodotte da Sun (JRE = Java Runtime Environment). I seguenti test sono stati eseguiti utilizzando IE 5.5 con il plugin Java 1.4.
Un modo per testare l'applet interfaceAppli.class consiste nel caricare il file HTML appli.htm direttamente nel browser facendo doppio clic su di esso. Il browser visualizza quindi la pagina HTML e la relativa applet senza l'ausilio di un server web:

Come si può vedere dall'URL (1), il file è stato caricato direttamente nel browser. Nell'esempio seguente, il file appli.htm è stato richiesto da un server web Apache in esecuzione sulla porta 81 della macchina locale:

5.6.4. Il tag <applet> in un documento HTML
Abbiamo visto che all'interno di un documento HTML, l'applet è indicata dal tag <applet>. Questo tag può avere vari attributi:
<applet
code=
width=
height=
codebase=
align=
hspace=
vspace=
alt=
>
<param name1=nom1 value=val1>
<param name2=nom2 value=val2>
texte
>
</applet>
Il significato dei parametri è il seguente:
Parametro | Significato |
codice | obbligatorio - nome del file .class da eseguire |
larghezza | obbligatorio - larghezza dell'applet nel documento |
altezza | obbligatorio - altezza … |
codebase | opzionale - URL della directory contenente l'applet da eseguire. Se codebase non è specificato, l'applet verrà cercata nella directory del documento HTML che la referenzia |
align | opzionale - posizionamento (LEFT, RIGHT, CENTER) dell’applet all’interno del documento |
hspace | opzionale - margine orizzontale che circonda l'applet, espresso in pixel |
vspace | opzionale - margine verticale che circonda l'applet, espresso in pixel |
alt | opzionale - testo visualizzato al posto dell'applet se il browser non riesce a caricarla |
param | opzionale - parametro passato all'applet che ne specifica il nome (name) e il valore (value). L'applet può recuperare il valore del parametro name1 utilizzando val1=getParameter("name1") È possibile utilizzare tutti i parametri che si desidera |
testo | opzionale - verrà visualizzato da qualsiasi browser che non sia in grado di eseguire un'applet, ad esempio perché non dispone di una Java Virtual Machine. |
Facciamo un esempio per illustrare il passaggio dei parametri a un'applet:
<html>
<head>
<title>paramètres applet</title>
</head>
<body>
<applet code="interfaceParams.class" width="400" height="300">
<param name="param1" value="val1">
<param name="param2" value="val2">
</applet>
</body>
</html>
Il codice Java per l'applet interfaceParams è stato generato come descritto in precedenza. Abbiamo creato un'applicazione JBuilder e poi abbiamo apportato le poche modifiche menzionate sopra:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class interfaceParams extends JApplet {
JPanel contentPane;
JScrollPane jScrollPane1 = new JScrollPane();
JLabel jLabel1 = new JLabel();
DefaultListModel params=new DefaultListModel();
JList lstParams = new JList(params);
//Building the frame
public void init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// other initializations
moreInit();
}
// initializations
public void moreInit(){
// displays applet parameter values
params.addElement("nom=param1 valeur="+getParameter("param1"));
params.addElement("nom=param2 valeur="+getParameter("param2"));
}//more Init
//Initialize component
private void jbInit() throws Exception {
............
this.setSize(new Dimension(205, 156));
//this.setTitle("Applet parameters");
jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
}
}
Esecuzione con AppletViewer:

5.6.5. Accesso alle risorse remote da un'applet
Molte applicazioni devono accedere alle informazioni memorizzate in file o database. Abbiamo notato che un'applet non ha accesso alle risorse del computer su cui viene eseguita. Si tratta di una precauzione dettata dal buon senso. Altrimenti, sarebbe possibile scrivere un'applet per "spiare" il disco rigido di chi la carica. L'applet ha tuttavia accesso alle risorse del server da cui è stata scaricata, come i file. È proprio questo che vedremo ora.
5.6.5.1. La classe URL
Qualsiasi applicazione Java può leggere un file che si trova su un computer in rete usando la classe java.net.URL (URL = Uniform Resource Locator). Un URL identifica una risorsa di rete, il computer su cui si trova, così come il protocollo e la porta di comunicazione da usare per recuperarla nella forma:
protocollo:porta//macchina/file
Pertanto, l'URL http://www.ibm.com/index.html si riferisce al file index.html presente sul computer www.ibm.com. È accessibile tramite il protocollo HTTP. La porta non è specificata: il browser utilizzerà la porta 80, che è la porta predefinita per il servizio HTTP.
Diamo un'occhiata più da vicino ad alcuni degli elementi della classe URL:
public URL(String spec) | crea un'istanza URL da una stringa del tipo "protocollo:porta//macchina/file" - genera un'eccezione se la sintassi della stringa non corrisponde a un URL |
public String getFile() | recupera il campo file dalla stringa "protocollo:porta//macchina/file" presente nell'URL |
public String getHost() | recupera il campo "machine" dalla parte "protocol:port//machine/file" dell'URL |
public String getPort() | recupera il campo porta dalla stringa URL "protocollo:porta//macchina/file" |
public String getProtocol() | recupera il campo del protocollo dalla stringa URL "protocollo:porta//macchina/file" |
public URLConnection openConnection() | apre una connessione al computer remoto getHost() sulla sua porta getPort() utilizzando il protocollo getProtocol() per leggere il file getFile(). Genera un'eccezione se non è stato possibile aprire la connessione |
public final InputStream openStream() | Scorciatoia per openConnection().getInputStream(). Recupera un flusso di input da cui è possibile leggere il contenuto del file getFile(). Genera un'eccezione se non è stato possibile ottenere il flusso |
public String toString() | Visualizza l'identità dell'istanza URL |
Ci sono due metodi qui che ci interessano:
- public URL(String spec) per specificare il file da elaborare
- public final InputStream openStream() per elaborarlo
5.6.5.2. Un esempio: una console-
Scriveremo un programma Java, senza interfaccia grafica, progettato per visualizzare sullo schermo il contenuto di un URL passato come parametro. Un esempio di chiamata potrebbe essere il seguente:
Il programma è relativamente semplice:
import java.net.*; // for the URL class
import java.io.*; // for streams
public class urlcontenu{
// displays contents of URL passed as argument
// this content must be text to be ˆtre lisible
public static void main (String arg[]){
// argument verification
if(arg.length==0){
System.err.println("Syntaxe pg url");
System.exit(0);
}
try{
// creation of URL
URL url=new URL(arg[0]);
// content reading
try{
// input stream creation
BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
try{
// read text lines in the input stream
String ligne;
while((ligne=is.readLine())!=null)
System.out.println(ligne);
} catch (Exception e){
System.err.println("Erreur lecture : " +e);
}
finally{
try { is.close(); } catch (Exception e) {}
}
} catch (Exception e){
System.err.println("Erreur openStream : " +e);
}
} catch (Exception e){
System.err.println("Erreur création URL : " +e);
}
}// fine hand
}// end of class
Dopo aver verificato che sia effettivamente presente un argomento, proviamo a creare un URL con esso:
// création de l'URL
URL url=new URL(arg[0]);
La creazione potrebbe non andare a buon fine se l'argomento non rispetta la sintassi dell'URL: protocollo:porta//macchina/file. Se l'URL è sintatticamente corretto, proviamo a creare un flusso di input da cui poter leggere righe di testo. Il flusso di input fornito da un URL URL.openStream() fornisce un InputStream, che è un flusso orientato ai caratteri: la lettura avviene carattere per carattere e le righe devono essere formate manualmente. Per leggere le righe di testo, è necessario utilizzare il metodo readLine delle classi BufferedReader o DataInputStream. In questo caso, abbiamo scelto BufferedReader. Non resta che convertire l'InputStream dell'URL in un flusso BufferedReader. Ciò avviene creando un flusso InputStreamReader intermedio:
BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
La creazione di questo flusso potrebbe non andare a buon fine. Gestiamo l'eccezione corrispondente. Una volta ottenuto il flusso, non resta che leggere le righe di testo da esso e visualizzarle sullo schermo.
String ligne;
while((ligne=is.readLine())!=null)
System.out.println(ligne);
Anche in questo caso, la lettura potrebbe generare un'eccezione che deve essere gestita. Ecco un esempio di esecuzione del programma che richiede un URL locale:
E:\data\serge\Jbuilder\interfaces\JApplets\3>java urlcontenu http://localhost
<html>
<head>
<title>Bienvenue dans le Serveur Web personnel</title>
</head>
<body bgcolor="#FFFFFF" link="#0080FF" vlink="#0080FF"
topmargin="0" leftmargin="0">
<table border="0" cellpadding="0" cellspacing="0" width="100%"
bgcolor="#000000">
............
</table>
</center></div></td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
5.6.5.3. Un esempio di interfaccia grafica
L'interfaccia grafica avrà questo aspetto:

Numero | Nome | Tipo | Ruolo |
1 | txtURL | JTextField | URL da leggere |
2 | btnLoad | JButton | pulsante per avviare il caricamento dell'URL |
3 | JScrollPane1 | JScrollPane | pannello scorrevole |
4 | lstURL | JList | elenco che mostra il contenuto dell'URL richiesto |
Una volta eseguito, otteniamo un risultato simile a quello del programma da console:

Il codice relativo all'applicazione è il seguente:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.*;
import java.io.*;
public class interfaceURL extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JTextField txtURL = new JTextField();
JButton btnCharger = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
DefaultListModel lignes=new DefaultListModel();
JList lstURL = new JList(lignes);
//Building the frame
public interfaceURL() {
..............
}
//Initialize component
private void jbInit() throws Exception {
..............
}
//Replaced, so we can get out when the window is closed
protected void processWindowEvent(WindowEvent e) {
...................
}
void txtURL_caretUpdate(CaretEvent e) {
// sets the state of the Load button
btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
}
void btnCharger_actionPerformed(ActionEvent e) {
// displays contents of URL in list
try{
afficherURL(txtURL.getText().trim());
}catch(Exception ex){
// error display
JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
}//try-catch
}
private void afficherURL(String strURL) throws Exception {
// displays contents of URL strURL in list
// no exceptions are handled specifically. They are simply reassembled
// creation of URL
URL url=new URL(strURL);
// input stream creation
BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
// read text lines in the input stream
String ligne;
while((ligne=IN.readLine())!=null)
lignes.addElement(ligne);
// close reading flow
IN.close();
}
}
5.6.5.4. Un'applet
L'applicazione grafica precedente viene convertita in un'applet, come è stato dimostrato più volte. L'applet è incorporata in un documento HTML denominato appliURL.htm:
<html>
<head>
<title>Applet lisant une URL</title>
</head>
<body>
<h1>Applet lisant une URL</h1>
<applet
code="appletURL.class"
width="400"
height="300"
>
</applet>
</body>
</html>

Nell'esempio sopra riportato, il browser ha richiesto l'URL http://localhost:81/Japplets/2/appliURL.htm da un server web Apache in esecuzione sulla porta 81. L'applet è stata quindi visualizzata nel browser. In questo esempio, abbiamo richiesto nuovamente l'URL http://localhost:81/Japplets/2/appliURL.htm per verificare che stessimo effettivamente ricevendo il file appliURL.htm che avevamo creato. Ora proviamo a caricare un URL che non appartiene alla macchina che ha servito l'applet (in questo caso, localhost):

L'URL è stato rifiutato. Qui ci imbattiamo nella limitazione associata alle applet: possono accedere solo alle risorse di rete presenti sul computer da cui sono state scaricate. Esiste un modo per l'applet di aggirare questa restrizione, ovvero delegare le richieste di rete a un programma server situato sul computer da cui è stata scaricata. Questo programma effettuerà le richieste di rete per conto dell'applet e le invierà i risultati. Si tratta di un programma proxy.
5.7. L'applet per il calcolo delle imposte
Convertiamo ora l'applicazione grafica IMPOTS in un'applet. Questo aspetto è particolarmente interessante: l'applicazione sarà accessibile a qualsiasi utente di Internet dotato di un browser e di un plugin Java 1.4 (grazie al componente JSpinner). La nostra applicazione diventa così globale... Questa modifica richiederà qualcosa di più della semplice conversione da applicazione grafica ad applet, ormai diventata standard. L'applicazione utilizza un'opzione di menu Initialize progettata per leggere il contenuto di un file locale. Tuttavia, se consideriamo un'applicazione web, vediamo che questo approccio non funziona più:

È chiaro che i dati che definiscono le fasce di imposta si troveranno sul server web e non su ogni macchina client. Il file da leggere dal server web verrà collocato qui nella stessa cartella dell'applet, e l'opzione "Initialize" dovrà recuperarlo da lì. Gli esempi precedenti hanno mostrato come farlo. Inoltre, per selezionare il file di dati localmente, avevamo utilizzato un componente JFileChooser, che qui non è più necessario.
Il documento HTML contenente l'applet sarà il seguente:
<html>
<head>
<title>Applet de calcul d'impôts</title>
</head>
<body>
<h2>Calcul d'impôts</h2>
<applet
code="appletImpots.class"
width="320"
height="270"
>
<param name="data" value="impots.txt">
Si noti il parametro data, il cui valore è il nome del file contenente i dati relativi alle fasce di imposta. Il documento HTML, la classe appletImpots, la classe impots e il file impots.txt si trovano tutti nella stessa cartella sul server web:
E:\data\serge\web\JApplets\impots>dir
12/06/2002 13:24 247 impots.txt
13/06/2002 10:17 654 appletImpots$2.class
13/06/2002 10:17 653 appletImpots$3.class
13/06/2002 10:17 653 appletImpots$4.class
13/06/2002 10:17 651 appletImpots$5.class
13/06/2002 10:06 651 appletImpots$6.class
13/06/2002 10:17 8 655 appletImpots.class
13/06/2002 10:17 657 appletImpots$1.class
13/06/2002 10:24 286 appletImpots.htm
13/06/2002 10:17 1 305 impots.class
Il codice dell'applet è il seguente (abbiamo evidenziato solo le modifiche rispetto all'applicazione grafica):
...........
import java.net.*;
import java.applet.Applet;
public class appletImpots extends JApplet {
// window components
JPanel contentPane;
............................
// class attributes
double[] limites=null;
double[] coeffr=null;
double[] coeffn=null;
impots objImpots=null;
String urlDATA=null;
//Building the frame
public void init() {
//enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// other initializations
moreInit();
}
// form initialization
private void moreInit(){
// calculate menu disabled
mnuCalculer.setEnabled(false);
................
// retrieve the name of the tax scale file
String nomFichier=getParameter("data");
// mistake?
if(nomFichier==null){
// error msg
txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
// we block the Initialize option
mnuInitialiser.setEnabled(false);
// end
return;
}//if
// set the URL of the data
urlDATA=getCodeBase()+"/"+nomFichier;
}//moreInit
//Initialize component
private void jbInit() throws Exception {
...................
}
void mnuQuitter_actionPerformed(ActionEvent e) {
// quit the application
System.exit(0);
}
void mnuInitialiser_actionPerformed(ActionEvent e) {
// load the data file
try{
// dATA READING
lireDATA();
// create impots object
objImpots=new impots(limites,coeffr,coeffn);
................
}
private void lireDATA() throws Exception {
// data tables
ArrayList aLimites=new ArrayList();
ArrayList aCoeffR=new ArrayList();
ArrayList aCoeffN=new ArrayList();
String[] champs=null;
// open file in read mode
BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
// read the file line by line
....................
}
void mnuCalculer_actionPerformed(ActionEvent e) {
// tAX CALCULATION
......................
}
void txtSalaire_caretUpdate(CaretEvent e) {
..........
}
void mnuEffacer_actionPerformed(ActionEvent e) {
...............
}
}
Qui commentiamo solo le modifiche derivanti dal fatto che il file di dati da leggere si trova ora su una macchina remota anziché su una locale:
L'URL del file di dati da leggere viene ottenuto utilizzando il seguente codice:
// retrieve the name of the tax scale file
String nomFichier=getParameter("data");
// mistake?
if(nomFichier==null){
// error msg
txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
// we block the Initialize option
mnuInitialiser.setEnabled(false);
// end
return;
}//if
// set the URL of the data
urlDATA=getCodeBase()+"/"+nomFichier;
Ricordare che il nome del file "impots.txt" viene passato nel parametro data dell'applet:
Il codice sopra riportato inizia recuperando il valore del parametro data e gestendo eventuali errori. Se l'URL del documento HTML contenente l'applet è http://localhost:81/JApplets/impots/appletImpots.htm, l'URL del file impots.txt sarà http://localhost:81/JApplets/impots/impots.txt. Dobbiamo costruire questo URL. Il metodo getCodeBase() dell'applet restituisce l'URL della directory da cui è stato recuperato il documento HTML contenente l'applet, quindi nel nostro esempio http://localhost:81/JApplets/impots. L'istruzione seguente costruisce quindi l'URL per il file di dati:
Nel metodo lireFichier(), che legge il contenuto dell'URL urlData, troviamo la creazione dello stream di input che ci permetterà di leggere i dati:
// open file in read mode
BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
Da questo punto in poi, non è più possibile distinguere se i dati provengano da un file remoto piuttosto che da uno locale. Ecco un esempio dell'applet in azione:

5.8. Conclusione
Questo capitolo ha fornito
- un'introduzione alla creazione di interfacce utente grafiche con JBuilder
- i componenti Swing più comuni
- sviluppo di applet
Va sottolineato che
- il codice generato da JBuilder può essere scritto a mano. Una volta ottenuto questo codice in un modo o nell'altro, è sufficiente un semplice JDK per eseguirlo, e JBuilder non è quindi più indispensabile.
- L'uso di uno strumento come JBuilder può portare a significativi aumenti di produttività:
- sebbene sia possibile scrivere a mano il codice generato da JBuilder, ciò può richiedere molto tempo e offre pochi vantaggi, poiché la logica dell’applicazione si trova generalmente altrove.
- Il codice generato può essere istruttivo. Leggerlo e studiarlo è un buon modo per scoprire determinati metodi e proprietà dei componenti che si utilizzano per la prima volta.
- JBuilder è multipiattaforma. Si mantengono quindi le proprie competenze quando si passa da una piattaforma all'altra. Essere in grado di scrivere programmi che funzionano sia su Windows che su Linux è, ovviamente, un fattore di produttività molto importante. Ma questo è dovuto a Java stesso, non a JBuilder.
5.9. JBuilder su Linux
Tutti gli esempi precedenti sono stati testati su Windows 98. Ci si potrebbe chiedere se i programmi scritti siano portabili così come sono su Linux. A condizione che la macchina Linux in questione disponga delle classi utilizzate dai vari programmi, lo sono. Se, ad esempio, avete installato JBuilder su Linux, le classi necessarie sono già presenti sulla vostra macchina. Ecco un esempio di ciò che accade quando uno dei nostri programmi viene eseguito sul componente JList con JBuilder 4 su Linux:
Di seguito descriviamo l'installazione di JBuilder 4 Foundation su una macchina Linux. L'installazione su una macchina Win9x non pone problemi ed è simile al processo qui descritto. L'installazione delle versioni successive è probabilmente diversa, ma questo documento può comunque fornire alcune informazioni utili.
JBuilder è disponibile sul sito web di Inprise all'indirizzo http://www.inprise.com/jbuilder

Questa pagina contiene link per Windows e Linux, tra gli altri. Descriveremo ora l'installazione di JBuilder su una macchina Linux che utilizza l'interfaccia grafica KDE.
Seguendo il link "JBuilder 4 per Linux", apparirà un modulo. Compilatelo e riceverete due file:
jb4docs_fr.tar.gz: documentazione ed esempi di JBuilder 4
jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. Si tratta di una versione limitata del JBuilder 4 commerciale, ma è sufficiente per scopi didattici.
Ti verrà inviata via e-mail una chiave di attivazione del software. Ti consentirà di utilizzare JBuilder 4 e ti verrà richiesta al primo utilizzo. Se perdi questa chiave, puoi tornare all'URL sopra indicato e seguire il link "get your activation key". Da questo punto in poi daremo per scontato che tu abbia effettuato l'accesso come root e che ti trovi nella directory contenente i due file tar.gz sopra menzionati. Decomprimi i due file:
[ls -l]
drwxr-xr-x 3 nobody nobody 4096 oct 10 2000 docs
drwxr-xr-x 3 nobody nobody 4096 déc 5 13:00 foundation
[ls -l foundation]
-rw-r--r-- 1 nobody nobody 1128 déc 5 13:00 deploy.txt
-rwxr-xr-x 1 nobody nobody 69035365 déc 5 13:00 fnd_linux_install.bin
drwxr-xr-x 2 nobody nobody 4096 déc 5 13:00 images
-rw-r--r-- 1 nobody nobody 15114 déc 5 13:00 index.html
-rw-r--r-- 1 nobody nobody 23779 déc 5 13:00 license.txt
-rw-r--r-- 1 nobody nobody 75739 déc 5 13:00 release_notes.html
-rw-r--r-- 1 nobody nobody 31902 déc 5 13:00 whatsnew.html
[ls -l docs]
-rw-r--r-- 1 nobody nobody 1128 oct 10 2000 deploy.txt
-rwxr-xr-x 1 nobody nobody 40497874 oct 10 2000 doc_install.bin
drwxr-xr-x 2 nobody nobody 4096 oct 10 2000 images
-rw-r--r-- 1 nobody nobody 9210 oct 10 2000 index.html
-rw-r--r-- 1 nobody nobody 23779 oct 10 2000 license.txt
-rw-r--r-- 1 nobody nobody 75739 oct 10 2000 release_notes.html
-rw-r--r-- 1 nobody nobody 31902 oct 10 2000 whatsnew.html
In entrambe le directory generate, il file .bin è il file di installazione. Inoltre, usa un browser web per visualizzare il file index.html in ciascuna directory. Questi file forniscono le istruzioni per l'installazione di entrambi i prodotti. Iniziamo installando JBuilder Foundation:
Viene visualizzata la prima schermata di installazione. Ne seguiranno molte altre:

Conferma. Segue una schermata esplicativa:

Fare clic su [Avanti].

Accetta il contratto di licenza e clicca su [Avanti].

Accetta la posizione suggerita per JBuilder (prendine nota; ti servirà in seguito) e clicca su [Avanti]. L'installazione si completa rapidamente.

Siamo pronti per un primo test. In KDE, avvia il file manager per andare alla directory dell'eseguibile di JBuilder: /opt/jbuilder4/bin (se hai installato JBuilder in /opt/jbuilder4):

Clicca sull'icona di JBuilder qui sopra. Poiché è la prima volta che utilizzi JBuilder, dovrai inserire la tua chiave di attivazione:

Compila i campi Nome e Azienda. Fai clic su [Aggiungi] per inserire la tua chiave di attivazione. Ricorda che questa chiave dovrebbe esserti stata inviata via e-mail e, se l'hai persa, puoi recuperarla dall'URL da cui hai scaricato JBuilder 4 (vedi l'inizio dell'installazione). Una volta accettata la tua chiave di attivazione, verranno visualizzati i termini di licenza:

Facendo clic su OK, tornerai alla finestra di immissione delle informazioni che hai visto in precedenza:

Fai clic su OK per completare questo passaggio, che viene eseguito solo durante la prima esecuzione. Verrà quindi visualizzato l'ambiente di sviluppo JBuilder:

Esci da JBuilder per installare subito la documentazione. Verranno installati diversi file che saranno utilizzati nella guida di JBuilder, attualmente incompleta. Torna alla directory in cui hai estratto i file tar.gz di JBuilder. Il programma di installazione si trova nella directory docs. Accedi a essa:
[cd docs]
[ls -l]
-rw-r--r-- 1 nobody nobody 1128 oct 10 2000 deploy.txt
-rwxr-xr-x 1 nobody nobody 40497874 oct 10 2000 doc_install.bin
drwxr-xr-x 2 nobody nobody 4096 oct 10 2000 images
-rw-r--r-- 1 nobody nobody 9210 oct 10 2000 index.html
-rw-r--r-- 1 nobody nobody 23779 oct 10 2000 license.txt
-rw-r--r-- 1 nobody nobody 75739 oct 10 2000 release_notes.html
-rw-r--r-- 1 nobody nobody 31902 oct 10 2000 whatsnew.html
Il file di installazione è doc_install.bin, ma non è possibile eseguirlo immediatamente. Se lo si fa, l'installazione fallirà senza che se ne capisca il motivo. Leggi il file index.html in un browser per una descrizione dettagliata del processo di installazione. Il programma di installazione richiede una Java Virtual Machine (JVM); in particolare, un programma chiamato java, che deve trovarsi nel PATH del tuo computer. Tieni presente che PATH è una variabile Unix il cui valore, nella forma rep1:rep2:...:repn, specifica le directory repi che devono essere cercate quando si cerca un eseguibile. In questo caso, il programma di installazione richiede l'esecuzione di un programma Java. Potresti avere più versioni di questo programma a seconda del numero di macchine virtuali Java che hai installato qua e là. Logicamente, useremo quella fornita da JBuilder 4, che si trova in /opt/jbuilder4/jdk1.3/bin. Per aggiungere questa directory alla variabile PATH:
[echo $PATH]
/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[export PATH=/opt/jbuilder4/jdk1.3/bin/:$PATH]
[echo $PATH]
/opt/jbuilder4/jdk1.3/bin/:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
Ora possiamo avviare l'installazione della documentazione:
Si tratta di un'installazione grafica:

È molto simile a quella di JBuilder Foundation. Pertanto, non entreremo nei dettagli in questa sede. C'è una schermata da non perdere:

Normalmente il programma di installazione dovrebbe individuare automaticamente la posizione in cui è stato installato JBuilder Foundation. Pertanto, non modificare le impostazioni predefinite a meno che, ovviamente, non siano errate.
Una volta installata la documentazione, siamo pronti per un altro test di JBuilder. Avviare l'applicazione come mostrato sopra. Una volta aperto JBuilder, selezionare Aiuto > Argomenti della guida. Nel riquadro di sinistra, fare clic sul collegamento Tutorial:

JBuilder include una serie di tutorial che vi aiuteranno a muovere i primi passi nella programmazione Java. Di seguito, abbiamo seguito il tutorial "Creazione di un'applicazione" menzionato in precedenza.

In JBuilder, vai su File > Nuovo progetto. Una procedura guidata ti accompagnerà attraverso tre schermate:

Creeremo una semplice finestra con il titolo "Ciao a tutti". Chiameremo questo progetto "hello". L'esempio è stato eseguito da root. JBuilder propone quindi di raggruppare tutti i progetti in una directory "jbproject" all'interno della directory di login di root. Il progetto "hello" verrà collocato nella directory "hello" (campo Nome directory progetto) all'interno di "jbproject". Fare clic su [Avanti].

Questa seconda schermata è un riepilogo dei vari percorsi del progetto. Non c'è nulla da modificare. Fare clic su [Avanti].

La terza schermata chiede di personalizzare il progetto. Inserire i dettagli e fare clic su [Fine].
Ora vai su File/Nuovo:

Seleziona Applicazione e clicca su OK. Una nuova procedura guidata mostrerà due schermate:

Il campo Pacchetto utilizza il nome del progetto. Il campo Classe richiede il nome da assegnare alla classe principale del progetto. Utilizza il nome sopra indicato e clicca su [Avanti]:

La nostra applicazione include una seconda classe Java per la finestra dell'applicazione. Assegnare un nome a questa classe. Il campo Titolo corrisponde al titolo che si desidera assegnare a questa finestra. Il riquadro Opzioni offre diverse opzioni per la finestra. Selezionarle tutte e fare clic su [Fine]. Si tornerà quindi all'ambiente JBuilder, che è stato aggiornato con le informazioni fornite per il progetto:

Nella finestra in alto a sinistra (1) è visibile l'elenco dei file che compongono il progetto. Questo include le due classi .java appena denominate. Nella finestra a destra (2) è visibile il codice Java per la classe coucouCadre. La finestra in basso a sinistra mostra la struttura (classi, metodi, attributi) del progetto. È pronto per l'esecuzione. Fare clic sul pulsante 4 in alto, oppure selezionare Esegui/Esegui progetto, oppure premere F9. Dovrebbe apparire la seguente finestra:

Facendo clic sull'opzione Aiuto, dovresti vedere le informazioni che hai fornito alle procedure guidate di creazione. Non andremo oltre. È ora il momento di immergersi nei tutorial.
Prima di concludere, vediamo che è possibile utilizzare non solo JBuilder e la sua interfaccia grafica, ma anche il JDK che è stato installato insieme ad esso e si trova in /opt/jbuilder4/jdk1.3. Crea il seguente file essai1.java:
import java.io.*;
public class essai1{
public static void main(String args[]){
System.out.println("coucou");
System.exit(0);
}
}
Compiliamo ed eseguiamo il codice utilizzando il JDK di JBuilder:






