Chapter 18: Integrating user interface and model: the
Download
Report
Transcript Chapter 18: Integrating user interface and model: the
An Introduction to
Programming and Object
Oriented Design using Java
2nd Edition. May 2004
Jaime Niño
Frederick Hosch
Chapter 18
Integrating user interface and model:
the Model-View-Controller pattern
Objectives
After studying this chapter you should understand the
following:
the Model-View-Controller pattern: components and their
roles;
the observer pattern, as realized by the class Observable
and interface Observer, and its use in the MVC pattern.
Also, you should be able to:
write a graphical user interface for a simple application
using the MVC architecture.
May 2004
NH-Chapter 18
1
Model-View-Controller
An Application structure
model components –objects that model and solve problem;
view components –objects that display model;
controller components –objects that handle user input.
May 2004
NH-Chapter 18
2
Model-View-Controller advantages
Processing of input and output is separate;
Controllers can be interchanged, allowing different
user interaction modes;
Allows multiple views of model.
May 2004
NH-Chapter 18
3
M-V-C architecture
View view1
View view3
Controller control1
Model
View view2
Controller control2
May 2004
NH-Chapter 18
4
Observer/Observable
relationships
java.util provides class Observable, interface Observer.
Observer is client and Observable is server.
Observer registers with the Observable,
Observable informs Observer when it changes state.
«interface»
notifies
Observer
SomeClient
May 2004
Observable
registers with
NH-Chapter 18
5
M-V-C example
Model: a right triangle.
base and height can be modified.
Three different views of triangle.
View one displays lengths of sides.
View two displays triangle graphically.
View three logs changes in triangle state to file.
A controller for view one, to modify triangle.
No controller for other views.
May 2004
NH-Chapter 18
6
RightTriangle class
public class RightTriangle {
private int base;
private int height;
private int hypotenuse;
public int hypotenuse () {
return this.hypotenuse;
}
public void setBase (int newB
this.base = newBase;
setHypotenuse();
}
public RightTriangle (int
base,
int height) {
this.base = base;
this.height = height;
setHypotenuse();
}
public int base () {
return this.base;
}
public int height () {
return this.height;
}
May 2004
public void setHeight (int ne
this.height = newHeight;
setHypotenuse();
}
private void setHypotenuse ()
this.hypotenuse = (int)
Math.sqrt(base*base + he
}
}//end RightTriangle.
NH-Chapter 18
7
Observable methods
java.util.Observable class specification provides
several methods; among those:
public void addObserver (Observer o);
protected void setChanged ();
public void notifyObservers ();
public void notifyObservers (Object arg);
May 2004
NH-Chapter 18
8
Structuring an Observer/Observable
RightTriangle extends Observable:
public class RightTriangle extends Observable …
All views are Observer’s of RightTriangle instance rt
Client Observer registers to rt invoking addObserver.
rt.addObserver(this);
When RightTriangle changes state, to notify all registered
observers of the event, modifies commands to add:
setChanged();
notifyObservers();
May 2004
NH-Chapter 18
9
Implementing an Observable
RightTriangle changes state in
setHeight
:
public void setBase (int newBase) {
setBase
or
this.base = newBase;
setHypotenuse();
setChanged();
notifyObservers();
}
public void setHeight (int newHeight) {
this.height = newHeight;
setHypotenuse();
setChanged();
notifyObservers();
}
May 2004
NH-Chapter 18
10
Interface Observer
interface Observer {
void update (Observable o,
Object arg);
}
May 2004
NH-Chapter 18
11
Observer structure
Observer must know target object.
Observer registers itself with the target.
When target notifies observer, observer executes update.
class RTObserver implements Observer {
private RightTriangle target;
// Create an observer of RightTriangle rt.
public RTObserver (RightTriangle rt) {
target = rt;
target.addObserver(this);
observer registers with model
…
}
public void update((Observable o, Object arg){
do something about o’s state
change.
}
…
}
May 2004
NH-Chapter 18
12
A simple view and controller for
RightTriangle
Build a view that shows the three components of the
triangle in text fields.
Controller will capture input from text fields labeled
Base and Height, and modify state of the
RightTriangle appropriately.
May 2004
NH-Chapter 18
13
The View
View extends JPanel and implements Observer.
RightTriangle to display is provided as constructor argument.
class TextView extends JPanel implements Observer {
private final static int FIELD_SIZE = 16;
private JTextField base;
private JTextField height;
private JTextField hypotenuse;
public TextView (RightTriangle model) {
super();
…
base = new JTextField(FIELD_SIZE);
base.setActionCommand("Base");
…
height = new JTextField(FIELD_SIZE);
height.setActionCommand("Height");
…
hypotenuse = new JTextField(FIELD_SIZE);
hypotenuse.setEditable(false);
…
}
May 2004
NH-Chapter 18
14
The View
View extends JPanel and implements Observer.
RightTriangle to display is provided as constructor argument.
May 2004
NH-Chapter 18
15
The View
When model changes state, notifies view to update text fields.
View’s update queries model for new state information,
and writes it into text fields:
public void update (Observable model, Object arg) {
int side;
RightTriangle rt = (RightTriangle)model;
side = rt.base();
base.setText(String.valueOf(side));
side = rt.height();
height.setText(String.valueOf(side));
side = rt.hypotenuse();
hypotenuse.setText(String.valueOf(side));
}
May 2004
NH-Chapter 18
16
Controller structure
Captures user input from base and height text
fields
must have references to the text fields,
must respond to ActionEvents generated by text fields,
must be an ActionListener,
must be added as listener to text fields.
Updates model.
This is response to ActionEvent text fields generate.
Must have reference to RightTriangle.
May 2004
NH-Chapter 18
17
Controller structure
private class TVController implements ActionListener {
private RightTriangle model;
¹
May 2004
/**
* Create a new controller for this TextView of t
* specified RightTriangle.
*/
public TVController (RightTriangle model) {
this.model = model;
TextView.this.base.addActionListener(this);
TextView.this.height.addActionListener(this
}
NH-Chapter 18
18
Controller structure
/**
* Update the model in response to user input.
*/
public void actionPerformed (ActionEvent e) {
JTextField tf = (JTextField)e.getSource();
try {
int i = Integer.parseInt(tf.getText());
if (i < 0) throw new NumberFormatExcepti
String which = e.getActionCommand();
if (which.equals("Base"))
model.setBase(i);
else
model.setHeight(i);
} catch (NumberFormatException ex) {
TextView.this.update(model, null);
}
}
May 2004
NH-Chapter 18
19
Model, View and Controller
observes
TextView
has
3
JTextFi eld
Ri ghtTriangle
2
listens-t o
TVController
May 2004
modifies
NH-Chapter 18
20
Nim Game : Model
provides
Pile
uses
Game
2
directs
«interface»
Player
AbstractPlayer
InteractivePlayer
May 2004
IndependentPlayer
NH-Chapter 18
21
Nim Game : TUI
creat es
G ame
creat es
NimG ame
NimTUI
creat es
«i nterface»
Pl ayer
«interface»
InteractiveController
TUIControl ler
May 2004
NH-Chapter 18
notifies
InteractivePl ayer
provides moves
22
Nim Game : TUI v.s. GUI design
TUI design:
TUIController
registers with InteractivePlayer,
prompts and reads user’s move, forwards it to InteractivePlayer.
The play loop is in the interface.
May 2004
NH-Chapter 18
23
Nim Game : GUI design
«i nterface»
observes
Obser ver
NimInterface
May 2004
Obser vabl e
Game
NH-Chapter 18
24
Nim Game : TUI v.s. GUI design
GUI design
No explicit loop coded.
User repeats some event.
NimController
When user presses an input button it invokes
setNumberToTake on InteractivePlayer.
Invokes Game’s play,
once for InteractivePlayer,
once for IndependentPlayer.
May 2004
NH-Chapter 18
25
View
Display composed of four panels:
a panel to display number of sticks remaining,
two panels each with a text field to report player’s moves,
a panel containing buttons for user to make a move.
May 2004
NH-Chapter 18
26
NimController
directs play
NimInterface.NimController
Game
provides moves
InteractivePlayer
listens to
3
JButton
May 2004
NH-Chapter 18
27
View
A NimInterface instance:
builds display,
observes the Game.
May 2004
NH-Chapter 18
28
Model’s Game
When Game completes a play, it notifies its
Observers.
public void play () {
if (!gameOver()) {
nextPlayer.takeTurn(pile,MAX_ON_A_TURN);
previousPlayer = nextPlayer;
nextPlayer = otherPlayer(nextPlayer);
setChanged();
notifyObservers();
}
}
May 2004
NH-Chapter 18
29
GUI structure
User selects “New Game” from main menu.
Menu
item
listener
initializeGame:
invokes
NimController’s
displays a JDialog to get initialization data from user,
creates a Game.
May 2004
NH-Chapter 18
30
NimInterface
When notified,
queries Game,
updates display.
NimInterface responsible for
displaying the number of sticks remaining in the game;
reporting the winner when the game is over.
May 2004
NH-Chapter 18
31
Sub-views
NimInterface
defines an inner class PlayerView with the responsibility to report
player’s moves.
A PlayerView observes a Player, and updates the text field
when the Player takes a turn.
NimInterface.PlayerView
May 2004
observes
«interface»
Player
NH-Chapter 18
32
Delaying IdependentPlayer’s move
NimController invokes Game’s play,
once for InteractivePlayer,
once for IndependentPlayer.
Need a delay between the two play invocations.
May 2004
NH-Chapter 18
33
Delaying IdependentPlayer’s move
public void actionPerformed (ActionEvent e) {
…
user.setNumberToTake(number);
game.play();
nhUtilities.utilities.Control.sleep(2); //dela
game.play();
…
}
Attempt to delay the two plays fails.
Application will pause, but moves appear to take place at the
same time.
May 2004
NH-Chapter 18
34
Delaying IdependentPlayer’s move
Event dispatch thread
user presses button
button-press event handler starts
display updates resulting from
InteractivePlayer move are scheduled
thread sleeps for two seconds
display updates resulting form
IndependentPlayer move are scheduled
button-press event handler completes
display is updated
May 2004
NH-Chapter 18
35
Scheduling a move to delay the
action
NimController uses javax.swing.Timer to schedule
IndependentPlayer’s play seconds after play of
InteractivePlayer.
User’s Button-press event handling is complete.
IndependentPlayer’s move occurs after and when
scheduled.
May 2004
NH-Chapter 18
36
MVC and Swing components
Swing components are structured using MVC pattern.
Each Swing JComponent has an associated model object
responsible for maintaining component’s state.
JButton or JCheckBox has a ButtonModel,
JTextArea or JTextField has a Document.
A Swing component delegates
responsibilities to its UI delegate.
view
and
control
The package javax.swing.plaf contains an abstract
delegate class for each Swing component.
May 2004
NH-Chapter 18
37
Summary
Overview basic format of Model-View-Controller
pattern.
MVC commonly used to structure event-driven
graphical user interfaces.
With MVC, interface responsibilities are partitioned
into two segments:
view has display responsibilities,
controller modifies model in accordance with user input.
May 2004
NH-Chapter 18
38
Summary
Developed three views of a right triangle.
Noted Java Observer interface and Observable class for
implementing the observes relationship.
Fundamental relationship between view and model is
observes, implemented by
making model object an extension of the class Observable,
view implements interface Observer.
Added a graphical user interface to the nim game, using the
MVC pattern.
May 2004
NH-Chapter 18
39
Summary
Swing components are structured along the lines of
MVC.
Each Swing component has
an associated model object responsible for maintaining
component’s state.
a UI delegate, to which view and control responsibilities
are delegated.
This structure allows to change application look-andfeel in a system-independent way.
May 2004
NH-Chapter 18
40