Nella programmazione tradizionale, anche con il linguaggio Java, abbiamo una funzione principale che controlla tutta l’esecuzione del programma ( metodo main ), se questo necessita di un dato dall’utente si mette in attesa e dopo averlo ricevuto lo analizza e compie l’azione. Se noi inseriamo nel metodo main un ciclo while che termina quando viene dato un determinato comando, abbiamo ancora l’attesa del programma per l’input dell’utente che poi reagisce facendo qualcosa. Se il ciclo degli eventi fosse proprio dell’applicazione allora avremmo dei conflitti tra i vari programmi in esecuzione nel catturare l’input dell’utente. Il sistema operativo quando apre una nuova applicazione e quindi una finestra di questa, la registra come un bersaglio di eventi dell’utente, a questo punto quando si ha un evento su una finestra è il sistema operativo a determinare a quale programma inviare il messaggio dell’azione che poi sarà l’applicazione a gestire. La finetra bersaglio è sempre una sola, quella che ha il cosiddetto focus, cioé la possibilità di avere l’input dell’utente, ecco come il sistema operativo riesce a determinare il bersaglio esatto di un’azione ( avete mai notato che quando si ha una finestra non attiva e si fa clic su un suo tasto, non viene compiuta l’azione del tasto, bensì viene attivata soltanto la finestra? ). La funzione che viene invocata dal gestore dell’interfaccia grafica al verificarsi di un evento si chiama callback per indicare il fatto che non è il programma a richiamarla bensì il sistema che gestisce l’input dell’utente e la grafica.
Quanto detto finora non dipende dal linguaggio di programmazione utilizzato per programmare l’interfaccia grafica. Vediamo quindi come in Java sia possibile gestire gli eventi provenienti dal sistema operativo e poi lo metteremo in pratica con l’esempio più semplice possibile, la pressione di un pulsante. Il modello degli eventi Java segue uno schema produttore-consumatore in cui il componente che può generare eventi segnala ad oggetti che si dichiarano interessati a ricerverli. Quando si attiva un evento sul componente esso invoca un metodo per tutti gli oggetti registrati ad ascoltarlo. L’oggetto che vuole ascoltare l’evento e gestirlo deve implementare determinate interfacce che terminano per Listener, quindi la pressione del tasto del mouse viene implementata con l’interfaccia MouseListener.
import java.awt.Frame; import java.awt.Button; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class Bottone implements ActionListener { private Frame m_nFrame; private Button m_nButton; private boolean m_bPressed; public Bottone(Frame f, Button b) { m_nFrame = f; m_nButton = b; m_bPressed = false; } public void actionPerformed(ActionEvent evt) { if (m_bPressed) { m_nFrame.dispose(); System.exit(0); } else { m_bPressed = true; m_nButton.setLabel("Premi per uscire!"); } } public static void main(String[] args) { Frame f = new Frame("Evento Bottone"); Button b = new Button("Premi qui!"); Bottone bt = new Bottone(f, b); b.addActionListener(bt); f.add(b); f.pack(); f.setVisible(true); } }
Questo esempio è il più semplice possibile per farvi capire come funzionano gli eventi, abbiamo creato una finestra principale ( Frame ) alla quale abbiamo inserito un pulsante ( Button ) che poi abbiamo passato nel costruttore della nostra classe registrata ( implementa l’interfaccia ActionListener ) per gestire i messaggi ed in particolare abbiamo inserito la classe Bottone come ActionListener del Button ( b.addActionListener(bt) ). Da dire che una classe che implementa l’interfaccia ActionListener deve avere il metodo actionPerformed che compie l’azione dell’evento che è descritto da un oggetto di tipo ActionEvent.