1. Introduzione agli eventi
In programmazione un evento è un segnale che qualcosa è accaduto. Può essere la pressione di un pulsante, l’inserimento di testo, il completamento del caricamento dei dati, la modifica del valore di una variabile — insomma, qualsiasi cosa possa accadere nella tua applicazione e a cui tu, come sviluppatore, vuoi reagire.
Per analogia, un evento è come il campanello alla porta: qualcuno è arrivato e tu decidi cosa fare. Puoi aprire la porta, ignorare, fingere di non essere in casa, o persino chiamare tutti i familiari a vedere chi è arrivato. In programmazione l’evento è il «campanello», e la tua reazione è il gestore dell’evento.
In Java gli eventi sono la base della programmazione reattiva e della programmazione grafica (GUI). Senza di essi non avremmo pulsanti, menu a discesa, applicazioni a finestre e persino molti sistemi lato server.
Listener: cos’è e a cosa serve
Listener è un oggetto che si sottoscrive a un determinato evento e aspetta che accada. Non appena l’evento si verifica, il listener riceve un segnale ed esegue il codice di reazione previsto.
In Java i listener sono di solito realizzati tramite interfacce. Uno degli esempi più diffusi è l’interfaccia ActionListener. Viene implementata dalle classi che devono reagire alle azioni dell’utente, per esempio alla pressione di un pulsante.
In pratica l’interazione funziona così: c’è una sorgente di eventi, per esempio un pulsante, e c’è un listener — un oggetto che implementa l’interfaccia necessaria. La sorgente mantiene l’elenco di tutti i listener che vi sono sottoscritti. Quando l’utente preme il pulsante, la sorgente dell’evento chiama un metodo speciale su ciascuno dei listener.
Questo schema è simile a un abbonamento alle notizie: finché sei abbonato, riceverai notifiche. Nel caso di Java tale notifica è la chiamata del metodo del listener, che esegue azioni descritte in precedenza.
2. Interfacce degli eventi: ActionListener, MouseListener e altri
In Java per ogni tipo di evento esiste una specifica interfaccia di listener:
| Tipo di evento | Interfaccia del listener | Dove si usa |
|---|---|---|
| Azione | |
Pulsanti, menu, timer |
| Mouse | |
Componenti che reagiscono al mouse |
| Tastiera | |
Campi di testo, qualsiasi componente |
| Modifica | |
Slider, checkbox, modelli di dati |
| Documento | |
Modifiche nel testo (ad esempio, JTextField) |
Ciascuna di queste interfacce definisce uno o più metodi da implementare. Per esempio, ActionListener richiede l’implementazione del metodo actionPerformed(ActionEvent e).
Esempio: ActionListener
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class MyActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Il pulsante è stato premuto!");
}
}
3. Principio di funzionamento del modello a eventi
L’intero modello a eventi di Java si basa su un meccanismo semplice ma potente:
- La sorgente dell’evento (per esempio, un pulsante) mantiene un elenco di listener.
- Quando si verifica un’azione (per esempio, l’utente fa clic sul pulsante), la sorgente crea un oggetto evento (per esempio, ActionEvent).
- La sorgente scorre tutti i listener registrati e chiama il loro metodo corrispondente (per esempio, actionPerformed), passando loro l’oggetto evento.
- Ciascun listener decide autonomamente come gestire l’evento.
Schema di funzionamento degli eventi:
flowchart LR
A[L'utente ha premuto il pulsante] --> B[Il pulsante ha creato l'evento]
B --> C[Il pulsante chiama actionPerformed su tutti i listener]
C --> D[Il listener reagisce: esegue il proprio codice]
Esempio di codice:
import javax.swing.*;
public class EventDemo {
public static void main(String[] args) {
JButton button = new JButton("Premimi!");
button.addActionListener(new MyActionListener());
JFrame frame = new JFrame("Esempio di evento");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(button);
frame.setSize(200, 100);
frame.setVisible(true);
}
}
Quando l’utente preme il pulsante, il metodo actionPerformed di tutti i listener registrati viene eseguito.
4. Esempio: aggiungere un listener a un pulsante
Vediamo lo schema classico con un esempio semplice.
Passo 1. Creiamo il pulsante
JButton button = new JButton("Saluta");
Passo 2. Creiamo il listener
class HelloListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Ciao, mondo!");
}
}
Passo 3. Registriamo il listener
button.addActionListener(new HelloListener());
In breve: com’è nel codice
JButton button = new JButton("Saluta");
button.addActionListener(new HelloListener());
5. Classi anonime ed espressioni lambda: breve e comodo
Classe anonima
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Listener anonimo: ciao!");
}
});
Espressione lambda (Java 8+)
button.addActionListener(e -> System.out.println("Lambda! Ciao!"));
La lambda è il modo più conciso per aggiungere un listener quando la tua reazione all’evento consiste in una o due righe.
6. Come si collega alla tua applicazione?
Integrare questo meccanismo nella tua applicazione didattica. Per esempio, abbiamo una finestra semplice con il pulsante «Aggiungi attività». Quando si preme il pulsante vogliamo aggiungere una nuova attività all’elenco e stampare un messaggio.
Esempio di codice:
import javax.swing.*;
import java.awt.event.ActionListener;
public class TaskManagerGUI {
public static void main(String[] args) {
JFrame frame = new JFrame("Gestore attività");
JButton addButton = new JButton("Aggiungi attività");
// Usiamo una lambda come listener
addButton.addActionListener(e -> {
System.out.println("Attività aggiunta!");
// Qui potrebbe esserci la logica per aggiungere l'attività all'elenco
});
frame.add(addButton);
frame.setSize(300, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Ora la tua applicazione non si limita a eseguire istruzioni, ma «reagisce» alle azioni dell’utente!
7. Errori tipici nella gestione di listener ed eventi
Errore n. 1: ci si è dimenticati di registrare il listener. Se hai creato un listener ma non lo hai aggiunto alla sorgente dell’evento, il tuo codice non verrà mai eseguito. È come abbonarsi a una rivista ma non inviare la richiesta — la rivista non arriverà.
Errore n. 2: lo stesso listener registrato più volte. Se aggiungi per errore lo stesso listener più volte, il gestore verrà chiamato tante volte quante lo hai aggiunto. A volte è utile, ma più spesso è la fonte di bug strani («perché la mia funzione si attiva tre volte?!»).
Errore n. 3: ci si è dimenticati di rimuovere il listener. Se il listener non serve più ma non lo rimuovi, resta in memoria. Nelle applicazioni di lunga durata ciò può portare a perdite di memoria.
Errore n. 4: operazioni lunghe nel gestore dell’evento. Se fai un lavoro pesante direttamente nel gestore (per esempio, carichi dati da internet), l’interfaccia «si blocca» e l’utente si innervosisce. Meglio avviare il lavoro pesante in un thread separato.
Errore n. 5: eccezioni non gestite nel listener. Se nel tuo gestore si verifica un’eccezione, può interrompere l’intera catena di eventi. Registra nel log gli errori e gestisci le eccezioni, in modo che l’applicazione non vada in crash.
GO TO FULL VERSION