Main Page

Previous Next

Using the Model/View Architecture

We need to develop an idea of how we're going to manage the data for a sketch in the Sketcher program before we start drawing a sketch, because this will affect where and how we handle events. We already have a class that defines an application window, SketchFrame, but this class would not be a very sensible place to store the underlying data that defines a sketch. For one thing, we'll want to save a sketch in a file, and serialization is the easiest way to do that. If we're going to use serialization to store a sketch, we won't want all the stuff in the implementation of the SketchFrame class muddled up with the data relating to the sketch we have created.

For another, it will make the program easier to implement if we separate out the basic data defining a sketch from the definition of the GUI. This will be along the lines of the MVC architecture that we first mentioned in Chapter 15, a variant of which is used in the definition of Swing components.

Ideally, we should manage the sketch data in a class designed specifically for that purpose – this class will be the model for a sketch.

A class representing a view of the data in the model class will display the sketch and handle user interactions – so this class will combine viewing functions and a sketch controller. The general GUI creation and operations not specific to a view will be dealt with in the SketchFrame class. This is not the only way of implementing the things we want in the Sketcher program, but it's quite a good way.

Our model object will contain a mixture of text and graphics that will go to make up a sketch. We'll call our model class SketchModel and we'll call the class representing a view of the model SketchView, although we won't be adding the view to the program until the next chapter. The following diagram illustrates the relationships between the classes we will have in Sketcher.

Click To expand

The application object will have overall responsibility for managing links between the other objects involved in the program. Any object that has access to the application object will be able to communicate with any other object as long as the application class has methods to make each of the objects available. Thus the application object will act as the communication channel between objects.

Note that SketchFrame is not the view class – it just defines the application window and the GUI components associated with that. When we create a SketchView object in the next chapter, we'll arrange to insert the SketchView object into the content pane of the SketchFrame object, and manage it using the layout manager for the content pane. By defining the view class separately from the application class, we separate the view of a sketch from the menus and other components we use to interact with the program. One benefit of this is that the area in which we display the document has its own coordinate system, independent of that of the application window.

To implement the foundations for the model/view design in Sketcher we need to define classes for the model and the view, at least in outline. The class to contain the data defining a sketch we can define in skeleton form as:

import java.util.Observable;

class SketchModel extends Observable {
  // Detail of the rest of class to be filled in later...

We obviously have a bit more work to do on this class, so we will add to this as we go along. Since it extends the Observable class, we will be able to register the view class with it as an observer, and automatically notify the view of any changes. This facility will come into its own when we have multiple views. We can define the view class as a component by deriving it from JComponent. This will build in all the methods for operating as a component and we can override any of these as necessary. The view class also needs to implement the Observer interface so that we can register it with the model. Here's the outline:

import javax.swing.JComponent;
import java.util.Observer;                  
import java.util.Observable;                  

class SketchView extends JComponent implements Observer {
  public SketchView(Sketcher theApp) {
    this.theApp = theApp;

  // Method called by Observable object when it changes
  public void update(Observable o, Object rectangle) {
    // Code to respond to changes in the model...

  private Sketcher theApp;           // The application object

The view is definitely going to need access to the model in order to display it, but rather than store a reference to the model, the constructor has a parameter to enable the application object to be passed to it. By storing the application object in the view, rather than a reference to the model, and adding a method to the application object to return a reference to the model, we make the view object independent of the model object. If a completely different object represents the model because, for example, a new file is loaded, we don't need to change the view object. As long as the view object is registered as an observer for the new model, the view will automatically redraw the new sketch when it is notified by the model that it has changed.

To integrate a model and its view into the Sketcher application, we just need to add some code to the Sketcher class:

import java.awt.*;
import java.awt.event.*;
import java.util.Observer;                  
import java.util.Observable;                  

public class Sketcher {
  public static void main(String[] args) {
    theApp = new Sketcher();                      // Create the application object
    theApp.init();                                // ... and initialize it

  public void init() {
    window = new SketchFrame("Sketcher", this);    // Create the app window
    Toolkit theKit = window.getToolkit();          // Get the window toolkit
    Dimension wndSize = theKit.getScreenSize();    // Get screen size

    // Set the position to screen center & size to 2/3 screen size
    window.setBounds(wndSize.width/6, wndSize.height/6,        // Position
                     2*wndSize.width/3, 2*wndSize.height/3);   // Size 

    window.addWindowListener(new WindowHandler()); // Add window listener

    sketch = new SketchModel();               // Create the model
    view = new SketchView(this);              // Create the view
    sketch.addObserver((Observer)view);       // Register the view with the model
    window.getContentPane().add(view, BorderLayout.CENTER);

  // Return a reference to the application window
  public SketchFrame getWindow() { 
     return window; 

  // Return a reference to the model
  public SketchModel getModel() { 
     return sketch; 

  // Return a reference to the view
  public SketchView getView() { 
     return view; 

  // Handler class for window events
  class WindowHandler extends WindowAdapter {
    // Handler for window closing event
    public void windowClosing(WindowEvent e) {
      // Code to be added here later...

  private SketchModel sketch;                     // The data model for the sketch
  private SketchView view;                        // The view of the sketch
  private static SketchFrame window;              // The application window
  private static Sketcher theApp;                 // The application object

There is no code in the windowClosing() method at present, so this assumes we have restored EXIT_ON_CLOSE as the default closing action in the SketchFrame class. We will be adding code to the windowClosing() method when we get to save sketches on disk. The SketchFrame constructor needs to be modified as follows:

  public SketchFrame(String title, Sketcher theApp) {
    setTitle(title);                            // Set the window title
    this.theApp = theApp;
    setJMenuBar(menuBar);                       // Add the menu bar to the window
    setDefaultCloseOperation(EXIT_ON_CLOSE);    // Default is exit the application

    // Rest of the constructor as before...

You need to add the theApp variable to the SketchFrame class:

private Sketcher theApp;

There are new methods in the Sketcher class that return a reference to the application window, the model, and the view, so any of these are accessible from anywhere that a reference to the application object is available.

After creating the model and view objects, we register the view as an observer for the model to enable the model to notify the view when it changes. We then add the view to the content pane of the window object, which is the main application window. Since it is added in the center using the BorderLayout manager for the content pane, it will occupy all the remaining space in the pane.

Now that we know roughly the direction in which we are heading, let's move on down the road.

Previous Next
JavaScript Editor Java Tutorials Free JavaScript Editor