GUI con Swing

Oggigiorno diamo per scontato che un software destinato all'utente medio abbia una GUI (Graphical User Interface), infatti tutte le applicazioni moderne ne hanno una. Negli anni '80 e primi '90 non era proprio così scontato, la maggior parte dei programmi si usava da riga di comando perché DOS non aveva interfaccia grafica. Con l'arrivo di Windows e OSX inizia l'era delle interfacce grafiche: finestre, icone e colori. Negli anni successivi il prezzo dei PC diventa competitivo e ogni famiglia comincia ad acquistarne uno; il concetto di GUI si evolve sempre di più, diventando talmente vasto da richiedere una nuovo specialista del settore: lo User Experience Developer.

Dopo quasi 30 anni di testing, si può dire che avere una GUI in un software ne facilita l'utilizzo, aumenta la produttività e lo rende più user friendly, tutte caratteristiche che vorremmo avere in ogni nostro software. Vediamo quindi come realizzare una GUI in Java.

AWT, Swing e JavaFX

Le principali librerie per realizzare un'interfaccia grafica in Java sono tre: AWT, Swing e JavaFX. AWT (Abstract Window Toolkit) è stata la prima e Swing si basa su di essa offrendo però più componenti. JavaFX invece utilizza un file xml per descrivere il layout dei componenti, ed è diventata lo standard. In questa guida ci concentreremo su Swing, che a mio parere è anche il più semplice.

La Prima Finestra

Proviamo a scrivere un semplice programma che mostra una finestra con un bottone.

import javax.swing.*;

public class Finestra {
    public static void main(String[] args) {
        
        JFrame f = new JFrame(); //Nuova finestra
        
        JButton b = new JButton("Ciao!"); //Nuovo bottone con testo 'Ciao!'
        
        //Posizionamento del bottone (partendo da in alto a destra) e dimensioni: 
        // spostato a destra di 100px e in basso di 150px
        // larghezza = 100px, altezza = 50px
        b.setBounds(100, 150, 100, 50); 
        
        f.add(b); //Aggiungo il bottone alla finestra
        
        f.setSize(300, 400); //Dimensioni della finestra: larghezza = 400px, altezza = 300px
        
        f.setLayout(null); //Nessun layout
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Quando chiudo la finestra termino il programma
        f.setVisible(true); //Rendo visibile la finestra
    }
} 

La prima cosa da fare in Swing è creare la vera e propria finestra con il componente JFrame. Dobbiamo poi istanziare un bottone usando la classe JButton. Impostiamo poi la posizione e la dimensione del bottone con setBounds() per poi aggiungerlo alla finestra tramite add(). Andiamo poi ad impostare la dimensione della finestra con setSize(). Infine specifichiamo che questa finestra non ha alcun layout tramite setLayout() e la rendiamo visibile con setVisible(). Non dimentichiamoci di impostare che il programma termina quando chiudiamo la finestra con setDefaultCloseOperation()!

Fin qua tutto semplice, avviando il programma ci troviamo davanti una finestra così:

Finestra con bottone

Eventi

La nostra app così com'è un po' inutile, cliccando il bottone non succede niente. Questo perché non abbiamo detto al bottone cosa fare quando viene cliccato. La interfacce grafiche lavorano ad eventi, per esempio dal clic di un bottone parte un evento; Questo viene ricevuto da una classe in ascolto e viene eseguito del codice.

Quello che dobbiamo fare noi è aggiungere un ActionListener al bottone, una classe che ascolta eventi di tipo ActionPerformed. Al clic del bottone si dovrà aprire un popup con scritto che abbiamo fatto clic.

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

//Implementiamo ActionListener
public class Finestra implements ActionListener {

    JFrame frame;
    JButton bottone;

    public Finestra() {
        frame = new JFrame();

        bottone = new JButton("Cliccami!");

        bottone.addActionListener(this); // Aggiungiamo l'action listener al botton (this perchè implementiamo ActionListener in questa classe)

        bottone.setBounds(100, 150, 100, 50);

        frame.add(bottone);

        frame.setSize(300, 400);

        frame.setLayout(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        Finestra f = new Finestra();
    }

    // Questo è il metodo che verrà chiamato quando clicchiamo il bottone
    public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(frame, "Hai cliccato il bottone!");
    }

} 

Al clic del bottone uscirà questo popup:

Popup

Layout e componenti

Provando ad aggiungere qualche altro bottone ci rendiamo subito conto che creare un'interfaccia grafica da codice diventa abbastanza noioso. Fortunatamente sia IntelliJ che Eclipse offrono degli strumenti grafici per semplificarci il lavoro.

Usando GUI Designer di Intellij...

GUI Designer

...mi viene generato automaticamente il seguente codice:

import javax.swing.*;
import java.awt.*;

public class Finestra {
    private JPanel panel1;
    private JButton button1Button;
    private JButton button3Button;
    private JButton button2Button;
    private JButton button4Button;
    private JButton button5Button;

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setContentPane(new Finestra().panel1);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        panel1 = new JPanel();
        panel1.setLayout(new BorderLayout(0, 0));
        button1Button = new JButton();
        button1Button.setText("Button 1");
        panel1.add(button1Button, BorderLayout.NORTH);
        button3Button = new JButton();
        button3Button.setText("Button 3");
        panel1.add(button3Button, BorderLayout.EAST);
        button2Button = new JButton();
        button2Button.setText("Button 2");
        panel1.add(button2Button, BorderLayout.WEST);
        button4Button = new JButton();
        button4Button.setText("Button 4");
        panel1.add(button4Button, BorderLayout.SOUTH);
        button5Button = new JButton();
        button5Button.setText("Button 5");
        panel1.add(button5Button, BorderLayout.CENTER);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return panel1;
    }

}

Nel GUI Designer di IntelliJ abbiamo modo di vedere tutti componenti grafici che possiamo utilizzare nella nostra app, e anche i layout che possiamo usare. Con la gerarchia delle classi sottomano possiamo quindi dire che:

  • Una Window può essere un JFrame (finestra classica) o un JDialog (popup)
  • Un JComponent è un elemento della UI (Bottoni, testo, tabelle, menu, slider...)
  • Un JFrame può contenere un solo JPanel
  • Un JPanel può contenere può contenere più JPanel e JComponent
  • Un JPanel permette di utilizzare un layout per disporre gli elementi in ordine (trovate una rappresentazione grafica dei layout a questo link)

Swing Diagram

© Nicola Bovolato 2020