gui e mvc - diunitobaldoni/didattica/splppp0102/guiemvc.pdf · mvc: sequenza dei messaggi ① viene...

35
1 GUI e MVC Linguaggi di Programmazione: Paradigmi di Programmazione (Sperimentazioni) Matteo Baldoni Dipartimento di Informatica Universita` degli Studi di Torino C.so Svizzera, 185 I-10149 Torino [email protected] http://www.di.unito.it/~baldoni/didattica 2 Gli oggetti prima di tutto: GUI, Event-driven programming e l’architettura MVC

Upload: others

Post on 09-Aug-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

1

GUI e MVCLinguaggi di Programmazione: Paradigmidi Programmazione (Sperimentazioni)

Matteo BaldoniDipartimento di InformaticaUniversita` degli Studi di TorinoC.so Svizzera, 185 I-10149 Torino

[email protected]://www.di.unito.it/~baldoni/didattica

2

Gli oggetti primadi tutto: GUI,Event-drivenprogramming el’architettura MVC

Page 2: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

2

3

Graphical User Interface� Un programma che fa uso di di

strumenti grafici come bottoni,menu`, disegni, finestre, ecc. perfacilitare le operazioni di input evisualizzazione dell’output

� Un GUI per il contatore: unafinestra che permetta dicontrollare 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 0� Desideriamo una interfaccia

grafica per un contatore(descritto nelle lezioniprecedenti) che contenga leseguenti funzionalita`:

� un display per il valorecorrente

� tre bottoni per le operazionidi incr(), decr() einit(0)

� un bottone per abbandonarel’interfaccia

decrementa il contatore di 1

incrementa il contatore di 1

chiude lafinestra

visualizza il valore corrente

inizializza ilcontatore a zero

chiude lafinestra

Page 3: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

3

5

L’architetturaModel View Controller

Un programma si compone di� Modello (Model): modella e

calcola il problema chedesideriamo risolvere

� Vista (View): rappresenta una“fotografia” dello stato internodel modello spesso perfacilitarne la sualettura/interpretazioneall’utente umano

� Controllore (Controller):controlla il flusso di dati nelprogramma, dalla vista almodello e quindi nuovamentaalla vista

http://www.cis.ksu.edu/~schmidt/CIS200

� Ha origine negli applicativisviluppati in Smalltalk

� E` stato utilizzato in Java per losviluppo delle componentiAWT/Swing

6

L’architetturaModel View Controller

� L’utente agisce sulla vista diun programma agendo su unadelle sue componenti dicontrollo (es. bottone)

� Il controllore e` avvertito di taleevento ed esamina la vista perrilevarne le informazioniaggiuntive

� Il controllore invia taliinformazioni al modello cheeffettua la computazionerichiesta e aggiorna il propriostato interno

� Il controllo (o il modello)

http://www.cis.ksu.edu/~schmidt/CIS200

richiede alla vista di visualizza-re ilrisultato della computazione

� La vista interroga il modello sul suonuovo stato interno e visulizzal’informazione all’utente

Page 4: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

4

7

Architettura MVC: vantaggi

� Le classi che formano l’applicativo possono essere piu`facilmente riutilizzate

� L’applicativo e` organizzato in parti piu` semplici ecomprensibili (ogni parte ha le sue specifiche finalita`)

� La modifica di una parte non coinvolge e non interferiscecon le altre parti (maggiore flessibilita` nella manutenzionedel software)

8

MVC: sequenza dei messaggi� viene premuto il bottone

“Decrementa”� l’evento e’ ascoltato dal

controller� il controller invia il

messaggio di decr() almodello

� il controller invia ilmessaggio diupdateView() allavista

� la vista richiede i dati almodello per aggiornarsi(getVal())

controller

model

view

model.decr()

view.updateView()

model.getVal()

event

�0 -1

actionPerformed(…)

ActionListener

Page 5: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

5

9

Event-Driven Programming� E` alla base della programmazione delle GUI� E` il nuovo tipo di input che deve essere trattato nella

programmazione delle GUI (pressione di bottoni, mouseon/off, ecc.)

� L’utente genera tramite la GUI una serie di eventi a cui ilcontrollore deve prontamente reagire in maniera opportuna

� Handling events: “processare” gli eventi� Il controllore che processa gli eventi e` chiamato event

handler o event listener� le informazioni sull’evento in Java sono memorizzate in

opportuni oggetti (EventObject)

10

Delegation Event Model

� Gli eventi messaggi passati dall’oggetto sorgente ad uno opiu` oggetti ascoltatori

� Quando un evento e` passato causa l’invocazione di unmetodo dell’oggetto ascoltatore

� Gli eventi sono oggetti contenenti le informazioni relative alparticolare evento che li ha determinati

Event Source Event ListenerEvent Object

Listener Registration

Page 6: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

6

11

Event-Driven Programming� La computazione e` guidata completamente dalla serie di

eventi generati dall’utente� Il programma processa gli eventi come input e aggiorna il

proprio modello interno e lo visualizza tramite la vista� Il controllo ha il compito di gestire il flusso di eventi e dati

dalla vista al modello e quindi nuovamente verso la vista� Piu` controllori, viste e modelli possono coesistere a

formare un programma� Gli eventi devono essere generabili in maniera coerente da

parte dell’utente (disabilita/abilita)

12

Event-Driven Programming

controller (e` registrato come ActionListener di Decrementa)

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 lasorgente dell’evento, creaun ActionEvent e loinvia all’incaricatoActionListener

� la proceduraactionPerformed(event) del controllore e`eseguita

� il controllo invia gliopportuni messaggi almodello e alla vista

� la vista si aggiornainterrogando il modello

Page 7: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

7

13

Event-Driven Programming� Ogni 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 listenerobjects e un listener object può “ascoltare” più componenti

� Quando un evento occorre, la lista viene scandita e a ognilistener object viene inviato il messaggioactionPerformed

14

AWT/Swing

� Componenti (component): oggetti che possono avere unaposizione e una dimensione nello schermo e nei qualipossono occorrere eventi

� Contenitori (container): componenti che possonocontenere al loro interno altre componenti come, adesempio, i pannelli (panel)

Page 8: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

8

15

AWT/Swing

� Finestre (windows): contenitori che possono esserevisualizzati direttamente sullo schermo

� Frame: finestre con titolo e menu visualizzatepermanentemente sullo schermo durante l’esecuzione di unprogramma

� Dialog: finestre visualizzate temporaneamente sulloschermo 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

Page 9: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

9

17

� Creazione del contenitoreJPanel della vista

� Uso del costruttore super� Layout 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: view� panelCenter: pannello da

aggiungere al centro delBorderLayout del pannelloprincipale

� Layout scelto: FlowLayout

valore contatore: ...

[…] label = new JLabel(“Valore contatore: "); JPanel panelCenter = new JPanel(new FlowLayout()); panelCenter.add(label); add(panelCenter, BorderLayout.CENTER); […]

panelCenterlabel

Page 10: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

10

19

Contatore GUI 0: view� panelSouth: pannello a Sud

nel pannello principale dellavista

� Layout 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: view� Definizione del metodo

updateView() perl’aggiornamento della vista

� Uso del modello(contatore) per reperirele informazioni necessarieper l’aggiornamento dellavista

public void updateView(){ label.setText("Valore Contatore: " + contatore.getVal());}

valore contatore: ...

IncrementaDecrementa Reset

label

Page 11: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

11

21

Contatore GUI 0: controller� Tratta 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 metodoactionPerformed(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:aggangio 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

Page 12: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

12

23

Contatore GUI 0: MVC� Dal main si crea il

modello …� … e la vista� la vista crea il

controllore (listenerbottoni) e lo agganciaai bottoni

• la vista riceve ilmodello tra i suoiparametri

• il controllore riceve trai suoi parametri lavista e il modello

model

view

0

actionPerformed(event)

ActionListener

controllermain

crea

crea

crea

inviamessaggi

inviamessaggi

eventi

24

Contatore GUI 0: overview� Diagramma delle

classi per il contatoreGUI 0

� Introduzione di unainterfaccia per la vista

� ContatoreFramecontiene il main equindi crea la vista e ilmodello

� ExitButton eExitFramecontrollano l’uscita dalprogramma principale

Page 13: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

13

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

Page 14: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

14

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

Page 15: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

15

29

� Si desidera rendereindipendente ilcontrollore dallavista

� L’idea è quella cheil controllore facciariferimento ad unainterfaccia anzichédirettamente la vista

Contatore GUI 1: l’indipendenza dallavista

public class CounterView extends JPanel implements CounterInterfaceView { […] public updateView(){ […] } […]}

public interface CounterInterfaceView {void updateView();

}

30

Contatore GUI 1: controller� Il controllore non fa più riferimento ad un oggetto di tipo CounterView

ma all’interfaccia di tipo CounterInterfaceView� Tramite 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(); }}

Page 16: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

16

31

Contatore GUI 1: overview� Diagramma delle

classi per il contatoreGUI 1

� Introduzione di unainterfaccia per la vista

32

Contatore GUI 1( bis): l’indipendenza dallavista� È estremamente

semplicecambiare la vistaCounterView conuna nuova vistaCounterViewBis,che allineaverticalmente ivari bottoni,senza toccare ilcodice dellaclasseCounterControl

Page 17: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

17

33

Contatore GUI 2� Variante: il controllo

contiene i bottoni

� I bottoni sono ilcontrollo

� E` piu` faciledeterminare lasorgente

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

Page 18: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

18

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

Page 19: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

19

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 3� Modifichiamo l’applicativo

precedente in modo da poterinserire il valore iniziale delcontatore

� E` importante controllare ilvalore immesso, cioe` verificarese questo e` un numero intero esegnalare 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

Page 20: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

20

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

Page 21: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

21

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 senzacambiare ne` l’implementazione del modello ne` quello delcontrollore

� Contatore GUI 6: una vista un po’ piu` complicata, unaetichetta (JLabel) e un pannello grafico per illustrare ilvalore del modello

Page 22: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

22

43

Contatore GUI 5

� Una nuova vista per ilcontatore e`rappresentata dallaclasseCounterViewDraw

� Il valore del contatore e`rappresentato nella vistada un pannello con dellepalline:

� rosse se positivo� blu se negativo

44

Contatore GUI 6

� Le due viste precedentisono unite in una unica:CounterView ospita unpannello della classeJPanelCounter

� Il metodo updateViewdeve occuparsidell’aggiornamento siadel pannello grafico siadella etichetta di tipoJLabel

Page 23: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

23

45

Contatore GUI 7� Piu` l’interfaccia si presenta

complessa piu` diventa complessoil lavoro del controllore

� Il controllore deve conoscere tuttigli oggetti che compongono la vistae contattarli tutti dopo aver inviato ilmessaggio al modello

� Observer/Observable: permettonodi rendere ignorante il controlloredella presenza delle viste.

� E` il Contatore GUI 6 realizzato conObserver/Observable

46

Event-Driven Programming withObservers

� È possibile scrivere programmi che attivano i propri eventiinternamente per mezzo della classe Observable edell’interfaccia Observaber

� È possibile implementare listener objects per componenti nongrafiche

� Quando un oggetto genera un evento, gli “Osservatori”dell’oggetto ricevono un messaggio di update

� Un oggetto ob è aggiunto alla lista di “osservatori” di unoggetto b tramite il messaggio b.addObserver(ob)

Page 24: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

24

47

Contatore GUI 7� Nessuna

relazione diassociazione trail controllo e lavista!

� Observer: e` unainterfaccia nelpackage java.util

� Observable: 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 oggettoosservabile ed ereditadue nuovi metodi chesono usati pergenerare un evento

NB: il contatore nonsa chi sono i suoiosservatori !!

Page 25: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

25

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: ilcontrollernonmenzionanessunavista !!

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

Page 26: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

26

51

Contatore GUI 7: View[…]import java.util.*;

public class CounterView extends JPanel implements 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(); }}

Ridefinisce ilmetodo update

Implemental’interfacciaObserver

52

E.-D. P. with Observers

controller (e` registrato come ActionListener di Decrementa)

model

view

model.decr()

view.update(...)

model.getVal()

ActionEventevent

0 -1

actionPerformed(event)

ActionListener

� OS intercetta l’evento “click diun bottone” e lo comunicaall’AWT/Swing

� AWT/Swing determina lasorgente dell’evento, crea unActionEvent e lo inviaall’incaricatoActionListener

� la proceduraactionPerformed(event) del controllore e`eseguita

� il controllo invia l’oppor-tunomessaggio al modello

� il modello notifica ai suoiascoltatore l‘avvenutol‘aggiornamento

� gli ascoltatori eseguono ilpropio update

Page 27: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

27

53

Event-Driven Programming withObservers

� Vantaggi� stile di programmazione che disaccoppia ulteriormente le

componenti del sistema� il controller, a differenza degli esempi precedenti, non ha

più la necessità di conoscere le viste del modello

� Svantaggi� non è sempre possibile utilizzare questo schema perché il

modello 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 soloospitata nel pannello)

� Contatore GUI 9: e` il Contatore GUI 8 replicato 4 voltenella vista principale

Page 28: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

28

55

Contatore GUI 8

� E` il ContatoreGUI 7 dove lavista grafica e`completa-mentedisacoppiatadalla vistaprincipale (masolo ospitatanel 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!!

Page 29: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

29

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 9� E` il Contatore GUI 8 replicando quattro volte la vista

grafica nella vista principale� Estrema 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); […] } […]

Page 30: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

30

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 classe

� Ognuno di questi metodi e` invocato quando un particolareevento si verifica

� Questi metodi possono essere logicamente raggruppati inuna interfaccia che condividono lo stesso tipo di evento cheestendono, in Java, la classe java.util.EventListener

interface KeyboardListener extends java.util.EventListener { void keyPressed(KeyboardEvent ke); void keyReleased(KeyboardEvent ke);}

Page 31: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

31

61

Per orientarsi: Event Listener

� Un ascolatore per un determinato evento deveimplementare la relativa interfaccia che specifica il metodoche 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 Registration� Rappresenta il collegamento di un ascoltatore presso la/le

sorgente/i degli eventi che vuole ascoltare� Tecnicamente questo e` denominato event registration� Ogni oggetto sorgente di un evento deve provvedere due

metodi per la registrazione e la deregistrazione deglieventuali ascoltatori

public void addKeyboardListener (KeyboardListener ke) { … }public void removeKeyboardListener (KeyboardListener ke) { … }

Page 32: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

32

63

Per orientarsi: Event Listener Registration

� E` consigliabile che i metodi di registrazione ederegistrazione presso la sorgente siano definitisynchronized

� L’oggetto sorgente si incarica di mantenere una lista di tuttigli ascoltatori registrati presso di lui

� L’oggetto sorgente deve notificare l’evento occorso a tutti isuoi ascoltatori, questo e` realizzato inviando ad ognuno diessi l’oggetto evento mediante invocazione dell’opportunometodo dell’ascoltatore.

64

Delegation Event Model: proviamo acostruirlo 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 deicontatori che vengono incrementati ad intervalli random ditempo. Quando un contatore viene incrementato un oggettoCounterEvent è inviato agli ascoltatoriCounterChangeListener registrati.

Counter

CounterEventCounterChangeListener

Page 33: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

33

65

Delegation Event Model: proviamo acostruirlo 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 acostruirlo 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)

Page 34: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

34

67

Delegation Event Model: proviamo acostruirlo 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 acostruirlo 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.

Page 35: GUI e MVC - DiUniTobaldoni/didattica/SpLPPP0102/GUIeMVC.pdf · MVC: sequenza dei messaggi ① viene premuto il bottone “Decrementa” ② l’evento e’ ascoltato dal controller

35

69

Delegation Event Model: proviamo acostruirlo 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