CodeGym /Corsi /JAVA 25 SELF /Ascoltatori (Listeners) e interfacce degli eventi

Ascoltatori (Listeners) e interfacce degli eventi

JAVA 25 SELF
Livello 50 , Lezione 0
Disponibile

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
ActionListener
Pulsanti, menu, timer
Mouse
MouseListener
Componenti che reagiscono al mouse
Tastiera
KeyListener
Campi di testo, qualsiasi componente
Modifica
ChangeListener
Slider, checkbox, modelli di dati
Documento
DocumentListener
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:

  1. La sorgente dell’evento (per esempio, un pulsante) mantiene un elenco di listener.
  2. Quando si verifica un’azione (per esempio, l’utente fa clic sul pulsante), la sorgente crea un oggetto evento (per esempio, ActionEvent).
  3. La sorgente scorre tutti i listener registrati e chiama il loro metodo corrispondente (per esempio, actionPerformed), passando loro l’oggetto evento.
  4. 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.

1
Compito
JAVA 25 SELF, livello 50, lezione 0
Bloccato
Cuore del modulo di comando dell'astronave 🚀
Cuore del modulo di comando dell'astronave 🚀
1
Compito
JAVA 25 SELF, livello 50, lezione 0
Bloccato
Posto di comando per il lancio del razzo ☄️
Posto di comando per il lancio del razzo ☄️
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION