gui e mvc - dipartimento di informaticamrt/didattica/proginrete-0304/mvc.pdfdi tutto: gui,...
Post on 04-Mar-2021
4 Views
Preview:
TRANSCRIPT
1
GUI e MVCProgrammazione in rete e laboratorio
Matteo BaldoniDipartimento di InformaticaUniversita` degli Studi di TorinoC.so Svizzera, 185 I-10149 Torino
baldoni@di.unito.ithttp://www.di.unito.it/~baldoni/didattica
2
Gli oggetti prima di tutto: GUI, Event-driven programming e l’architettura MVC
3
Graphical User InterfaceUn programma che fa uso di di strumenti grafici come bottoni, menu`, disegni, finestre, ecc. per facilitare le operazioni di input e visualizzazione dell’outputUn GUI per il contatore: una finestra che permetta di controllare l’invio dei messaggidi incremento, decremento, inizializzazione di un contatore, nonche` la visualizzazione delsuo valore corrente
public class Counter {public Counter() {
[…]}[…]public void init(int val){
c = val;}public void incr(){
c++;}public void decr(){
c--;}public int getVal(){
return c;}[…]private int c;private String nomeContatore;
}
4
Contatore GUI 0Desideriamo una interfaccia grafica per un contatore (descritto nelle lezioni precedenti) che contenga le seguenti funzionalita`:
un display per il valore correntetre bottoni per le operazioni di incr(), decr() e init(0)
un bottone per abbandonare l’interfaccia
decrementa il contatore di 1
incrementa il contatore di 1
chiude lafinestra
visualizza il valore corrente
inizializza ilcontatore a zero
chiude lafinestra
5
L’architettura Model View Controller
Un programma si compone di Modello (Model): modella e calcola il problema che desideriamo risolvereVista (View): rappresenta una “fotografia” dello stato interno del modello spesso per facilitarne la sua lettura/interpretazione all’utente umanoControllore (Controller): controlla il flusso di dati nel programma, dalla vista al modello e quindi nuovamente alla vista
http://www.cis.ksu.edu/~schmidt/CIS200
Ha origine negli applicativi sviluppati in SmalltalkE` stato utilizzato in Java per lo sviluppo delle componenti AWT/Swing
6
L’architettura Model View Controller
L’utente agisce sulla vista di un programma agendo su una delle sue componenti di controllo (es. bottone)Il controllore e` avvertito di tale evento ed esamina la vista per rilevarne le informazioni aggiuntiveIl controllore invia tali informazioni al modello che effettua la computazione richiesta e aggiorna il proprio stato internoIl controllo (o il modello)
http://www.cis.ksu.edu/~schmidt/CIS200
richiede alla vista di visualizzare il risultato della computazioneLa vista interroga il modello sul suo nuovo stato interno e visualizza l’informazione all’utente
2
7
Architettura MVC: vantaggi
Le classi che formano l’applicativo possono essere piu` facilmente riutilizzate
L’applicativo e` organizzato in parti piu` semplici e comprensibili (ogni parte ha le sue specifiche finalita`)
La modifica di una parte non coinvolge e non interferisce con le altre parti (maggiore flessibilita` nella manutenzione del software)
8
MVC: sequenza dei messaggi① viene premuto il bottone
“Decrementa”② l’evento e’ ascoltato dal
controller③ il controller invia il
messaggio di decr() al modello
④ il controller invia il messaggio di updateView() allavista
⑤ la vista richiede i dati al modello per aggiornarsi(getVal())
controller
model
view
model.decr()
view.updateView()
model.getVal()
event
①
②
③
④
⑤0 -1
actionPerformed(…)
ActionListener
9
Event-Driven ProgrammingE` alla base della programmazione delle GUIE` il nuovo tipo di input che deve essere trattato nella programmazione delle GUI (pressione di bottoni, mouse on/off, ecc.)L’utente genera tramite la GUI una serie di eventi a cui il controllore deve prontamente reagire in maniera opportunaHandling events: “processare” gli eventiIl controllore che processa gli eventi e` chiamato event handler o event listenerle informazioni sull’evento in Java sono memorizzate in opportuni oggetti (EventObject)
10
Delegation Event Model
Gli eventi messaggi passati dall’oggetto sorgente ad uno o piu` oggetti ascoltatoriQuando un evento e` passato causa l’invocazione di unmetodo dell’oggetto ascoltatoreGli eventi sono oggetti contenenti le informazioni relative al particolare evento che li ha determinati
Event Source Event ListenerEvent Object
Listener Registration
11
Event-Driven ProgrammingLa computazione e` guidata completamente dalla serie di eventi generati dall’utenteIl programma processa gli eventi come input e aggiorna il proprio modello interno e lo visualizza tramite la vistaIl controllo ha il compito di gestire il flusso di eventi e dati dalla vista al modello e quindi nuovamente verso la vistaPiu` controllori, viste e modelli possono coesistere a formare un programmaGli eventi devono essere generabili in maniera coerente da parte dell’utente (disabilita/abilita)
12
Event-Driven Programming
controller (e` registrato come ActionListener diDecrementa)
model
view
model.decr()
view.updateView()
model.getVal()
ActionEventevent
①
②
③
④
⑤0 -1
actionPerformed(event)
ActionListener
① OS intercetta l’evento“click di un bottone” e locomunica all’AWT/Swing
② AWT/Swing determina la sorgente dell’evento, creaun ActionEvent e loinvia all’incaricato ActionListener
③ la procedura actionPerformed(event) del controllore e` eseguita
④ il controllo invia gli opportuni messaggi al modello e alla vista
⑤ la vista si aggiorna interrogando il modello
④
3
13
Event-Driven ProgrammingOgni componente grafico (per esempio, un bottone) mantiene al suo interno una lista di listener objects(oggetti in ascolto) Un listener object ob è aggiunto alla lista di un oggetto btramite il messaggio b.addActionListener(ob)In generale, un componente grafico può avere molti listener objects e un listener object può “ascoltare” più componentiQuando un evento occorre, la lista viene scandita e a ogni listener object viene inviato il messaggio actionPerformed
14
AWT/Swing
Componenti (component): oggetti che possono avere una posizione e una dimensione nello schermo e nei quali possono occorrere eventi
Contenitori (container): componenti che possono contenere al loro interno altre componenti come, ad esempio, i pannelli (panel)
15
AWT/Swing
Finestre (windows): contenitori che possono essere visualizzati direttamente sullo schermo
Frame: finestre con titolo e menu visualizzate permanentemente sullo schermo durante l’esecuzione di unprogramma
Dialog: finestre visualizzate temporaneamente sullo schermo durante l’esecuzione di un programma (es. visualizzano messaggi di errore, input file, ecc)
16
Contatore GUI 0: view
JPanelBorderLayout
CENTERSOUTH
JPanelFlowLayout
JPanelFlowLayout
JButtonJButton
JButton
JLabel
valore contatore: ...
IncrementaDecrementa Reset
Contenitori Struttura delcontenitore JPanel
Componenti (in realta` sonoa loro volta contenitori, etichette,icon, …)
Componente
17
Creazione del contenitore JPanel della vistaUso del costruttore superLayout scelto: BorderLayout
Contatore GUI 0: view
public class CounterView extends JPanel {public CounterView(Counter model){
super(new BorderLayout());// alternativa: setLayout(new BorderLayout());[…]
}
CENTER
SOUTH
NORTH
WEST
EAST
18
Contatore GUI 0: viewpanelCenter: pannello da aggiungere al centro delBorderLayout del pannello principaleLayout scelto: FlowLayout
valore contatore: ...
[…]label = new JLabel(“Valore contatore: ");JPanel panelCenter = new JPanel(new FlowLayout()); panelCenter.add(label);add(panelCenter, BorderLayout.CENTER); […]
panelCenterlabel
4
19
Contatore GUI 0: viewpanelSouth: pannello a Sud nel pannello principale dellavistaLayout scelto: FlowLayout
valore contatore: ...
IncrementaDecrementa Reset
[…] JPanel panelSouth = new JPanel(new FlowLayout()); JButton bottoneDecr = new JButton("Decrementa"); panelSouth.add(bottoneDecr); JButton bottoneReset = new JButton("Reset");panelSouth.add(bottoneReset);JButton bottoneIncr = new JButton("Incrementa"); panelSouth.add(bottoneIncr);add(panelSouth, BorderLayout.SOUTH); […]
panelSouth
20
Contatore GUI 0: viewDefinizione del metodo updateView() per l’aggiornamento della vistaUso del modello(contatore) per reperirele informazioni necessarieper l’aggiornamento dellavista
public void updateView(){ label.setText("Valore Contatore: " + contatore.getVal());
}
valore contatore: ...
IncrementaDecrementa Reset
label
21
Contatore GUI 0: controllerTratta gli oggetti di tipo ActionEvent creati dall’AWT/Swing contenenti tutte le informazioni sull’evento occorso nell’interfaccia(vista)implementazione di ActionListener e definizione del metodo actionPerformed(ActionEvent)
public class CounterControl implements ActionListener {private Counter contatore;private CounterView contatoreVista;public CounterControl(Counter cont, CounterView contVista){
contatore = cont;contatoreVista = contVista;
}public void actionPerformed(ActionEvent e){
JButton source = (JButton)e.getSource(); // notare il cast!if (source.getText().equals("Decrementa")) contatore.decr(); else if (source.getText().equals("Incrementa")) contatore.incr();
else contatore.init(0); contatoreVista.updateView();
}}
22
Contatore GUI 0: aggancio del controllerpublic class CounterView extends JPanel {
public CounterView(Counter model){[…]contatore = model; […]controlloCounter = new CounterControl(contatore, this); […] JButton bottoneDecr = new JButton("Decrementa"); bottoneDecr.addActionListener(controlloCounter);[…] JButton bottoneReset = new JButton("Reset");bottoneReset.addActionListener(controlloCounter);[…]JButton bottoneIncr = new JButton("Incrementa"); bottoneIncr.addActionListener(controlloCounter);[…]updateView();
}
creazione del controllore
aggancio
23
Contatore GUI 0: MVC① Dal main si crea il
modello …② … e la vista③ la vista crea il
controllore (listener bottoni) e lo aggancia ai bottoni
• la vista riceve il modello tra i suoi parametri
• il controllore riceve trai suoi parametri la vista e il modello
model
view
①
②
③
0
actionPerformed(event)
ActionListener
controllermain
crea
crea
crea
inviamessaggi
inviamessaggi
eventi
24
Contatore GUI 0: overviewDiagramma delle classi per il contatoreGUI 0Introduzione di una interfaccia per la vistaContatoreFramecontiene il main e quindi crea la vista e il modelloExitButton e ExitFramecontrollano l’uscita dal programma principale
5
25
Contatore GUI 0: frame
Exit
Container(pannello del contenuto)
BorderLayoutCENTERSOUTH
JButton
windowClosing(…)
setTitle(…)
Contatore GUI
Finestra: JFrame
Strutturadel Container
Componente
Contenitore all’interno del JFrame
26
Contatore GUI 0: frame
valore contatore: ...
IncrementaDecrementa Reset
Exit
Container(pannello del contenuto)
BorderLayoutCENTERSOUTH
Contatore GUI 1: view
Contatore GUI
27
Contatore GUI 0: framepublic class ContatoreFrame extends JFrame {
public ContatoreFrame(){contatoreModello = new Counter(0); contatoreVista = new CounterView(contatoreModello);Container cp = getContentPane();cp.setLayout(new BorderLayout()); cp.add(contatoreVista, BorderLayout.CENTER);cp.add(new ExitButton(), BorderLayout.SOUTH);addWindowListener(new ExitFrame());setTitle("Contatore GUI");setSize(300, 140);setVisible(true);
}public static void main(String[] args) {
ContatoreFrame frame = new ContatoreFrame();}
private Counter contatoreModello;private CounterView contatoreVista;
}
per la chiusurasull “X” della finestra
il bottonedi Exit
il main e` tutto qua!!
28
Contatore GUI 0: frame
class ExitFrame extends WindowAdapter {public void windowClosing(WindowEvent e) {
System.exit(0);}
}
class ExitButton extends JButton implements ActionListener {public ExitButton () {
super("Exit");addActionListener(this);
}public void actionPerformed(ActionEvent e) {
System.exit(0);}
}
Classi per la chiusura dell’applicativo mediante la “X” sulla finestrae un bottone “Exit”Vanno bene per molti applicativi diversi dal contatore GUI
29
Si desidera rendere indipendente ilcontrollore dallavistaL’idea è quella che il controllore faccia riferimento ad una interfaccia anzichédirettamente allavista
Contatore GUI 1: l’indipendenza dalla vista
public class CounterView extends JPanel implements CounterInterfaceView {
[…]public updateView(){
[…]} […]
}
public interface CounterInterfaceView {void updateView();
}
30
Contatore GUI 1: controllerIl controllore non fa più riferimento ad un oggetto di tipo CounterViewma all’interfaccia di tipo CounterInterfaceViewTramite il binding dinamico si risolverà il riferimento al metodo updateView()
public class CounterControl implements ActionListener {private Counter contatore;private CounterInterfaceView contatoreVista;public CounterControl(Counter cont, CounterInterfaceView contVista){
contatore = cont;contatoreVista = contVista;
}public void actionPerformed(ActionEvent e){
JButton source = (JButton)e.getSource(); // notare il cast!if (source.getText().equals("Decrementa")) contatore.decr(); else if (source.getText().equals("Incrementa")) contatore.incr();
else contatore.init(0); contatoreVista.updateView();
}}
6
31
Contatore GUI 1: overviewDiagramma delle classi per il contatoreGUI 1Introduzione di una interfaccia per la vista
32
Contatore GUI 1( bis): l’indipendenza dalla vista
È estremamente semplice cambiare la vista CounterView con una nuova vista CounterViewBis,che allinea verticalmente i vari bottoni, senza toccare il codice della classe CounterControl
33
Contatore GUI 2Variante: il controllo contiene i bottoni
I bottoni sono il controllo
E` piu` facile determinare la sorgente
34
Contatore GUI 2: controller
public class CounterControl extends JPanel implements ActionListener {
[…]private JButton decrButton;[…]public CounterControl(Counter cont, CounterInterfaceView contVista){
[…]decrButton = new JButton("Decrementa"); add(decrButton); decrButton.addActionListener(this);[…]
}public void actionPerformed(ActionEvent e){
Object source = e.getSource();if (source == decrButton) contatore.decr(); else if (source == incrButton) contatore.incr();
else contatore.init(0);contatoreVista.updateView();
}}
posso determinarepiu` facilemente lasorgente essendo questa interna alla classe stessa
35
Inside Contatore GUI 1Sorgente:contiene i metodiper registrare e deregistrare gli ascoltatore e ilper inviare l’eventooggetto a tutti gli ascoltatori
Interfacciaascoltatore
Ascoltatore:implementa il metodo specificatonell’interfaccia
36
Inside Contatore GUI 1import java.util.*;public class JButton {
private ActionListener[] arrayOfActionListener;private Vector listOfActionListener = new Vector(); public synchronized void addActionListener(ActionListener al) {
listOfActionListener.add(l); } public synchronized void removeActionListener(ActionListener al) {
listOfActionListener.remove(l); } protected void notifyAction(Event e) {
ActionEvent ae = new ActionEvent(this, e)synchronized (this) {
arrayOfActionListener = listOfActionListener.toArray(); }for (int i=0; i<arrayOfActionListener.length; i++) {
arrayOfActionListener[i].actionPerformed(ae);}
}}
Nota: per binding dinamico verra` eseguira ilmetodo actionPerformed definito in CounterControl
7
37
Inside Contatore GUI 1public interface ActionListener extends java.util.EventListener {
public void actionPerformed(ActionEvent e);}
public class CounterControl implements ActionListener {[…]public void actionPerformed(ActionEvent e){
JButton source = (JButton)e.getSource(); if (source.getText().equals("Decrementa"))
contatore.decr(); else if (source.getText().equals("Incrementa"))
contatore.incr();else
contatore.init(0); contatoreVista.updateView();
}}
38
Contatore GUI 3Modifichiamo l’applicativo precedente in modo da poter inserire il valore iniziale del contatore
E` importante controllare il valore immesso, cioe` verificare se questo e` un numero intero e segnalare l’eventuale errore
decrementa il contatore di 1
incrementa il contatore di 1
chiude lafinestra
visualizza il valore corrente ol’eventuale errore
inizializza ilcontatore con
il valore immesso
chiude lafinestra
input del valoreiniziale del contatore
39
Contatore GUI 3: view
JPanelBorderLayout
NORTHCENTERSOUTH
JPanelFlowLayout
JButtonJButton
JButton
valore contatore: ...
IncrementaDecrementa Inizializza
JPanelFlowLayout
JLabel
JLabelvalore iniziale:
JTextField
JPanelFlowLayout
0
40
Contatore GUI 3: frame
Exit
Contatore GUI
valore contatore: ...
IncrementaDecrementa Inizializza
valore iniziale: 0
Container(pannello del contenuto)
BorderLayoutCENTERSOUTH
JButton
windowClosing(…)
setTitle(…)
Contatore GUI 3: view
41
Contatore GUI 3: controller
public void actionPerformed(ActionEvent e){ Object source = e.getSource(); if (source == initButton) {
try {int input = Integer.parseInt((contatoreVista.getInput()).trim());contatore.init(input); contatoreVista.setAnswer();
} catch(RuntimeException err){
contatoreVista.setError(err.getMessage()); }
}else {
if (source == incrButton) contatore.incr();else contatore.decr(); contatoreVista.setAnswer();
} contatoreVista.updateView();
}
lettura del valorein input nel campoJTextField tramite interrogazione dellavista
42
La Serie dei Contatori
Contatore GUI 4: in un frame due contatori (due modelli) con rispettivi viste (due viste) e controllori (due controllori)
Contatori GUI 5: si puo` facilmente cambiare vista senza cambiare ne` l’implementazione del modello ne` quello delcontrollore
Contatore GUI 6: una vista un po’ piu` complicata, una etichetta (JLabel) e un pannello grafico per illustrare il valore del modello
8
43
Contatore GUI 5
Una nuova vista per il contatore e` rappresentata dalla classe CounterViewDraw
Il valore del contatore e` rappresentato nella vista da un pannello con delle palline:
rosse se positivoblu se negativo
44
Contatore GUI 6
Le due viste precedenti sono unite in una unica: CounterView ospita unpannello della classe JPanelCounter
Il metodo updateViewdeve occuparsi dell’aggiornamento siadel pannello grafico sia della etichetta di tipo JLabel
45
Contatore GUI 7Piu` l’interfaccia si presenta complessa piu` diventa complesso il lavoro del controlloreIl controllore deve conoscere tutti gli oggetti che compongono la vista e contattarli tutti dopo aver inviato il messaggio al modelloObserver/Observable: permettonodi rendere ignorante il controllore della presenza delle viste. E` il Contatore GUI 6 realizzato con Observer/Observable
46
Event-Driven Programming with Observers
È possibile scrivere programmi che attivano i propri eventi internamente per mezzo della classe Observable e dell’interfaccia ObserverÈ possibile implementare listener objects per componenti non graficheQuando un oggetto genera un evento, gli “Osservatori”dell’oggetto ricevono un messaggio di updateUn oggetto ob è aggiunto alla lista di “osservatori” di unoggetto b tramite il messaggio b.addObserver(ob)
47
Contatore GUI 7Nessuna relazione diassociazione tra il controllo e la vista!Observer: e` una interfaccia nelpackage java.utilObservable: e` una classe nelpackage java.util
48
Contatore GUI 7: Modelimport java.util.*;
public class Counter extends Observable {[…]public void init(int val){
c = val;setChanged();notifyObservers();
}public void incr(){
c++;setChanged();notifyObservers();
}public void decr(){
c--;setChanged();notifyObservers();
}[…]
}
Definisce un oggetto osservabile ed eredita due nuovi metodi che sono usati per generare un evento
NB: il contatore non sa chi sono i suoi osservatori !!
9
49
Contatore GUI 7: Controller[…]public class CounterControl extends JPanel implements ActionListener {
private Counter contatore;[…]
public CounterControl(Counter cont){[…]// NON c'e` piu` bisogno della seguente!!//contatoreVista = contVista;[…]
}public void actionPerformed(ActionEvent e){
Object source = e.getSource();if (source == decrButton) contatore.decr();else if (source == incrButton) contatore.incr();else contatore.init(0);// NON c'e` piu` bisogno della seguente!!// contatoreVista.updateView();
}}
NB: il controller non menzionanessunavista !!
50
Contatore GUI 7: Aggancio del Controller[…]public class ContatoreFrame extends JFrame {
public ContatoreFrame(){Counter contatoreModello = new Counter(0);CounterView contatoreVista = new CounterView(contatoreModello);contatoreModello.addObserver(contatoreVista);Container cp = getContentPane();cp.setLayout(new BorderLayout());cp.add(contatoreVista, BorderLayout.CENTER);cp.add(new ExitButton(), BorderLayout.SOUTH);addWindowListener(new ExitFrame());setTitle("Contatore GUI");setSize(320, 220);;setVisible(true);
}public static void main(String[] args) {
ContatoreFrame frame = new ContatoreFrame();}
}
contatoreVistasi dichiara unascoltatore delcontatore
51
Contatore GUI 7: View[…]import java.util.*;
public class CounterView extends JPanelimplements CounterInterfaceView, Observer {
[…]public CounterView(Counter model){
[…]}
public void updateView(){label.setText("Valore Contatore: " + contatore.getVal());panelCounter.repaint();
}
public void update(Observable ob, Object extra_arg) {updateView();
}}
Implementa il metodo update
Implementa l’interfacciaObserver
52
E.-D. P. with Observers
controller (e` registrato come ActionListener diDecrementa)
model
view
model.decr()
view.update(...)
model.getVal()
ActionEventevent
①
②
③
⑤
0 -1
actionPerformed(event)
ActionListener
① OS intercetta l’evento “click di un bottone” e lo comunica all’AWT/Swing
② AWT/Swing determina la sorgente dell’evento, crea un ActionEvent e lo invia all’incaricato ActionListener
③ la procedura actionPerformed(event) del controllore e` eseguita
④ il controllo invia l’opportuno messaggio al modello
⑤ il modello notifica ai suoi ascoltatore l‘avvenuto l‘aggiornamento
⑥ gli ascoltatori eseguono il propio update
④
⑥
53
Event-Driven Programming with Observers
Vantaggistile di programmazione che disaccoppia ulteriormente le componenti del sistemail controller, a differenza degli esempi precedenti, non ha più la necessità di conoscere le viste del modello
Svantagginon è sempre possibile utilizzare questo schema perché ilmodello deve ‘estendere’ la classe Observable
54
La Serie dei Contatori
Contatore GUI 8: e` il Contatore GUI 7 dove la vista graficae` completamente slegata dalla vista principale (ma solo ospitata nel pannello)
Contatore GUI 9: e` il Contatore GUI 8 replicato 4 volte nella vista principale
10
55
Contatore GUI 8
E` il ContatoreGUI 7 dove la vista grafica e` completa-mente disacoppiatadalla vista principale (ma solo ospitata nel pannello)
56
Contatore GUI 8: View 1[…]public class CounterView extends JPanel
implements CounterInterfaceView, Observer {[…]public CounterView(Counter model){
[…]JPanelCounter panelCounter = new JPanelCounter(model);model.addObserver(panelCounter);add(panelCounter, BorderLayout.CENTER);[…]
}
public void updateView(){label.setText("Valore Contatore: " + contatore.getVal());
}
public void update(Observable ob, Object extra_arg) {updateView();
}}
Update della sola Jlabel e nonpiu` repaint!!
57
Contatore GUI 8: View 2[…]public class JPanelCounter extends JPanel
implements CounterInterfaceView, Observer {public JPanelCounter(Counter model) {
contatore = model;}
public void paintComponent(Graphics g) {[…]
}
public void updateView(){repaint();
}
public void update(Observable ob, Object extra_arg) {updateView();
}
}
Si autogestiscel’update essendo a sua volta unObserver delcontatore
58
Contatore GUI 9E` il Contatore GUI 8 replicando quattro volte la vista grafica nella vista principaleEstrema facilita` nel gestire viste complesse
[…]public class CounterView extends JPanel
implements CounterInterfaceView, Observer {private JPanelCounter[] arrayPanelCounter;public CounterView(Counter model){
[…]JPanel panelCenter = new JPanel(new GridLayout(2,2));JPanelCounter[] arrayPanelCounter = new JPanelCounter[4];for(int i=0;i<arrayPanelCounter.length;i++) {
arrayPanelCounter[i] = new JPanelCounter(model);model.addObserver(arrayPanelCounter[i]);panelCenter.add(arrayPanelCounter[i]);
}add(panelCenter, BorderLayout.CENTER);[…]
} […]
59
Per orientarsi: Event Object
Ogni oggetto evento in Java estende la classejava.util.EventObject
public class KeyboardEvent extends java.util.EventObject {private char key;KeyboardEvent (java.awt.Component source, char key) {
super(source);this.key = key;
}}
60
Per orientarsi: Event Listener
Ogni ascoltatore puo` essere rappresentato da un metodoin una data classeOgnuno di questi metodi e` invocato quando un particolare evento si verificaQuesti metodi possono essere logicamente raggruppati in una interfaccia che condividono lo stesso tipo di evento che estendono, in Java, la classe java.util.EventListener
interface KeyboardListener extends java.util.EventListener {void keyPressed(KeyboardEvent ke);void keyReleased(KeyboardEvent ke);
}
11
61
Per orientarsi: Event Listener
Un ascolatore per un determinato evento deve implementare la relativa interfaccia che specifica il metodo che tratta tale evento
class MyClass implements KeyboardListener {
public void keyPressed(KeyboardEvent ke) {// implementation of the method
}
public void keyReleased(KeyboardEvent ke) {// implementation of the method
}}
62
Per orientarsi: Event Listener RegistrationRappresenta il collegamento di un ascoltatore presso la/le sorgente/i degli eventi che vuole ascoltareTecnicamente questo e` denominato event registrationOgni oggetto sorgente di un evento deve provvedere due metodi per la registrazione e la deregistrazione degli eventuali ascoltatori
public void addKeyboardListener (KeyboardListener ke) { …
}public void removeKeyboardListener (KeyboardListener ke) {
…}
63
Per orientarsi: Event Listener Registration
E` consigliabile che i metodi di registrazione e deregistrazione presso la sorgente siano definitisynchronizedL’oggetto sorgente si incarica di mantenere una lista di tutti gli ascoltatori registrati presso di luiL’oggetto sorgente deve notificare l’evento occorso a tutti i suoi ascoltatori, questo e` realizzato inviando ad ognuno diessi l’oggetto evento mediante invocazione dell’opportuno metodo dell’ascoltatore.
64
Delegation Event Model: proviamo a costruirlo da noi
Tratto da: D. J. Berg e J. S. Fritzinger, Advanced Techniques for Java Developers, John Wiley & Sons, Inc., 1998, Cap. 2, pag. 13-22.Si vuole creare una classe Counter e una classe CounterEvent, la classe Counter permette di creare dei contatori che vengono incrementati ad intervalli random di tempo. Quando un contatore viene incrementato un oggetto CounterEvent è inviato agli ascoltatori CounterChangeListener registrati.
Counter
CounterEventCounterChangeListener
65
Delegation Event Model: proviamo a costruirlo da noipublic class Counter extends Thread {private java.util.Vector listeners = new java.util.Vector();private int count = 0;[…]public void run() {
while(true) {try {
sleep((int)Math.round(Math.random()*3000));}catch (InterruptedException e) {}count++;notifyCounterChange(count);
} }
public void startCounting() {this.start();
}
continua ...
Ogni contatore estendela classe Thread
Questo è il codiceeseguito in un threadseparato
Ogni volta che il valore delcontatore cambia viene eseguita la notifica a tutti gli ascoltatoridel contatore stesso memorizzati inun apposito Vector
66
Delegation Event Model: proviamo a costruirlo da noi
continua ...
protected void notifyCounterChange(int count) {java.util.Vector tmpList;CounterEvent ce = new CounterEvent(this, count);synchronized(this) {tmpList = (java.util.Vector) listeners.clone();
}for (int i=0; i<tmpList.size(); i++) {((CounterChangeListener)tmpList.elementAt(i)).
counterChange(ce);}
}
continua ...
Questo è il metodo di notificadell’evento ad ogni ascoltatore
listeners è una risorsa condivisa! Quando si estrae un oggetto daun Vector è
necessario fare un downcast per poterlo vedere come ascoltatore degli eventi CounterEvent e poter invocare il metodo counterChange(ce)
12
67
Delegation Event Model: proviamo a costruirlo da noi
continua ...
public synchronized void addCounterChangeListener(CounterChangeListener ccl)throws java.util.TooManyListenersException {
listeners.addElement(ccl);}
public synchronized void removeCounterChangeListener(CounterChangeListener ccl){
listeners.removeElement(ccl);}
}
listener è una risorsacondivisa!
registrazione e deregistrazione degli ascoltatori presso un contatore
68
Delegation Event Model: proviamo a costruirlo da noi
public class CounterEvent extends java.util.EventObject {private int count;
CounterEvent(Object source, int count) {super(source);this.count = count;}
public int getCount() {return(count);}
}
Un CounterEvent contieneanche la sorgente dell’evento,cioe` il contatore incrementato.
69
Delegation Event Model: proviamo a costruirlo da noi
public class CountTest implements CounterChangeListener {public static void main(String args[]) {
CountTest ct = new CountTest();}
public CountTest() {try {
Counter c = new Counter();c.addCounterChangeListener(this);c.startCounting();
}catch(Exception err) {
System.out.println("Error: " + err);}
}public void counterChange(CounterEvent evt) {System.out.println("Counter value has changed: " + evt.getCount());}
}
public interface CounterChangeListener extends java.util.EventListener {void counterChange(CounterEvent e);
} L’interfaccia!
Registrazione dell’ascoltatorepresso la sorgente degli eventi
Viene fatto partire un threadin cui il metodo run del contatoreè eseguito
Metodo eseguito ogni volta cheviene ascoltato un evento
top related