450 likes | 549 Views
Chapter 19. Designing the GUI front-end: the Model-View-Controller pattern. This chapter discusses. The Model-View-Controller (MVC) Two components: View and Controller. Implementing MVC and the observes relation in Java. Basic Swing components structured along the lines of the MVC pattern.
E N D
Chapter 19 Designing the GUI front-end: the Model-View-Controller pattern
This chapter discusses • The Model-View-Controller (MVC) • Two components: View and Controller. • Implementing MVC and the observes relation in Java. • Basic Swing components structured along the lines of the MVC pattern
Model-View-Controller • model components -- the objects that model and solve the problem at hand. • view components -- the objects that determine the manner in which the model components are to be displayed. • controller components -- the objects that handle user input.
Advantages • Input processing is separated from output processing. • Controllers can be interchanged, allowing different user interaction modes. • Multiple views of the model can be supported easily.
Model • The model does not require details of the other components. • The model is independent. • The model can be retrofitted readily with a new look and feel.
View • The view must insure that the display accurately reflects the current state of the model. • The view is an observer, notified of state changes in a target (model). • The view-controller relationship is often has-as-strategy. • View is often a composite built of simpler views.
Controller • The controller defines how the view responds to user input. • The controller must effect changes in the model as determined by user input. • The controller listensto the view or its components.
Example • Let’s consider a system that models a right triangle. • It accepts base and height and calculates the hypotenuse.
Example: Model public class RightTriangle { //Contructors /** * Create right triangle with base and height * require: * base>=0; height >= 0 */ public RightTriangle (int base, int height) { this.base = base; this.height = height; setHypotenuse(); } //Queries /** * The base * ensure: * result >= 0; */ public int base() { return this.base; }
Example: Model (cont.) /** * The height * ensure: * result >= 0; */ public int height() { return this.height; } /** * The hypotenuse * ensure: * result >= 0; */ public int hypotenuse() { return this.hypotenuse; } //Commands /** * Change base * require: * newBase>= 0; */ public void setBase(int newBase) { this.base = newBase; setHypotenuse(); }
Example: Model (cont.) public void setHeight(int newHeight) { this.height = newHeight; setHypotenuse(); } //Private Methods /** * Adjust hypotenuse */ public void setHypotenuse() { this.hypotenuse = (int) Math.round( Math.sqrt(base*base + height*height)); } //Private Methods private int base; private int height; private int hypotenuse; }
Observer • To support the observes relation, Java provides a class Observableand an interface Observer in the package java.util. • Observable methods: public void addObserver(Observer o); protected void setChanged (); public void notifyObservers (); public void notifyObservers (Object arg); • Class component: private boolean haschanged; private ObserverList observers;
Example:Model (cont.) public class RightTriangle extends Observable { … public void setBase (int newBase) { this.base = newBase; setHypotenuse(); setChanged(); notifyObservers(); } public void setHeight (int newHeight) { this.height = newHeight; setHypotenuse(); setChanged(); notifyObservers(); } … }
Example:Observer class RTObserver implements Observer { public RTObserver (RightTriangle rt) { target = rt; target.addObserver(this); } … private RightTriangle target; }
Observer • The interface Observer specifies only one method: void update (Observable o, Object arg); • The first parameter references the target; the second is the argument provided by the target to notifyObservers. • Called by the target to notify the observer of a state change notifyObservers(info); • causes the update method of each of its observers to be called.
Observer (cont.) public class Observable () { public Observable () { observer = new ObserverList(); hasChanged = false; } public void addObserver (Observer o) { observer.append(o); } public void setChanged () { hasChanged = true; }
Observer (cont.) public void notifyObservers(Object arg){ if (hasChanged) { int i; int len = observers.size(); for (i = 0; i < len; i = i+1) ((Observer)observers.get(i)).update( this, arg); hasChanged = false; } } public void notifyObservers () { this.notifyObservers(null); } private boolean hasChanged; private ObserverList observers; }
Example:view and controller • The components of the view are the 3 text fields. • Each text field has an action command incorporated in any ActionEvent it generates.
Example: view class TextView extends JPanel implements Observer { 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.setActionCommand(“Hypotenuse”); … } …
Example: view (cont.) • update is invoked whenever the model changes state. 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)); } private final static int FIELD_SIZE = 16; privateJTextField base; private JTextField height; private JTextField hypotenuse; }
Example: controller • It captures user input from the base and height text fields, and updates the model. • Because the controller and the view are very closely related, we make the controller class an inner class of TextView. • The controller will then have direct access to the view’s text field components. • The controller must be an ActionListener and must respond to ActionEvents generated by the text fields. • It implements actionPerformed.
Example: Controller class TVController implements ActionListener { public TVController(RightTriangle model, TextView view) { this.model = model; this.view = view; view.base.addActionListener(this); view.height.addActionListener(this); } public void actionPerformed (ActionEvent e) { JTextField tf = (JTextField)e.getSource(); try { int i = Integer.parseInt(tf.getText()); String which = e.getActionCommand(); if (which.equals(“Base”)); model.setBase(i); else model.setHeight(i); } catch (NumberFormatExeception ex) { view.update(model, null); } } private TextView view; private RightTrangle model; }
View layout • We lay out components in a 2 3 grid, using a GridBagLayout layout manager. • A GridBagLayout layout manager uses a GridBagConstraints object to position each component.
View layout (cont.) public TextView (RightTriangle model) { super(); setLayout(new GridBagLayout()); GridBagConstraints constraints = new GrideBagContraints(); constraints.gridx = 0; constraints.gridy = GridBagConstraints.RELATIVE; constraints.anchor = GridBagConstrains.EAST; constraints.insets = new Insets(5,5,5,5); add(new Label(“Base”),constraints); add(new Label(“Height”),constraints); add(new Label(“Hypotenuse”),constraints); constraints.gridx = 1; base = new JTextField(FIELD_SIZE); base.setActionCommand(“Base”); add(base,constraints);
View layout (cont.) height = new JTextField(FIELD_SIZE); height.setActionCommand(“Height”); add(height,constraints); hypotenuse = new JTextField(FIELD_SIZE); hypotenuse.setEditable(false); add(hypotenuse,constraints); model.addObserver(this); controller = new TVController(Model, this); update(model,null); }
A graphic view • This shows a graphic rendition of the triangle without a controller. • The basic structure is the same as the previous view.
A graphical view • JPanel is not just a container for other components, but also is useful as a blank canvas on which to draw. • We override the JPanel paintComponent method to draw. • The Graphics object provides several methods for drawing on components.
View • A view does not need to be a part of a graphical interface. • Example: A view can log changes in the model’s state to a file.
MVC and Swing • Swing components are structured along the Model-View-Controller pattern.
Swing: model • Each Swing JComponent has an associated model object that is responsible for maintaining the component’s state.
Swing: model (cont.) • ButtonModel: public boolean isPressed() public boolean isEnabled() public void setPressed (boolean b) public void setEnabled (boolean b) default class: DefaultButtonModel. • State information is maintained by a Document.
Swing: UI delegate • Because the view and controller for a component are very closely related, they are combined into one object for many Swing components. • The component delegates the view and control responsibilities to its UI delegate. • The plugable look-and-feel package (javax.swing.plaf) contains an abstract delegate class for each Swing component. • Basic classes in javax.swing.plaf.basic can be used for building custom look-and-feel components.
Swing: UI delegate • A standard JButton implementation consists of: • a model (implements the interface ButtonModel) • a look-and-feel specific view element • An element that responds to user input and functions as a controller
We’ve covered • The Model-View-Controller pattern. • The standard Java library for implementing the observes relation. • Swing components structured along the lines of MVC.