• Non ci sono risultati.

Linguaggi di Programmazione: Paradigmi di Programmazione

N/A
N/A
Protected

Academic year: 2022

Condividi "Linguaggi di Programmazione: Paradigmi di Programmazione"

Copied!
32
0
0

Testo completo

(1)

Matteo Baldoni, Marco Botta

Dipartimento di Informatica - Universita` degli Studi di Torino C.so Svizzera, 185 - I-10149 Torino (Italy)

e-mail: botta@di.unito.it - URL: http://www.di.unito.it/~botta e-mail: baldoni@di.unito.it - URL: http://www.di.unito.it/~baldoni

Linguaggi di

Programmazione: Paradigmi di Programmazione

GUI, Event-Driven Programming e l’architettura Model View Controller

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;

}

(2)

GUI, Event-Driven Programming e l'architettura Model View Controller 3

Contatore GUI 1

• 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

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

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

(3)

GUI, Event-Driven Programming e l'architettura Model View Controller 5

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 visualizza- re il risultato della computazione

• La vista interroga il modello sul suo nuovo stato interno e visulizza l’informazione all’utente

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)

(4)

GUI, Event-Driven Programming e l'architettura Model View Controller 7

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() alla vista

⑤ la vista richiede i dati al modello per aggiornarsi (getVal())

controller model view

model.decr() view.updateView()

model.getVal()

event

0 -1

actionPerformed(…) Action Listener

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, mouse on/off, ecc.)

• L’utente genera tramite la GUI una serie di eventi a cui il controllore 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)

(5)

GUI, Event-Driven Programming e l'architettura Model View Controller 9

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)

Event-Driven Programming

controller (e`

registrato come ActionListener di Decrementa)

model view

model.decr() view.updateView()

model.getVal()

ActionEvent event

0 -1

actionPerformed(event) Action Listener

① 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 gli opportuni messaggi al modello e alla vista

⑤ la vista si aggiorna

(6)

GUI, Event-Driven Programming e l'architettura Model View Controller 11

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 b tramite il messaggio

b.addActionListener(ob)

• In generale, un componente grafico può avere molti listener objects e un listener object può “ascoltare”

più componenti

• Quando un evento occorre, la lista viene scandita e a ogni listener object viene inviato il messaggio actionPerformed

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)

(7)

GUI, Event-Driven Programming e l'architettura Model View Controller 13

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

• Dialog: finestre visualizzate temporaneamente sullo schermo durante l’esecuzione di un

programma (es. visualizzano messaggi di errore, input file, ecc)

Contatore GUI 1: view

JPanel BorderLayout

CENTER SOUTH JPanel FlowLayout

JPanel FlowLayout JButton JButton

JButton JLabel

valore contatore: ...

Incrementa Decrementa Reset

Contenitori Struttura del

contenitore JPanel Componenti (in realta` sono

a loro volta contenitori, etichette, icon, …)

Componente

(8)

GUI, Event-Driven Programming e l'architettura Model View Controller 15

• Creazione del

contenitore JPanel della vista

• Uso del costruttore super

• Layout scelto:

BorderLayout

Contatore GUI 1: view

public class CounterView extends JPanel

implements CounterInterfaceView { public CounterView(Counter model){

super(new BorderLayout());

// alternativa: setLayout(new BorderLayout());

[…]

}

CENTER

SOUTH NORTH

WEST EAST

Contatore GUI 1: view

• panelCenter: pannello da aggiungere al centro del BorderLayout del pannello principale

• Layout scelto:

FlowLayout

valore contatore: ...

[…]

label = new JLabel(“Valore contatore: ");

JPanel panelCenter = new JPanel(new FlowLayout());

panelCenter.add(label);

add(panelCenter, BorderLayout.CENTER);

[…]

panelCenter label

(9)

GUI, Event-Driven Programming e l'architettura Model View Controller 17

Contatore GUI 1: view

• panelSouth: pannello a Sud nel pannello principale della vista

• Layout scelto:

FlowLayout

valore contatore: ...

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

Contatore GUI 1: view

• Definizione del metodo

updateView()

per l’aggiornamento della vista

• Uso del modello (contatore) per

reperire le informazioni necessarie per

l’aggiornamento della vista

public void updateView(){

label.setText("Valore Contatore: " + contatore.getVal());

}

valore contatore: ...

Incrementa Decrementa Reset

label

(10)

GUI, Event-Driven Programming e l'architettura Model View Controller 19

Contatore GUI 1:

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 metodo

actionPerformed(ActionEvent)

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

} }

Contatore GUI 1:

aggangio del controller

public class CounterView extends JPanel

implements CounterInterfaceView { 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

(11)

GUI, Event-Driven Programming e l'architettura Model View Controller 21

Contatore GUI 1: 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 tra i suoi parametri la vista e il modello

model view

0

actionPerformed(event) Action Listener

controller main

crea crea

crea

invia messaggi

invia messaggi

eventi

Contatore GUI 1: overview

• Diagramma delle classi per il contatore GUI 1

• Introduzione di una interfaccia per la vista

• ContatoreFrame

contiene il main e quindi crea la vista e il modello

• ExitButton

e

ExitFrame

controllano l’uscita

dal programma

principale

(12)

GUI, Event-Driven Programming e l'architettura Model View Controller 23

Contatore GUI 1: frame

Exit

Container (pannello del contenuto)

BorderLayout CENTER

SOUTH

JButton

windowClosing(…) setTitle(…)

Contatore GUI Finestra: JFrame

Struttura del Container Componente

Contenitore all’

interno del JFrame

Contatore GUI 1: frame

valore contatore: ...

Incrementa Decrementa Reset

Exit

Container (pannello del contenuto)

BorderLayout CENTER

SOUTH Contatore GUI 1: view Contatore GUI

(13)

GUI, Event-Driven Programming e l'architettura Model View Controller 25

Contatore GUI 1: frame

public 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 chiusura sull “X” della finestra

il bottone di Exit

il main e` tutto qua!!

Contatore GUI 1: 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 finestra e un bottone “Exit”

• Vanno bene per molti applicativi diversi dal contatore GUI

(14)

GUI, Event-Driven Programming e l'architettura Model View Controller 27

Contatore GUI 2

• Variante: il

controllo contiene i bottoni

• I bottoni sono il controllo

• E` piu` facile determinare la sorgente

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 determinare piu` facilemente la sorgente essendo questa interna alla classe stessa

(15)

GUI, Event-Driven Programming e l'architettura Model View Controller 29

Delegation Event Model

• Gli eventi messaggi passati dall’oggetto sorgente ad uno o piu` oggetti ascoltatori

• Quando un evento e` passato causa l’invocazione di un metodo dell’oggetto ascoltatore

• Gli eventi sono oggetti contenenti le informazioni relative al particolare evento che li ha determinati

Event Source Event Object Event Listener

Listener Registration

Event Object

• Ogni oggetto evento in Java estende la classe java.util.EventObject

public class KeyboardEvent extends java.util.EventObject { private char key;

KeyboardEvent (java.awt.Component source, char key) { super(source);

this.key = key;

} }

(16)

GUI, Event-Driven Programming e l'architettura Model View Controller 31

Event Listener

• Ogni ascoltatore puo` essere rappresentato da un metodo in una data classe

• Ognuno di questi metodi e` invocato quando un particolare evento si verifica

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

}

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

} }

(17)

GUI, Event-Driven Programming e l'architettura Model View Controller 33

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 degli eventuali ascoltatori

public void addKeyboardListener (KeyboardListener ke) {

}

public void removeKeyboardListener (KeyboardListener ke) {

}

Event Listener Registration

• E` consigliabile che i metodi di registrazione e deregistrazione presso la sorgente siano definiti synchronized

• L’oggetto sorgente si incarica di mantenere una lista di tutti gli ascoltatori registrati presso di lui

• L’oggetto sorgente deve notificare l’evento occorso a tutti i suoi ascoltatori, questo e` realizzato

inviando ad ognuno di essi l’oggetto evento

mediante invocazione dell’opportuno metodo

dell’ascoltatore.

(18)

GUI, Event-Driven Programming e l'architettura Model View Controller 35

Inside Contatore GUI 1

Sorgente:

contiene i metodi per registrare e deregistrare gli ascoltatore e il per inviare l’evento oggetto a tutti gli ascoltatori

Interfaccia ascoltatore

Ascoltatore:

implementa il metodo specificato nell’interfaccia

Inside Contatore GUI 1

import 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 il metodo actionPerformed definito in CounterControl

(19)

GUI, Event-Driven Programming e l'architettura Model View Controller 37

Inside Contatore GUI 1

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

} }

Contatore GUI 3

• Modifichiamo 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 la

finestra visualizza il

valore corrente o l’eventuale errore

inizializza il contatore con il valore immesso

chiude la finestra input del valore iniziale del contatore

(20)

GUI, Event-Driven Programming e l'architettura Model View Controller 39

Contatore GUI 3: view

JPanel BorderLayout

NORTH CENTER SOUTH JPanel FlowLayout JButton JButton

JButton valore contatore: ...

Incrementa Decrementa Inizializza

JPanel FlowLayout

JLabel

JLabel valore iniziale:

JTextField

JPanel FlowLayout

0

Contatore GUI 3: frame

Exit Contatore GUI

valore contatore: ...

Incrementa Decrementa Inizializza

valore iniziale: 0

Container (pannello del contenuto)

BorderLayout CENTER

SOUTH

JButton windowClosing(…) setTitle(…)

Contatore GUI 3: view

(21)

GUI, Event-Driven Programming e l'architettura Model View Controller 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 valore in input nel campo JTextField tramite interrogazione della vista

La Serie dei Contatori

• Contatore GUI 4: in un frame due contatori (modello) con rispettivi viste e controllori

• Contatori GUI 5: si puo` facilmente cambiare vista senza cambiare ne` l’implementazione del modello ne` quello del controllore

• Contatore GUI 6: una vista un po’ piu` complicata,

una etichetta (JLabel) e un pannello grafico per

illustrare il valore del modello

(22)

GUI, Event-Driven Programming e l'architettura Model View Controller 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 positivo – blu se negativo

Contatore GUI 6

• Le due viste

precedenti sono unite in una unica:

CounterView ospita un pannello della classe JPanelCounter

• Il metodo updateView deve occuparsi

dell’aggiornamento

sia del pannello

grafico sia della

etichetta di tipo

JLabel

(23)

GUI, Event-Driven Programming e l'architettura Model View Controller 45

Contatore GUI 7

• Piu` l’interfaccia si presenta complessa piu` diventa complesso il lavoro del controllore

• Il controllore deve conoscere tutti gli oggetti che

compongono la vista e contattarli tutti dopo aver inviato il messaggio al modello

• Observer/Observable:

permettono di rendere ignorante il controllore della presenza delle viste.

• E` il Contatore GUI 6 realizzato con Observer/Observable

Event-Driven Programming with Observers

• È possibile scrivere programmi che attivano i propri eventi internamente per mezzo della classe Observer e dell’interfaccia Observable

• È possibile implementare listener objects per componenti non grafiche

• Quando un oggetto genera un evento, gli

“Osservatori” dell’oggetto ricevono un messaggio di update

• Un oggetto ob è aggiunto alla lista di “osservatori” di un oggetto b tramite il messaggio

b.addObserver(ob)

(24)

GUI, Event-Driven Programming e l'architettura Model View Controller 47

Contatore GUI 7

• Nessuna relazione di associazione tra il controllo e la vista!

• Observer: e`

una interfaccia nel package java.util

• Observable:

e` una classe nel package java.util

Contatore GUI 7: Model

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

(25)

GUI, Event-Driven Programming e l'architettura Model View Controller 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 menziona nessuna vista !!

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

} }

contatoreVista si dichiara un ascoltatore del contatore

(26)

GUI, Event-Driven Programming e l'architettura Model View Controller 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 il metodo update

Implementa l’interfaccia Observer

E.-D. P. with Observers

controller (e`

registrato come ActionListener di Decrementa)

model view

model.decr() view.update(...) model.getVal()

ActionEvent event

0 -1

actionPerformed(event) Action Listener

① 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’oppor- tuno messaggio al modello

⑤ il modello notifica ai suoi ascoltatore l‘avvenuto l‘aggiornamento

⑥ gli ascoltatori eseguono il

(27)

GUI, Event-Driven Programming e l'architettura Model View Controller 53

Event-Driven Programming with Observers

• 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

La Serie dei Contatori

• Contatore GUI 8: e` il Contatore GUI 7 dove la vista grafica e` completamente slegata dalla vista principale (ma solo ospitata nel pannello)

• Contatore GUI 9: e` il Contatore GUI 8 replicato 4

volte nella vista principale

(28)

GUI, Event-Driven Programming e l'architettura Model View Controller 55

Contatore GUI 8

• E` il Contatore GUI 7 dove la vista grafica e`

completa- mente disacoppiata

dalla vista principale (ma solo ospitata nel pannello)

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 non piu` repaint!!

(29)

GUI, Event-Driven Programming e l'architettura Model View Controller 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 autogestisce l’update essendo a sua volta un Observer del contatore

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

[…]

} […]

(30)

GUI, Event-Driven Programming e l'architettura Model View Controller 59

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

CounterEvent CounterChangeListener

Delegation Event Model:

proviamo a costruirlo da noi

public 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 estende la classe Thread

Questo è il codice eseguito in un thread separato

Ogni volta che il valore del contatore cambia viene eseguita la notifica a tutti gli ascoltatori del contatore stesso memorizzati in un apposito Vector

(31)

GUI, Event-Driven Programming e l'architettura Model View Controller 61

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 notifica dell’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)

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

registrazione e deregistrazione degli ascoltatori presso un contatore

(32)

GUI, Event-Driven Programming e l'architettura Model View Controller 63

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 contiene anche la sorgente dell’evento, cioe` il contatore incrementato.

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’ascoltatore presso la sorgente degli eventi

Viene fatto partire un thread in cui il metodo run del contatore è eseguito

Metodo eseguito ogni volta che viene ascoltato un evento

Riferimenti

Documenti correlati

 Quando ciò avviene per tutti gli elementi della coda, join() esce.  Meccanismo analogo ai due semafori suppletivi (vuote, piene) del

• Richiede tuttavia di un processo di traduzione da Assembly a linguaggio macchina, ma a differenza dei linguaggi ad alto livello la corrispondenza è 1:1 (ad ogni istruzione

Siccome le regole specificano il significato delle espressioni in modo operazionale, si dice che esse definiscono una semantica operazionale di tali espressioni. Alcune regole

Induzione matematica e strutturale sono casi particolari di un potente metodo di prova chiamato induzione ben fondata In questa lezione vedremo in dettaglio:. ¾ Induzione

Supponiamo di voler estendere le espressioni aritmetiche di IMP includendo un nuovo operatore “^” con il significato di elevamento a potenza. La sintassi di Aexp di IMP verrà

Negli anni sessanta, Christopher Strachey e Dana Scott riuscirono a superare le limitazioni della semantica operazionale introducendo una semantica più astratta basata sull’utilizzo

La sintassi specifica sia la struttura lessicale del linguaggio (come costruire le parole a partire dai caratteri dell’alfabeto) sia le regole per la costruzione delle

Si noti che nel comando if, comunque sia valutato b in σ’, esso viene interrotto dopo l’esecuzione di c e dunque in questo caso &lt;w,σ&gt; è valutato σ’ sse &lt;if,σ&gt;.