gui e mvc - dipartimento di informaticamrt/didattica/proginrete-0304/mvc.pdfdi tutto: gui,...

12
GUI e MVC Programmazione in rete e laboratorio 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 3 Graphical User Interface Un programma che fa uso di di strumenti grafici come bottoni, menu`, disegni, finestre, ecc. per facilitare le operazioni di input e visualizzazione dell’output Un GUI per il contatore: una finestra che permetta di controllare l’invio dei messaggi di incremento, decremento, inizializzazione di un contatore, nonche` la visualizzazione del suo 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 lezioni precedenti) che contenga le seguenti funzionalita`: un display per il valore corrente tre 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 la finestra visualizza il valore corrente inizializza il contatore a zero chiude la finestra 5 L’architettura Model View Controller Un programma si compone di Modello (Model): modella e calcola il problema che desideriamo risolvere Vista (View): rappresenta una “fotografia” dello stato interno del modello spesso per facilitarne la sua lettura/interpretazione all’utente umano Controllore (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 Smalltalk E` 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 aggiuntive Il controllore invia tali informazioni al modello che effettua la computazione richiesta e aggiorna il proprio stato interno Il controllo (o il modello) http://www.cis.ksu.edu/~schmidt/CIS200 richiede alla vista di visualizzare il risultato della computazione La vista interroga il modello sul suo nuovo stato interno e visualizza l’informazione all’utente

Upload: others

Post on 04-Mar-2021

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

1

GUI e MVCProgrammazione in rete e laboratorio

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 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

Page 2: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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

Page 3: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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

Page 4: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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

Page 5: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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();

}}

Page 6: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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

Page 7: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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

Page 8: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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

Page 9: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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

Page 10: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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);

}

Page 11: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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)

Page 12: GUI e MVC - Dipartimento di Informaticamrt/didattica/ProgInRete-0304/MVC.pdfdi tutto: GUI, Event-driven programming e l’architettura MVC 3 Graphical User Interface Un programma che

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