L'obiettivo di questo e dei succcessivi articoli è quello di portare, attraverso un approccio "Swing by examples", il lettore principiante all'utilizzo delle fondamenta della libreria Swing per la costruzione di applicazioni desktop in java.
Al fine di rendere il tutto più interessante, introdurremo i vari esempi tramite la realizzazione di una semplice applicazione (per il calcolo di prezzi con o senza iva), il cui unico prerequisito è soltanto la conoscenza di base del linguaggio Java.
La libreria Swing
Cos'è AWT
A partire dalla versione 1.0 dell'ambiente di sviluppo java venne fornita la libreria AWT (Abstract Window Toolkit). Si tratta di una libreria per creare interfacce grafiche in Java utilizzando componenti dipendenti dal sistema operativo.
In pratica il codice per la costruzione delle finestre sarà al solito indipendente dal sistema operativo (java come sappiamo è portabile, se si dispone di una virtual machine per eseguirlo), ma sia l'aspetto e lo stile dei componenti grafici che il comportamento delle finestre stesse saranno invece gestiti ed imposti dal sistema operativo.
Cos'è Swing
Swing è la libreria grafica di seconda generazione di Java, è stata introdotta dalla versione 1.2 in poi, allo scopo di disporre di un toolkit di sviluppo di GUI portabile su vari sistemi operativi, e fa parte di un gruppo di librerie note come Java Fountation Classes (JFC). A differenza di AWT, Swing non effettua chiamate native al sistema operativo per la costruzione dei componenti, ma li ricostruisce da zero.
Per questa caratteristica in molti casi AWT è più performante, ma esistono numerosi vantaggi nell'utilizzo di Swing:
- A partire dalla versione 1.6 delle JDK le performance sono migliorate sensibilmente, questa release ha proprio come caratteristica più importante le performance
- A differenza di AWT, Swing definisce qualsiasi tipo di componente di qualsiasi sistema operativo e addirittura ne inventa di nuovi
- I pulsanti e le label di Swing possono visualizzare anche immagini oltre che testo
- Grazie al supporto del cambio del look & feel, è possibile vedere GUI con stili di diversi sistemi operativi su uno stesso sistema operativo. (Possiamo ad esempio voler dare lo "stile mac" anche ad una applicazione eseguita su windows)
- Cambiare l'aspetto o il comportamento di un componente Swing si riduce semplicemente nell'invocare metodi o definire sottoclassi
- I componenti Swing non devono essere necessariamente rettangolari
- E' facile anche cambiare i bordi dei componenti cosi come gestire i tooltip
- La release 1.6 delle JDK porta con se un'interessante nuova caratteristica: una facility per creare splash screen in modo semplice e senza programmare.
I componenti Swing possono essere trovati nel package javax.swing
. I nomi delle classi iniziano tutti per convenzione con la lettera J, la parte rimanente del nome della classe rappresenta il nome del componente Swing: JButton
, JLabel
, JTextField
...
È importante sottolineare che non possono essere combinati con i componenti AWT, mentre invece i layout managers di AWT funzionano perfettamente con i componenti Swing, così come la gestione degli eventi.
In figura un esempio di semplice applicazione Swing:
(clic per ingrandire)
Swing come componenti "leggeri"
I componenti Swing sono un insieme molto ampio di componenti per le interfacce utente di tipo grafico, scritti in modo da avere un aspetto ed un comportamento indipendente dal sistema operativo su cui gira l'applicazione. Ciò è differente dai componenti AWT che fanno uso dei componenti GUI nativi del sistema operativo.
Ad esempio un pulsante AWT appare come un pulsante Windows su una macchina windows e come un pulsante Macintosh su una macchina Macintosh: la sua interazione con il programma rimane la stessa su tutte le piattaforme, ma all'utente verrà presentato l'aspetto nativo.
Un componente Swing ha lo stesso aspetto su tutte le piattaforme, visto che il suo codice è scritto in Java: si parla a tal proposito di componenti lightweight ("leggeri"), poiché non richiedono una allocazione di risorse da parte del sistema operativo al di fuori della JVM.
L'aspetto è espandibile e personalizzabile (look and feel), nel senso che ciascun utente può utilizzarne uno standard o inventarsene di nuovi.
Creazione della prima finestra (vuota)
Tanto per chiarire le idee, creiamo e visualizziamo una finestra vuota come la seguente:
La finestra in figura è realizzata attraverso la classe javax.swing.JFrame
.
Un JFrame è una finestra con una barra del titolo e un bordo.
La classe JFrame è una sottoclasse di java.awt.Frame
che, a sua volta, è una sottoclasse di java.awt.Window
. Per questi motivi JFrame è uno dei componenti GUI di Swing che non è considerato un componente leggero: a differenza della maggior parte dei componenti Swing, JFrame non è scritto esclusivamente in Java, ma va considerato una sorta di "wrapper" sulle finestra native del sistema.
Importiamo quindi prima di tutto questa classe e creiamo una sua istanza all'interno del metodo main, questa istanza crea una finestra come risorsa ma non la visualizza ancora:
import javax.swing.JFrame;
public class EmptyFrame {
public static void main(String[] args) {
JFrame jFrame = new JFrame("Empty window");
// la finestra è creata ma non ancora visibile!
}
}
Quando visualizziamo una finestra in un programma Java, la finestra fa parte dell'insieme dei componenti della piattaforma locale, ha in pratica di default la forma e l'aspetto di tutte le altre finestre del sistema operativo in uso, e ne eredita anche i comportamenti predefiniti. Per modificare queste caratteristiche bisogna intervenire successivamente sul componente, ma per ora accontentiamoci dell'uso standard.
JFrame: istanziazione, visualizzazione e rilascio di risorse
La classe JFrame supporta 3 differenti operazioni in risposta all'azione di chiusura da parte dell'utente.
Bisogna tenere a mente che i programmi dotati di interfaccia grafica hanno un ciclo di vita completamente diverso rispetto a quelli che non la hanno.
Quando eseguiamo un'applicazione Java senza GUI (Graphical User Interface) la sua durata è quella di esecuzione del main e di tutti i thread creati, mentre nel momento in cui viene visualizzata la GUI del nostro programma, la Java Virtual Machine fa partire un nuovo thread che mantiene sullo schermo la GUI stessa e cattura eventuali eventi su essa. Quindi un'applicazione dotata di GUI, una volta lanciata, rimane in attesa dell'input utente e termina solo in base ad un determinato evento (es. click su un pulsante close,chiusura della finestra...).
Per default una finestra viene nascosta: questo significa rimossa semplicemente dallo schermo.
Possiamo controllare questo tipo di azione attraverso il metodo setDefaultCloseOperation
di JFrame:
import javax.swing.JFrame;
public class EmptyFrame {
public static void main(String[] args) {
JFrame jFrame = new JFrame("Empty window");
// definiamo il comportamento per la chiusura
jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
}
L'interfaccia WindowConstants
(una delle interfacce implementate da JFrame) del package javax.swing
definisce 3 costanti da utilizzare con questo metodo: DISPOSE_ON_CLOSE
, DO_NOTHING_ON_CLOSE
, HIDE_ON_CLOSE
(default).
Un finestra deve essere considerata una risorsa da resitutire al sistema quando non più necessaria; bisogna chiamare il metodo setDefaultCloseOperation
con l'argomento JFrame.DISPOSE_ON_CLOSE
(oppure WindowConstants. DISPOSE_ON_CLOSE
).
Se scegliamo DO_NOTHING_ON_CLOSE
indichiamo che saremo noi a decidere di volta in volta cosa fare quando l'utente chiude una finestra, in questo caso particolare dovremo però far uso del metodo dispose()
, da invocare sul JFrame per la restituzione della finestra al sistema.
Per default una finestra non viene visualizzata sullo shermo fino a quando non viene chiamato il suo metodo show()
, oppure, come fatto precedentemente, chiamando il metodo setVisible(true)
.
La dimensione di una finestra dovrebbe essere inoltre impostata con una chiamata al metodo setSize()
ereditato dalla classe java.awt.Component
. Il codice completo per mostrare la finestra in figura è quindi il seguente:
import javax.swing.JFrame;
public class EmptyFrame {
public static void main(String[] args) {
JFrame jFrame = new JFrame("Empty window");
jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jFrame.setSize(400,400);
jFrame.setVisible(true);
}
}
Conclusioni
In questo primo articolo abbiamo introdotto la libreria Swing e visto gli aspetti fondamentali per costruire una finestra Swing di base attraverso la classe JFrame. Vedremo nel prossimo articolo come aggiungere componenti (pulsanti, input text...), la gestione della disposizione all'interno della finestra, la gestione degli eventi generati dai componenti stessi. Costruiremo infine la nostra prima semplice applicazione Swing per il calcolo del prezzo con o senza iva (PriceExtractor), così da mettere in pratica passo-passo i concetti esposti.