Menu


Trascrizione diapositive

1. Interfacce grafiche

  • Complessità: MEDIA.


2. Cosa ci serve?

  • Le interfacce grafiche vengono implementate grazie alle librerie:

  • - java.awt: consente di definire la grafica.
  • - javax.swing: evoluzione della libreria java.awt.
  • - java.awt.event: permette la gestione degli eventi su awt.
  • - javax.swing.event: permette la gestione degli eventi su swing.

  • Con questi package è possibile dotare le applicazioni di finestre con barra del titolo, bottoni di chiusura, riduzione ad icona e ridimensionamento, inoltre, sarà possibile implementare tutte le funzionalità di una applicazione grafica moderna.


3. La mia prima finestra con AWT

  • Per realizzare una finestra usando la libreria AWT è utile estendere la classe «Frame», definendo un metodo costruttore nella classe estesa, come per esempio:

[Download]

import java.awt.*;
class FinestraAWT extends Frame {
public FinestraAWT() {
super("La mia prima finestra con awt");
setSize(400,400); // Dimensione in pixel.
setLocation(1,1); /* Posizione della finestra sullo schermo, coordinate dell'angolo superiore sinistro. */
setVisible(true); // Visualizza la finestra
}
}
public class Programma {
public static void main(String[] args) {
new FinestraAWT();
}
}

  • Risultato a video:

  • Finestra AWT

  • Se clicchiamo sul bottone di chiusura: la finestra non si chiude, per chiudere la finestra è necessario terminare l’attività attraverso il task manager (CTRL-ALT-CANC).


4. La mia prima finestra con SWING

  • Possiamo anche realizzare un’interfaccia grafica senza bisogno di creare una classe specifica, come in questo esempio in cui facciamo uso della libreria SWING:

[Download]

import javax.swing.JFrame;
public class Programma {
public static void main(String args[]) {
JFrame finestra = new JFrame("La mia prima finestra con swing"); /* Istanziamo e dichiariamo un oggetto di tipo JFrame */
finestra.setSize(400,400); /* Dimensione in pixel. */
finestra.setLocation(1,1); /* Posizione della finestra sullo schermo, coordinate dell'angolo superiore sinistro. */
finestra.setVisible(true); // Visualizza la finestra.
}
}

  • Risultato a video:

  • Finestra SWING

  • Se clicchiamo sul bottone di chiusura: la finestra si chiude, questo avviene perché la classe «Jframe» incorpora una funzionalità che permette la gestione di questo evento.


5. Contenitori e componenti

  • Un contenitore è in sostanza un componente che può ospitare altri componenti concreti al suo interno, per componente concreto si intende un elemento (bottone, testo, etc...) che deve essere aggiunto alla nostra finestra.

  • Sostenere che un contenitore contiene componenti concreti, significa che gli elementi inseriti saranno disegnati nella regione di spazio occupata dal loro contenitore.

  • Ad esempio: se creo un contenitore e lo posiziono in alto (a NORD) e poi aggiungo a quest’ultimo un bottone, il bottone si posizionerà in alto, non appena aggiungerò un altro contenitore che posizionerò in basso (a SUD), aggiungendo ad esso un altro pulsante, il primo bottone rimarrà in alto (a NORD), mentre il secondo si posizionerà in basso (a SUD), se provo a ridimensionare la finestra, i pulsanti si sposteranno mantenendo la loro zona. Questa relatività delle posizioni è fondamentale nella costruzione di un'interfaccia.


6. Posizione relativa

  • Per rendere ancor meglio l’idea della posizione relativa dei componenti, vi mostro il risultato di alcuni ridimensionamenti:

Finestre ridimensionate


7. Contenitori e componenti

  • Il contenitore più usato in una finestra AWT è chiamato Panel, mentre il suo corrispettivo in SWING è chiamato JPanel, questa differenza non è casuale, infatti, molto spesso per convertire un componente AWT in componente SWING, basta aggiungere la lettera J prima di specificare il nome del componente.

  • Ovviamente, un contenitore di tipo Panel, può essere inserito solo e soltanto all’interno di una finestra di tipo Frame, mentre un contenitore di tipo JPanel, può essere inserito solo e soltanto all’interno di una finestra di tipo JFrame, anche in questo caso la differenza tra i nomi non è casuale.


8. Panel (AWT)

  • Il contenitore Panel è un componente che può ospitare altri componenti, la posizione del contenitore deve essere specificata quando l’aggiungiamo alla finestra, usando il gestore «BorderLayout». Di seguito un frammento di codice esplicativo:

[Download]

(Prima parte del codice)

import java.awt.*;
class FinestraAWT extends Frame {
public FinestraAWT() {
super("Allineamento...");
setSize(400, 200); // Dimensione in pixel.
setLocation(1, 1); /* Posizione della finestra sullo schermo, coordinate dell'angolo superiore sinistro.*/
Panel contenitoreAlto = new Panel(new FlowLayout(FlowLayout.RIGHT)); /* Crea un contenitore (elementi allineati a destra) */
Button bottoneAlto = new Button("Bottone a NORD"); // Crea un bottone
contenitoreAlto.add(bottoneAlto); // Inserisce il bottone dentro il contenitore
this.add(contenitoreAlto, BorderLayout.NORTH); // Aggiunge il contenitore a NORD
Panel contenitoreOvest = new Panel(); // Crea un contenitore
Button bottoneOvest = new Button("Bottone a OVEST"); // Crea un bottone
contenitoreOvest.add(bottoneOvest); // Inserisce il bottone dentro il contenitore
this.add(contenitoreOvest, BorderLayout.WEST); // Aggiunge il contenitore a OVEST


9. Panel (AWT)


[Download]

(Seconda parte del codice)

Panel contenitoreCentro = new Panel(); // Crea un contenitore
Button bottoneCentro = new Button("Bottone al CENTRO"); // Crea un bottone
contenitoreCentro.add(bottoneCentro); // Inserisce il bottone dentro il contenitore
this.add(contenitoreCentro, BorderLayout.CENTER); /* Aggiunge il contenitore al CENTRO */

Panel contenitoreEst = new Panel(); // Crea un contenitore
Button bottoneEst = new Button("Bottone a EST"); // Crea un bottone
contenitoreEst.add(bottoneEst); // Inserisce il bottone dentro il contenitore
this.add(contenitoreEst, BorderLayout.EAST); // Aggiunge il contenitore a EST

Panel contenitoreBasso = new Panel(new FlowLayout(FlowLayout.LEFT)); /* Crea un contenitore (elementi allineati a sinistra). */
Button bottoneBasso = new Button("Bottone a SUD"); // Crea un bottone
contenitoreBasso.add(bottoneBasso); // Inserisce il bottone dentro il contenitore
this.add(contenitoreBasso, BorderLayout.SOUTH); // Aggiunge il contenitore a SUD

setVisible(true);// Visualizza la finestra
}
}


10. Panel (AWT)


[Download]

(Terza parte del codice)

public class Programma {
public static void main(String[] args) {
new FinestraAWT();
}
}


11. Panel (AWT)

  • Ecco il risultato del codice sorgente che abbiamo appena visto; ora è chiaro come i componenti concreti si posizionano nello schermo grazie ai contenitori.

Disposizione dei componenti nel Panel (AWT)



12. Label e TextField (AWT)

  • Dopo aver visto come posizionare un bottone (elemento «Button») nella finestra, ci accorgiamo che per ottenere un semplice esempio di interazione tra noi e il nostro software, sono necessari almeno altri due componenti. Si tratta degli elementi: «Label» e «TextField».
  • Il componente «Label», ci permette di inserire un’etichetta di testo all’interno della nostra finestra, il testo inserito non può essere modificato direttamente dall’utente.
  • Invece «TextField» permette di inserire un’area di testo modificabile, ciò significa che l’utente può inserire o rimuovere del testo a proprio piacimento; questo componente è molto importante se intendiamo elaborare dei dati di input forniti dall’utente.


13. Label e TextField (AWT)

  • Per provare l’elemento «Label» e l’elemento «TextField», inseriamo prima un’etichetta e poi un testo per il campo modificabile dell’interfaccia grafica, procediamo:

[Download]

import java.awt.*;
public class Programma extends Frame {

public Programma() {
super("Label e TextField con AWT");
setSize(400, 400); // Dimensione in pixel.
setLocation(1, 1); /* Posizione della finestra sullo schermo, coordinate dell'angolo superiore sinistro. */
setLayout(new GridLayout (2, 1)); // Disposizione griglia (2 righe, 1 colonna)
add(new Label("Questa è una etichetta")); // Dichiarazione Label
add(new TextField("Questo è un testo modificabile")); // Dichiarazione TextField
setVisible(true); // Visualizza la finestra
}

public static void main(String[] args) {
new Programma();
}
}


14. Label e TextField (AWT)

  • In figura c'è il risultato del codice precedente, notiamo che gli elementi si posizionano secondo la disposizione della griglia, poiché in questo esempio abbiamo tacitamente introdotto il gestore «GridLayout».

Componenti grafici



15. Ricapitolando…

  • Giunti a questo punto sappiamo quali sono i principali gestori e contenitori che compongono una finestra, così come siamo in grado di posizionare alcuni elementi nell’interfaccia grafica.
  • Nello specifico gli elementi di cui ci siamo occupati sono i seguenti:

  • - «Button» per i bottoni.
  • - «Label» per le etichette.
  • - «TextField» usato principalmente per il testo editabile.

  • Mentre i gestori di cui ci siamo occupati sono:

  • - «BorderLayout» per posizioni NORD/OVEST/CENTRO/EST/SUD.
  • - «FlowLayout» per allineare gli elementi a DESTRA/CENTRO/SINISTRA.
  • - «GridLayout» per generare una griglia.

  • I gestori possono essere usati liberamente, ad esempio è possibile immaginare un contenitore posizionato a centro finestra (attraverso BorderLayout), con elementi interni al contenitore disposti in griglia (GridLayout), in sostanza, la fantasia è l’unico requisito richiesto al lettore.
  • Chiaramente, comporre un’interfaccia grafica che risulti priva di qualsiasi interazione con l’utente non ha senso, dunque, è opportuno implementare degli ascoltatori, ossia dei costrutti che ci permetteranno di catturare alcune azioni dell’utente (ad esempio il click del mouse), per poi effettuare una determinata azione.


16. Creare un’interfaccia con ascoltatore

  • Innanzitutto, vediamo come implementare un’interfaccia grafica composta da due «Panel», posizionati rispettivamente a NORD e al CENTRO, in cui il primo «Panel» contiene due elementi di tipo «Button» disposti in una griglia di due colonne e una riga:

[Download]

(Prima parte del codice)

public class Programma extends Frame implements ActionListener {
public Panel contenitoreRisultato;

public Programma() {

super("Primo esempio di interazione");
setSize(400, 400); // Dimensione in pixel.
setLocation(1, 1); // Posizione della finestra sullo schermo, coordinate dell'angolo superiore sinistro.
setVisible(true); // Visualizza la finestra
Panel contenitoreAlto = new Panel(new GridLayout(1, 2)); // Disposizione griglia su pannello (1 riga, 2 colonne)
Button rosso = new Button("Rosso"); // Dichiarazione e istanza del bottone rosso
Button blu = new Button("Blu"); // Dichiarazione e istanza del bottone blu
rosso.addActionListener(this); // Aggiunge ascoltatore che cattura azione in questa classe (per bottone rosso)
blu.addActionListener(this); // Aggiunge ascoltatore che cattura azione in questa classe (per bottone blu)
contenitoreAlto.add(rosso); // Aggiunta bottone rosso al «Panel»
contenitoreAlto.add(blu); // Aggiunta bottone blu al «Panel»
this.add(contenitoreAlto, BorderLayout.NORTH); // Inserisce il pannello nella finestra a NORD
contenitoreRisultato = new Panel(); // Crea nuovo pannello
this.add(contenitoreRisultato, BorderLayout.CENTER); // Inserisce il pannello nella finestra al CENTRO
}


17. Creare un’interfaccia con ascoltatore

  • Quindi vediamo come attraverso gli ascoltatori siamo in grado di catturare l’azione intrapresa dall’utente, azione che determinerà la successiva modifica dello sfondo relativo al «Panel» centrale:

[Download]

(Seconda parte del codice)

public static void main(String[] args) {
new Programma();
}

// Metodo per catturare l'azione dei bottoni
@Override
public void actionPerformed(ActionEvent e) {
String click = e.getActionCommand(); // Cattura l'azione dell'evento in una stringa
switch (click) { // Selezione dell'azione in base al bottone d'appartenenza
case "Blu": // Se il tasto premuto è quello con su scritto «Blu»…
contenitoreRisultato.​setBackground(Color.blue); // Imposta sfondo di colore BLU
break;
case "Rosso": // Se il tasto premuto è quello con su scritto «Rosso»…
contenitoreRisultato.​setBackground(Color.red); // Imposta sfondo di colore ROSSO
break;
}
}
}


18. Esempio d’interfaccia con ascoltatore

19. Ascoltatore per la finestra

  • Notiamo che dopo aver eseguito il codice sorgente ed accertato il corretto funzionamento del programma: alla pressione del tasto di chiusura della finestra non accade nulla, ciò si verifica poiché le finestre di tipo AWT devono sempre implementare uno specifico ascoltatore, perfino per gestire operazioni standard come la pressione del tasto «X».

  • Per aggiungere un ascoltatore di finestra, è necessario implementare un’interfaccia di tipo «WindowListener» e fare override dei seguenti metodi:

  • - «windowOpened(WindowEvent e)» per eseguire istruzioni all’apertura della finestra.
  • - «windowClosing(WindowEvent e)» per eseguire istruzioni alla chiusura della finestra.
  • - «windowClosed(WindowEvent e)» per eseguire istruzioni a finestra ormai chiusa.
  • - «windowIconified(WindowEvent e)» per eseguire istruzioni a finestra ridotta a icona.
  • - «windowDeiconified(WindowEvent e)» per eseguire istruzioni a finestra ripristinata da icona.
  • - «windowActivated(WindowEvent e)» per eseguire istruzioni quando la finestra viene attivata.
  • - «windowDeactivated(WindowEvent e)» per eseguire istruzioni quando la finestra viene disattivata.

  • Dunque, per il nostro scopo implementeremo il metodo di «windowClosing()» che ci servirà a terminare il programma e chiudere la finestra, naturalmente il lettore è libero di utilizzare qualsiasi altro metodo che ritiene necessario.


20. Ascoltatore per la finestra

  • Per attivare l’interattività della finestra bisogna effettuare alcune aggiunte al codice precedente, notiamo in particolar modo l’implementazione dell’interfaccia «WindowListener» e l’istruzione «this.addWindowListener(this);» che delega le funzioni di risposta alle azioni della finestra alla classe stessa.

[Download]

(Prima parte del codice)

public class Programma extends Frame implements WindowListener, ActionListener {
public Panel contenitoreRisultato;

public Programma() {
super("Primo esempio di interazione");
setSize(400, 400); // Dimensione in pixel.
setLocation(1, 1); // Posizione della finestra sullo schermo, coordinate dell'angolo superiore sinistro.
setVisible(true); // Visualizza la finestra
Panel contenitoreAlto = new Panel(new GridLayout(1, 2)); // Disposizione griglia su pannello (1 riga, 2 colonne)
Button rosso = new Button("Rosso"); // Dichiarazione e istanza del bottone rosso
Button blu = new Button("Blu"); // Dichiarazione e istanza del bottone blu
rosso.addActionListener(this); // Aggiunge ascoltatore che cattura azione in questa classe (per bottone rosso)
blu.addActionListener(this); // Aggiunge ascoltatore che cattura azione in questa classe (per bottone blu)
this.addWindowListener(this); // Aggiunge ascoltatore che cattura azioni di finestra in questa classe
contenitoreAlto.add(rosso); // Aggiunta bottone rosso al «Panel»
contenitoreAlto.add(blu); // Aggiunta bottone blu al «Panel»
this.add(contenitoreAlto, BorderLayout.NORTH); // Inserisce il pannello nella finestra a NORD
contenitoreRisultato = new Panel(); // Crea nuovo pannello
this.add(contenitoreRisultato, BorderLayout.CENTER); // Inserisce il pannello nella finestra al CENTRO
}


21. Ascoltatore per la finestra

  • La seconda parte del codice che si occupava dell’interazione dei bottoni è rimasta invariata.

[Download]

(Seconda parte del codice)

public static void main(String[] args) {
new Programma();
}

// Metodo per catturare l'azione dei bottoni
@Override
public void actionPerformed(ActionEvent e) {
String click = e.getActionCommand(); // Cattura l'azione dell'evento in una stringa
switch (click) { // Selezione dell'azione in base al bottone d'appartenenza
case "Blu": // Se il tasto premuto è quello con su scritto «Blu»…
contenitoreRisultato.​setBackground(Color.blue); // Imposta sfondo di colore BLU
break;
case "Rosso": // Se il tasto premuto è quello con su scritto «Rosso»…
contenitoreRisultato.​setBackground(Color.red); // Imposta sfondo di colore ROSSO
break;
}
}


22. Ascoltatore per la finestra

  • La terza ed ultima parte del codice permette di terminare il processo e quindi chiudere la finestra, attraverso il metodo «windowClosing()» e la relativa istruzione «System.exit(0);».

[Download]

(Terza parte del codice)

@Override
public void windowOpened(WindowEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}

@Override
public void windowClosed(WindowEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void windowIconified(WindowEvent e) {

throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void windowDeiconified(WindowEvent e) {

throw new UnsupportedOperationException("Not supported yet.");
}
...


23. Esempio d’ascoltatore per la finestra

24. La calcolatrice

  • Ora che avrai capito come generare una finestra e come lavorare con contenitori ed ascoltatori, è arrivato il momento di passare ad un progetto leggermente più complesso: la calcolatrice!

  • Per realizzare la nostra calcolatrice ci serviremo della libreria AWT: perciò dovremo estendere la classe «Frame», dichiarare gli elementi, inserirli all’interno dei contenitori, aggiungere i contenitori alla finestra, ed infine gestire gli eventi tramite gli ascoltatori.

  • La gestione degli eventi sarà la parte più complessa del progetto e richiede la vostra massima attenzione: non sarà facile.


25. La calcolatrice

  • Cominciamo subito dichiarando gli elementi del display e della tastiera:

[Download]

(Prima parte del codice)

public class Calcolatrice extends Frame implements WindowListener, ActionListener {
// Dichiarazione degli elementi del display
TextField display = new TextField(20);
Panel schermo = new Panel();
// Dichiarazione degli elementi della tastiera
Panel tastiera = new Panel();
Button[] tasto = new Button[10];
{
for (int i=0; i<10; i++) {
tasto[i] = new Button(Integer.toString(i));
}
}
Button tastoSomma = new Button("+");
Button tastoSottrazione = new Button("-");
Button tastoMoltiplicazione = new Button("*");


// Dichiarazione degli elementi per AC
Panel reset = new Panel();
Button tastoCancella = new Button("AC");


26. La calcolatrice

  • Proseguiamo dichiarando l’elemento di copyright che vi consiglio di aggiungere sempre in progetti di una certa complessità, sia per proteggere il vostro diritto d’autore, così come per evitare che qualcuno possa distribuire il vostro software a vostra insaputa.

  • Alla fine dichiariamo le variabili di sistema, il cui funzionamento sarà chiarito più avanti.

[Download]

(Seconda parte del codice)

// Dichiarazione degli elementi per Copyright
Label copy = new Label("Domenico Boncoddo");

// Dichiarazione delle variabili di sistema
String operatore, contenutoTasto;
double accumulatore = 0.0D;
boolean decimale = false;
boolean pulisci = false;
boolean fatto = false;


27. La calcolatrice

  • Adesso creiamo il metodo «aggiungiBottone(Button b)» che accetterà in argomento una variabile di tipo «Button», relativa ad un bottone del tastierino numerico della calcolatrice.

  • Nel corpo del metodo verrà poi aggiunto un ascoltatore, che si occuperà della gestione degli eventi di ogni bottone passato in argomento; eventi che, in questo caso, saranno processati dalla classe stessa, dopodiché il bottone verrà finalmente aggiunto al suo contenitore.

[Download]

(Terza parte del codice)

// Metodo per aggiungere i bottoni della tastiera
private void aggiungiBottone(Button b) {
b.addActionListener(this); // Aggiunge ascoltatore che cattura azione in questa classe
tastiera.add(b); // Aggiunta bottone al «Panel»
}


28. La calcolatrice

  • Nel metodo costruttore collochiamo il display in alto sulla finestra ed aggiungiamo i tasti del tastierino:

[Download]

(Quarta parte del codice)

// Metodo costruttore che genera la finestra
public Calcolatrice() {
super("Calcolatrice");

// Creo il display
this.display.setBackground(Color.BLACK); // Sfondo del display
this.display.setForeground(Color.WHITE); // Colore del carattere
this.display.setEditable(false); // Disattiva l'editing del display
super.add(this.display, BorderLayout.NORTH); // Aggiunge il contenitore a NORD

// Creo la tastiera
this.tastiera.setLayout(new GridLayout(4, 4, 1, 1)); // Disposizione in griglia su pannello (4 righe, 4 colonne)

this.aggiungiBottone(tasto[7]); // Aggiunta del tasto 7
this.aggiungiBottone(tasto[8]); // Aggiunta del tasto 8
this.aggiungiBottone(tasto[9]); // Aggiunta del tasto 9
this.aggiungiBottone(tastoDivisione); // Aggiunta del tasto per divisione
this.tastoDivisione.setBackground​(Color.ORANGE); // Imposta colore per il tasto della divisione



29. La calcolatrice


[Download]

(Quinta parte del codice)

// Metodo per la gestione degli eventi dei bottoni
@Override
public void actionPerformed(ActionEvent evento) {
if (this.pulisci == true) {
this.display.setText("");
this.operatore = null;
this.decimale = false;
this.pulisci = false;
this.fatto = false;
}

this.contenutoTasto = evento.getActionCommand();
try {
Integer.parseInt(this.contenutoTasto);
this.aggiungiCifra(this.contenutoTasto);
} catch (Exception exc) {
if (this.contenutoTasto.equals(".")) {
this.aggiungiPunto();
} else if (this.contenutoTasto.equals("=")) {
this.esegui();
} else if (this.contenutoTasto.equals("AC")) {
this.accumulatore = 0.00D;
this.display.setText("");
this.pulisci = true;
} else {
this.memorizza();
}
}
}

  • Il metodo «actionPerformed()» cattura gli eventi del tastierino, perciò in caso di click su un tasto numerico verrà invocato il metodo «aggiungiCifra()», altrimenti sarà sollevata un'eccezione che verrà gestita nel relativo blocco catch.

  • Di conseguenza, in caso di click sul tasto del punto: verrà invocato il metodo «aggiungiPunto()».

  • Se l’utente clicca sul tasto uguale «=», sarà chiamato il metodo «esegui()».

  • Nel caso di click sul bottone di reset «AC»: verrà innanzitutto azzerato l’accumulatore (variabile che contiene il risultato) e il display verrà pulito; dopodiché la varabile «pulisci» sarà settata a «true», cosicché al prossimo click su un altro bottone, verrà eseguito il primo if del metodo «actionPerformed()», che si occuperà di resettare le altre variabili.

  • Infine, quando l’utente clicca su un operatore (somma, divisione...), sarà eseguito il metodo «memorizza()».


30. La calcolatrice

  • Il metodo «aggiungiPunto()» controlla che la variabile «decimale» sia impostata a «false», se è così verrà aggiunto un punto sul display, altrimenti, se la variabile è impostata su «true»: l’if non verrà eseguito, pertanto non sarà aggiunto il punto.

  • Notiamo che, indipendentemente dall’esecuzione dell’if, la variabile «decimale» verrà settata a «true», ciò significa che il punto sarà sempre aggiunto una sola volta sul display.

[Download]

(Sesta parte del codice)

// Metodo per aggiungere il punto nel display (solo una volta)
private void aggiungiPunto() {
if (this.decimale == false) {
this.display.setText(this.display.getText() + ".");
}
this.decimale = true;
}


31. La calcolatrice

  • Il metodo «aggiungiCifra(String c)» permette di inserire una cifra nel display della calcolatrice (quando si preme su un tasto numerico):

[Download]

(Settima parte del codice)

// Metodo per aggiungere una cifra nel display
private void aggiungiCifra(String c) {
if (fatto == true) { // Se prima è stato premuto un tasto di un operatore...
this.display.setText("" + c); // Resetta display e aggiungi la cifra
fatto = false; // Adesso l'ultima operazione riguarda la pressione di un tasto numerico
} else { // Se l'ultima operazione riguarda la pressione di un tasto numerico...
this.display.setText(this.display.getText() + c); // Aggiunge la cifra al contenuto presente
}
}

  • Se prima era stato premuto un tasto per effettuare un operazione aritmetica: la variabile booleana «fatto» si troverà nello stato di «true», di conseguenza nel display vedremo solamente il valore del tasto numerico cliccato, dopodiché la variabile «fatto» ritornerà al suo valore originario «false».

  • Invece, se in precedenza era stato premuto un tasto numerico e quindi la variabile «fatto» si trovava impostata su «false»: la cifra passata in argomento verrà accodata alle cifre già presenti nel display.


32. La calcolatrice


[Download]

(Ottava parte del codice)

// Metodo per memorizzare i valori durante un operazione
private void memorizza() {

double numero = 0.0D; // Inizializza la variabile che conterrà il numero sul display
if (fatto == false) { // Se l'ultima operazione riguarda la pressione di un tasto numerico...
try {
numero = Double.parseDouble​(this.display.getText()); // Preleva il numero dal display
// Effettua l'operazione tra il contenuto del display e l'accumulatore
if (this.operatore == "+") {
this.accumulatore = this.accumulatore + numero;
} else if (operatore == "-") {
this.accumulatore = this.accumulatore - numero;
} else if (operatore == "*") {
this.accumulatore = this.accumulatore * numero;
} else if (operatore == "/") {
this.accumulatore = this.accumulatore / numero;
} else {
if (!this.display.getText().isEmpty()) {
this.accumulatore = Double.parseDouble​(this.display.getText());
}
}

this.operatore = this.contenutoTasto; // Imposta l'operatore
decimale = false; // Sarà nuovamente possibile inserire il punto decimale (se era stato inserito)
fatto = true; // Adesso l'ultima operazione riguarda la pressione di un tasto operatore
display.setText(Double.toString​(this.accumulatore)); // Mostra il risultato
} …

  • Il metodo «memorizza()» viene eseguito quando si preme su un tasto operatore (di somma, sottrazione, divisione o moltiplicazione).

  • L’operazione verrà eseguita solo se l’ultimo tasto premuto dall’utente corrisponde ad un numero, perciò inizialmente sarà controllata la variabile booleana «fatto» che dovrà corrispondere al valore «false».

  • Dopodiché verrà prelevato il valore presente nel display e se la variabile «operatore» non è null verrà effettuata l’operazione tra il contenuto del display e l’accumulatore, mentre se è null, verrà settato l’accumulatore al valore del display, infine, verrà mostrato il risultato a schermo.

  • Inoltre, notiamo come la variabile «decimale» verrà impostata a «false», in modo tale da consentire il reinserimento del punto sul display, infine la variabile «fatto» verrà impostata a «true», visto che adesso l’ultimo tasto premuto corrisponde ad un operatore.


33. La calcolatrice


[Download]

(Nona parte del codice)

// Metodo per restituire il risultato
private void esegui() {
double numero = 0.0D; // Inizializza la variabile che conterrà il numero sul display
if (fatto == false) { // Se l'ultima operazione riguarda la pressione di un tasto numerico...
try {
numero = Double.parseDouble​(this.display.getText()); // Preleva il numero dal display
// Effettua l'operazione tra il contenuto del display e l'accumulatore
if (this.operatore.equals("+")) {
this.accumulatore = this.accumulatore + numero;
}
if (this.operatore.equals("-")) {
this.accumulatore = this.accumulatore - numero;
}
if (this.operatore.equals("*")) {

this.accumulatore = this.accumulatore * numero;
}
if (this.operatore.equals("/")) {

this.accumulatore = this.accumulatore / numero;
}
this.display.setText(String.valueOf​(this.accumulatore)); // Mostra il risultato
this.pulisci = true; // Pulisci lo schermo
} catch (NumberFormatException exc) { // Tasto uguale dopo reset o avvio...
display.setText(String.valueOf("")); // Display vuoto
}
}
} ...

  • Il metodo «esegui()» viene invocato quando un utente preme sul tasto «=» per eseguire un’operazione.

  • A questo punto, la variabile che dovrà contenere il numero presente sul display sarà inizializzata a zero e dopodiché, se il display non è vuoto, gli verrà assegnato il relativo valore, altrimenti sarà eseguito il blocco «catch».

  • Nel caso in cui non venga sollevata alcuna eccezione: verrà effettuata l’operazione tra il numero presente sul display e l’accumulatore, il cui risultato sarà mostrato sul display stesso.

  • Infine, la varabile «pulisci» sarà settata a «true», cosicché al prossimo click su un altro bottone, verrà eseguito il primo if del metodo «actionPerformed()», che si occuperà di resettare le altre variabili.


34. Esempio di calcolatrice

35. Introduzione a SWING

  • SWING è una libreria per la costruzione di interfacce grafiche indubbiamente più evoluta rispetto ad AWT, poiché detiene un maggior numero di componenti grafici, tutti pienamente aderenti alla filosofia della portabilità, infatti, un'interfaccia grafica costruita con SWING sarà visualizzata allo stesso modo su ogni dispositivo nel quale venga impiegata.

  • Al contrario, un'interfaccia costruita con AWT visualizzerà gli elementi in maniera diversa, ad esempio: un bottone AWT su un Macintosh sarà mostrato in modo differente rispetto ad un PC con Windows, poiché AWT utilizza delle chiamate native proprie del sistema operativo su cui opera la JVM e ciò incide notevolmente dal punto di vista grafico.

  • Tuttavia non è tutto oro quel che luccica, tra gli sviluppatori è risaputo che SWING ha problemi che riguardano la velocità, il motivo è che l’elaboratore deve provvedere a disegnare ogni elemento sul display senza alcun supporto proveniente dal sistema, ciò comporta una notevole perdita di tempo causata dall’elevato calcolo computazionale richiesto.

  • Ora che abbiamo compreso le principali differenze tra SWING e AWT, vediamo come implementare una finestra SWING più moderna rispetto a quella mostrata in precedenza.


36. Finestra SWING più moderna con i processi


[Download]

public class Programma extends JFrame {
static JLabel label;
public Programma() {
super("Test su swing");
label = new JLabel("Primo saluto");
super.add(label);

super.setDefaultCloseOperation​(JFrame.EXIT_ON_CLOSE);
super.setSize(400, 100);
super.setLocation(1, 1);
super.setVisible(true);
}

public static void main(String[] args) throws InterruptedException {
new Programma();
TimeUnit.SECONDS.sleep(1);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
label.setText("Secondo saluto");
}
});
}
}

  • Il codice a fianco genera una finestra SWING che mostra su schermo un messaggio del tipo: «Primo saluto», dopo circa 1 sec. il messaggio cambierà mostrando la dicitura «Secondo saluto». La modifica dell’etichetta è stata eseguita da un processo dedicato.

  • A questo punto è lecito domandarsi: per quale motivo creare un nuovo processo? Dobbiamo sapere che per ogni operazione bloccante avviata dall’interfaccia grafica è obbligatorio lanciare un processo dedito ad espletarne la funzione, altrimenti, fino a quando l’operazione non sarà ultimata: l’interazione con l’interfaccia sarà impossibile, pertanto l’utente avrà la sensazione che il software sia totalmente bloccato.

  • Un processo si avvia grazie al metodo statico «invokeLater()» della classe «SwingUtilities», a cui dovrà essere passato un parametro relativo ad un’istanza che estende «Runnable»; nel caso del nostro esempio: viene istanziato «Runnable» direttamente nel parametro per via della classe anonima che lo estende, che riscrive il metodo «run()» e che a sua volta modifica il «JLabel».

  • L’attesa tra un messaggio e l’altro è resa possibile grazie all’istruzione: «TimeUnit.SECONDS.sleep(1);».


37. Chiudere il processo della finestra

  • Il lettore più attento si sarà accorto di un particolare presente nella diapositiva precedente, mi riferisco all’istruzione:

  • super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  • Questa istruzione permette di terminare il processo quando premiamo il tasto di chiusura della finestra, senza questa chiamata, Java in modalità predefinita non terminerà l’esecuzione del software, che quindi rimarrà attivo in background nel task manager.


38. JTextArea (SWING)

  • È bene precisare che i componenti grafici esaminati in precedenza possono essere trasformati in elementi SWING aggiungendo la lettera J alla loro dichiarazione ed istanza, ad esempio un «Button» su AWT corrisponde ad un «JButton» su SWING, inoltre, ricorda che per creare una finestra di componenti SWING occorre estendere la classe «JFrame», importando la relativa libreria.

  • Premesso ciò, iniziamo ad utilizzare SWING e vediamo subito come implementare una «JTextArea» in un «JScrollPane»; «JTextArea» ci permette di creare un’area di testo libera dove poter scrivere, mentre «JScrollPane» ci serve per lo scorrimento del testo.

  • [Download]

  • super("Test JTextArea");
    textArea = new JTextArea(5, 20); // Istanzia JTextArea
    scrollPane = new JScrollPane(textArea); // Aggiunge JTextArea a JScrollPane per scorrimento verticale
    super.add(scrollPane); // Aggiunge JScrollPane alla finestra

  • RISULTATO DEL CODICE:

  • JTextArea


39. JRadioButton (SWING)

  • Passiamo ad esaminare il «JRadioButton» che è un controllo grafico che ci consente di effettuare una scelta singola esclusiva nell'ambito di un insieme predefinito di possibili scelte.

  • La mutua esclusione è resa possibile grazie all'inserimento del «JRadioButton» in un gruppo di tipo «ButtonGroup».

  • [Download]

  • super("Test JRadioButton");
    super.setLayout(new GridLayout (3, 1)); // Disposizione griglia (3 righe, 1 colonna)

    radioButton = new JRadioButton("primo", false); // Istanzia JRadioButton
    radioButton1 = new JRadioButton("secondo", false); // Istanzia JRadioButton
    radioButton2 = new JRadioButton("terzo", false); // Istanzia JRadioButton

    gruppo = new ButtonGroup(); // Istanzia ButtonGroup per creare un gruppo di JRadioButton
    gruppo.add(radioButton); // Inserisce radioButton nel gruppo
    gruppo.add(radioButton1); // Inserisce radioButton1 nel gruppo
    gruppo.add(radioButton2); // Inserisce radioButton2 nel gruppo
    super.add(radioButton); // Aggiunge radioButton alla finestra
    super.add(radioButton1); // Aggiunge radioButton1 alla finestra
    super.add(radioButton2); // Aggiunge radioButton2 alla finestra

  • RISULTATO DEL CODICE:

  • JRadioButton


40. JCheckBox (SWING)

  • I componenti «JCheckBox» sono mostrati sullo schermo come dei quadrati che possono contenere uno spazio bianco (quando non sono selezionati), oppure un segno di spunta (quando sono selezionati).

  • Adiacente al «JCheckBox» è mostrata una breve descrizione. Per invertire lo stato (selezionato/non selezionato) del «JCheckBox» è sufficiente cliccare sul riquadro o sulla descrizione.

  • [Download]

  • super("Test JCheckBox");
    super.setLayout(new GridLayout(3, 1)); // Disposizione griglia (3 righe, 1 colonna)

    checkBox = new JCheckBox("primo"); // Istanzia JCheckBox
    checkBox1 = new JCheckBox("secondo"); // Istanzia JCheckBox
    checkBox2 = new JCheckBox("terzo"); // Istanzia JCheckBox

    super.add(checkBox); // Aggiunge checkBox alla finestra
    super.add(checkBox1); // Aggiunge checkBox1 alla finestra
    super.add(checkBox2); // Aggiunge checkBox2 alla finestra

  • RISULTATO DEL CODICE:

  • JCheckBox


41. JComboBox (SWING)

  • Un «JComboBox» è un controllo grafico che permette all'utente di effettuare una scelta da un menù a tendina.

  • Da un oggetto «JComboBox» è possibile aggiungere o cancellare elementi dinamicamente. Per aggiungere un elemento al «JComboBox» ci serviremo del metodo «addItem()», viceversa useremo «removeItem()» per rimuoverlo.

  • [Download]

  • String[] colori = { "Giallo", "Blu", "Verde", "Arancione", "Nero" }; // Lista colori
    JComboBox lista; // Dichiara JComboBox
    String selezione;

    public Programma() {
    super("Test JComboBox");
    lista = new JComboBox(colori); // Istanzia JComboBox con elementi array
    lista.addItem("Viola"); // Aggiunge un altro colore alla lista (colore viola)
    lista.removeItem("Arancione"); // Rimuove un colore dalla lista (colore arancione)
    lista.setSelectedIndex(2); // Valore predefinito della lista (colore verde)
    lista.addActionListener(this); // Aggiunge ascoltatore per la lista

  • RISULTATO DEL CODICE:

  • JComboBox


42. JTabbedPane (SWING)


[Download]

super("Test JTabbedPane");
// Istanzia JPanel
panelScheda1 = new JPanel(new BorderLayout());
panelScheda2 = new JPanel(new BorderLayout());
// Istanzia JLabel
labelScheda1 = new JLabel("Questa è la prima scheda");
labelSchedaSUD = new JLabel("Questo è un testo in basso sulla prima scheda");
labelScheda2 = new JLabel("Questa è la seconda scheda");
// Allineamento JLabel
labelScheda1.setHorizontalAlignment(JLabel.CENTER);
labelScheda2.setHorizontalAlignment(JLabel.CENTER);
// Aggiunge JLabel a JPanel
panelScheda1.add(labelScheda1, BorderLayout.NORTH);
panelScheda1.add(labelSchedaSUD, BorderLayout.SOUTH);
panelScheda2.add(labelScheda2, BorderLayout.NORTH);
schede = new JTabbedPane(); // Istanzia JTabbedPane
// Aggiunge schede a JTabbedPane
schede.add("Scheda 1", panelScheda1);
schede.add("Scheda 2", panelScheda2);
schede.addChangeListener(this); // Aggiunge ascoltatore per le schede
super.add(schede); // Aggiunge le schede alla finestra

  • «JTabbedPane» permette di impostare un layout a schede all’interno del proprio programma, ogni scheda può essere aperta attraverso un singolo click del mouse.

  • RISULTATO DEL CODICE:

  • JTabbedPane


43. JMenuBar (SWING)


  • Il menù è un elemento fondamentale in un’applicazione grafica, poiché ci consente di accedere a tutte le funzioni del software da uno spazio ridotto.

  • Un menù può essere inserito istanziando un oggetto di tipo «JMenuBar», al quale bisogna aggiungere istanze di altri oggetti di tipo «JMenu» (che rappresentano le voci del menù principale); cliccando su una voce del menù principale, è possibile selezionare una delle altre voci secondarie di tipo «JMenuItem» (aggiunte al «JMenu» cliccato). Ecco un esempio:

  • [Download]

  • super("Test JMenuBar");
    menu = new JMenuBar(); // Istanzia JMenuBar

    file = new JMenu("File"); // Istanzia JMenu
    info = new JMenu("?"); // Istanzia JMenu

    nuovo = new JMenuItem("Nuovo"); // Istanzia JMenuItem
    apri = new JMenuItem("Apri"); // Istanzia JMenuItem

    … file.add(nuovo); // Aggiunge JMenuItem a JMenu
    file.add(apri); // Aggiunge JMenuItem a JMenu

    … menu.add(file); // Aggiunge JMenu a JMenuBar
    menu.add(Box.createHorizontalGlue()); // Posiziona i menù successivi sulla destra
    menu.add(info); // Aggiunge JMenu a JMenuBar
    super.setJMenuBar(menu); // Imposta la barra dei menù nella finestra

  • RISULTATO DEL CODICE:

  • JMenuBar


44. JFileChooser (SWING)


  • Per completezza implementeremo delle azioni che riguardano le voci di menù create, cominciamo da un componente che ci servirà ad aprire o salvare un file: stiamo parlando di «JFileChooser».

  • Ebbene, per aprire una finestra di dialogo di tipo «Open» con «JFileChooser» dovremo semplicemente chiamare il metodo «showOpenDialog();», mentre per una aprire una finestra di tipo «Save» utilizzeremo il metodo «showSaveDialog()».

  • I metodi «getSelectedFile()» e «getCurrentDirectory()» ci consentiranno rispettivamente di ottenere il nome e la directory del file selezionato.

  • [Download]

  • public void actionPerformed(ActionEvent e) {
    String selezione;
    JFileChooser file = new JFileChooser();
    // Finestra di dialogo Apri...
    case "Apri":
    int responso = file.showOpenDialog(this);
    if (responso == JFileChooser.APPROVE_OPTION) {
    System.out.println(file.​getCurrentDirectory().toString() + "\\" + file.getSelectedFile().getName());
    // Finestra di dialogo Salva...
    case "Salva":
    int responso = file.showSaveDialog(this);
    if (responso == JFileChooser.APPROVE_OPTION) {
    System.out.println(file.​getCurrentDirectory().toString() + "\\" + file.getSelectedFile().getName());
  • RISULTATO DEL CODICE:

  • JFileChooser


45. JOptionPane (SWING)


  • Per realizzare la finestra di dialogo delle informazioni, utilizzeremo il metodo statico «showMessageDialog()» della classe «JOptionPane».

  • «showMessageDialog()» è un metodo che accetta quattro parametri in ingresso in cui l'ultimo è il più significativo, poiché ci permette di scegliere il tipo di messaggio da visualizzare; i tipi principali di messaggio sono:

  • - INFORMATION_MESSAGE: per i messaggi informativi.
  • - WARNING_MESSAGE: per i messaggi che richiedono attenzione.
  • - ERROR_MESSAGE: per i messaggi di errore.

  • [Download]

  • // Finestra di informazioni
    case "Informazioni su...": {
    JOptionPane.showMessageDialog(null,"Domenico Boncoddo","Informazioni su...",JOptionPane.INFORMATION_MESSAGE);
    }

  • RISULTATO DEL CODICE:

  • JOptionPane (INFORMATION_MESSAGE)


46. JOptionPane (SWING)


  • Vediamo un’altra interessante variante che riguarda la classe «JOptionPane», che questa volta fa uso del metodo statico «showConfirmDialog()».

  • «showConfirmDialog()» permette di visualizzare una finestra di dialogo sulla quale è possibile effettuare una scelta relativa ad un messaggio personalizzabile.

  • [Download]

  • int risposta = JOptionPane.showConfirmDialog(null, "Vuoi maggiori info?", "Informazioni su...", JOptionPane.YES_NO_OPTION);

    if (risposta == 0) { // Se si...
    System.out.println("Hai risposto di sì");
    } else { // Se no...
    System.out.println("Hai risposto di no");
    }

  • RISULTATO DEL CODICE:

  • JOptionPane (YES_NO_OPTION)


47. Strumenti di disegno


  • Per concludere, voglio mostravi un esempio di finestra con delle forme elementari e un’immagine:

  • [Download]

  • class Cerchio extends JPanel {

    @Override
    public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g; // Istanzia la tela
    g2d.setColor(Color.RED); // Imposta colore da usare sulla tela
    BasicStroke b = new BasicStroke(6); // Istanzia ed imposta lo spessore
    g2d.setStroke(b); // Imposta spessore sulla tela
    Ellipse2D cerchio = new Ellipse2D.Double(10, 10, 100, 100); // Istanzia ed imposta un cerchio
    g2d.draw(cerchio); // Disegna un cerchio sulla tela
    g.drawString("Cerchio", 120, 110); // Disegna didascalia
    class Immagine extends JPanel {

    @Override
    public void paintComponent(Graphics g) {
    ImageIcon img = new ImageIcon("profilo.jpg"); // Istanzia immagine
    g.drawImage(img.getImage(), 10, 10, 150, 150, this); // Disegna immagine sulla tela

  • RISULTATO DEL CODICE:

  • Strumenti di disegno