Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

Implementing The Model-View-Controller Paradigm using Observer and Observable

Java Programming, Lecture Notes # 200, Revised 02/24/98.

Preface

Students in Prof. Baldwin's Advanced Java Programming classes at ACC are responsible for knowing and understanding all of the material in this lesson.

Introduction

In a nutshell, the Model-View-Controller (MVC) paradigm is an approach to programming that separates data input, data processing, and data output in such a way that either the input or the output can be modified without having any impact on the processing.

This is also another application of callbacks in Java.

The Model-View-Controller Paradigm

The MVC concept has been used in the Smalltalk world for some time, and has now been carried forward into Java. The primary Java tools for implementing MVC are the Observable class and the Observer interface.

The Observable class is used to implement the Model (where the data processing is performed) and the Observer interface is used to implement the View (where the results of the processing are displayed).

No special tools are required to implement the Controller which handles data input.

According to Mark Wutka in Java Expert Solutions:
 
"The idea behind MVC is that an application really consists of three things-a model, some views of the model, and some controllers

The model is the part of the application that contains the actual application logic. ... When we talk about separating the user interface from the application, the model is the application. 

If the model represents the application, then the view and controller represent the user interface. The user interface is conceptually split into input components and output components. 

A controller is an input component. It supplies information to the model. 

A view is an output component-it displays information from the model. 

MVC is not some brand new, untested theory - it is the way Smalltalk applications have been written for many years. "

In a discussion having to do with format translation of input data, Wutka also tells us:
 
"The model should have absolutely no dependence on the external representation of information. This is an extremely important point, because it greatly affects the reusability of your code. 

You should be able to change input sources and change output formats without touching the model. In other words, the model deals with pure information that has no external meaning attached to it."

In other words, Wutka is saying that the model should have no responsibility for translating the format of input data. Such translation, if required, should be performed in the Controller. Also, the model should have no responsibility for determining how results are to be displayed.

In his discussion of Observables and the Model-View-Controller Paradigm Wutka tells us:
 
"The Observer interface and the Observable class make it easier for you to create views of data in the model by creating a notification system to let your view know when data in the model has changed. 

The mechanism is very simple. You create some object in your model that is a subclass of Observable. Anytime this class changes, it calls setChanged to flag itself as having changed, and then calls notifyObservers

The reason for the separation is that you may run through a series of checks in your model, any one of which might change the data. When you have finished, you call notifyObservers one time, rather than notifying the observers after every check. Whether to notify every time or periodically is a design decision."

Many word processors provide good examples of the MVC concept at work. Most word processors provide at least two views of the data: the WYSIWYG edit view and the preview of how the page will actually look when the document is printed.

In the case of word processors, the Controller collects keystrokes from the keyboard and delivers them to the Model which notifies the View that the data has changed so that the updated data can be displayed.

Sometimes with a word processor, a slow computer, and a large document, the View will lag behind the Controller and the Model, but normally this doesn't have any detrimental impact on the ability of the Controller and the Model to do their jobs. The Model simply notifies the views that the data has changed. It doesn't know or care what the View does with the data, or if the View is able to keep up. In fact, the Model might not even know anything about the View other than that it is registered for notification of changes in the data.

This lesson makes no attempt to provide a rigorous discussion of MVC. If you link to your favorite search engine and do a search, you will probably find more material on the subject than you have the time to read (although most of it will probably be couched in Smalltalk). Rather, this lesson will attempt to teach you how to use Java to implement MVC.

If you go to the news groups, you will probably find more discussion and debate on the topic than you care to read (for example, do a search on Observable at DejaNews.com).

As is often the case, we will attempt to teach you how to use Java to implement MVC by examining a sample program that implements MVC.

The MVC Sample Program

This program illustrates the use of the Observer interface and the Observable class in the implementation of the Model-View-Controller (MVC) paradigm.

When you run this program, three Frame objects will appear on the screen in a column. The top Frame object is the Controller object that lets you enter temperature data in Celsius into a TextField object. The Controller object also lets you terminate the program by clicking its close box.

The two bottom Frame objects display different Views of the temperature data after it has been converted to Fahrenheit by the Model. One displays the data in standard digital format. The other converts the temperature to a color and displays the color.

Conversion from Celsius to Fahrenheit is the data processing function of the model.

The Model-View-Controller paradigm requires one Model object, one or more Controller objects, and one or more View objects.

This program instantiates a Model object, as an instance of the class named ModelClass that extends the Observable class.

The Model object is instantiated on the main thread. The program saves a reference to the Model object in an instance variable of the controlling class for use by the methods of the other objects.

The program spawns one thread which is a Controller object and two threads which are View objects. In other words, one Controller object is provided to accept user input and pass it along to the Model object. Two different View objects are provided that display two different views of the value of the property named temp maintained by the Model object.

The Model, the Controller, and both View objects all operate on different threads.

The Model object accepts temperature values in Celsius, from the Controller object, converts them to Fahrenheit as data-processing task, and maintains them as a property named temp. Only one value of the temp property is maintained. New temperature values cause the current value of the temp property to be overwritten.

Because the class named ModelClass (which is used to instantiate the Model object) extends the Observable class, objects of type ModelClass have the ability to maintain a list of registered Observer objects (View objects). This is a form of callbacks.

Interested Observer (View) objects register their interest in being notified of changes in the temp property of the Model by invoking the addObserver() method of the Observable class on a reference to the Model object.

Whenever the property value changes, the Model object notifies all of the registered View objects of the change, passing its own identify and the new value of the temp property to each of the registered View objects.

The registered View objects are notified only when actual changes occur in the temp property value. If two successive input temperature values from the Controller object are the same (don't result in an actual change in the temp property), the View objects are not notified.

The notification process consists of calculating and saving the new value of the temp property in Fahrenheit, invoking the setChanged() method of the Observable class (as described earlier), and then invoking the notifyObservers() method of the Observable class.

The actual notification of the registered View objects takes place behind the scenes. As is typical for this sort of thing in Java, the notification is accomplished by invoking the update() method on each of the registered View objects and passing the identity of the Model object along with the new value of the temp property as parameters (similar to notifying listener objects than an event has occurred).

Although this program has only one Controller object, there is no reason that additional Controller objects could not be added. Therefore, the setTemp() method is synchronized to avoid the possibility of two or more Controller objects trying to modify the temp property value at the same time.

A Thread class named ControlThread is used to implement a Controller object that accepts temperature data from the user and passes the data along to the Model object.

The Controller object provides a TextField object that the user can access to enter new temperature values. If the user enters a character combination that cannot be successfully converted to a double value, an error message appears in the TextField object.

The mechanism by which the Controller object sends new data to the Model object is by invoking the setTemp() method on a reference to the Model object. The reference to the Model object is passed to the Controller object when it is instantiated to be saved and used later for this purpose.

The "close" button on the Frame provided by the Controller object is used to terminate the program. An anonymous inner-class is used to instantiate an anonymous WindowListener object to accomplish this.

A named inner-class action listener object is registered on the TextField to process the user-input data whenever the user presses the [Enter] key while the TextField has the focus.

The ActionListener object extracts the data from the TextField object, converts it to a double value (if possible), and sends it to the Model object by invoking the setTemp() method on the reference to the Model object and passing the double value as a parameter.

If the TextField data is successfully converted to a double value, the TextField object is cleared for entry of new data. If not, an error message is written into the TextField object.

Two View objects are instantiated and registered on the Model object. One of the View objects displays the temperature data in digital form in a Frame object.

The other View object converts the temperature data to a color and displays the color in a Frame object with red tones indicating warmer and blue tones indicating colder.

The "close" buttons on the Frame objects provided by the View objects are not active. As mentioned earlier, the program can be terminated by clicking the "close" button on the Frame object provided by the Controller object.

Both of the View objects are passed a reference to the Model object when they are instantiated. This reference is saved and used later to register the View objects on the Model object for notification of changes to the temp property value maintained by the Model object.

Each of the View objects registers its interest in receiving such notifications by invoking the addObserver() method on its reference to the Model object.

View objects receive notification of changes in the values of interest by having their update() method invoked. This method is declared by the Observer interface which is implemented by the two View classes.

The update() methods of all registered View objects are invoked when the notifyObservers() method of the Observable class is invoked by code in the Model object (after having first invoked the setChanged() method of the Observable class).

When the upDate() method is invoked, the identification of the Model object and the value of the temp property are passed in as parameters. The parameter identifying the Model object is not used in this program because the View objects are registered on only one Model and therefore, identification of the source is not required.

Code within the upDate() method of one of the View objects displays the value of the temp property in digital format.

Code within the upDate() method of the other View object converts the value of the temp property to a color and displays the color.

Thus, we have two different views of the data which has been provided by the Controller object and processed by the Model object, in the same sense that a typical word processing program provides two or more views of data provided by the user and processed by the program.

Although our sample program deals only with one simple property of type double, an object is passed to the View object when its update() method is invoked and there is no reason that that object could not contain a variety of different instance variables to be used by the View object for different purposes.

Similarly, even though the Controller object passes only a simple double value to the Model object, there is no reason that the Controller object could not pass an object containing a variety of instance variables for use by the Model object.

This program was tested using JDK 1.1.3 under Win95.

Interesting Code Fragments

The first interesting code fragment is an instance variable of the controlling class named refToModel that provides the critical link between the Model object and the Controller and View objects.

The Controller objects must be able to access the Model object in order to invoke the setTemp() method on the Model object to pass data to the Model object.

Similarly, the View objects must be able to access the Model object in order to invoke the addObserver() method on the Model object to register themselves as observers.

Therefore, some kind of link that supports invocation of methods on the Model object by the Controller and View objects is critical to the overall operation of the program.
 
class Mvc01{//controlling class
  ModelClass refToModel;//reference to the Model object
As is typical, the main method instantiates an object of the controlling class. Inside the constructor of the controlling class, a new object of the ModelClass is instantiated on the main thread. A reference to that object is assigned to the instance variable named refToModel as discussed above.
 
  Mvc01(){//constructor
    refToModel = new ModelClass();  
Next, we spawn three new threads: two for View objects, and one for a Controller object. As a result, all of the major components of our program are operating on different threads. The following code fragment is typical of that used to instantiate and start the three thread objects.
 
    Thread view1Thread = 
           new Thread(new view1Thread(refToModel),"View1");    
    view1Thread.start();
Next, we define a class that is used to instantiate an object that represents the Model. This Model converts incoming temperature data in degrees Celsius to temperature in degrees Fahrenheit and makes those temperature values available to any View objects that are registered for notification when the value changes.

Because this class extends Observable, it knows how to registerObservers to be notified when the value of interest changes, and to notify Observers when that happens.

The first interesting code fragment for this class is the line showing that it extends Observable and the instance variable that constitutes the property named temp.

A property is a special thing (not just an instance variable) and the name of the property derives from the Java design patterns that say that a property that is set by a method named setTemp() is itself named temp. This naming convention is discussed more fully in the lessons on Java Beans. The value of the property named temp is actually maintained in an instance variable named tempF.

The value of the property named temp is observed and displayed by the View objects in this program.
 
class ModelClass extends Observable{
  double tempF;
Because of the simplicity of this Model, all of the data processing as well as notification of registered observers takes place inside the setTemp() method, which is the method invoked by the Controller object to provide new data to the Model.

When this method is invoked by the Controller object with new data, the method first converts the data from Celsius to Fahrenheit and then confirms that there is actually a change in the data value. If the value has not actually changed, the registered View objects are not notified.

If the value of the property named temp has actually changed, the code goes through the required steps of first invoking the setChanged() method and then invoking the notifyObservers() method. The rationale for this two-step process was explained in the earlier quotation from Wutka.

Note that the name tempF is used both as the name of an instance variable of the class (this.tempF) and as the name of a local variable in the method (another name choice for the local variable might have been better, but this does illustrate the ability to use the this reference to disambiguate such things).
 
  synchronized void setTemp(double tempC){
    double tempF = 1.8 * tempC + 32;//convert C to F
    if(tempF != this.tempF){//confirm value changed
      this.tempF = tempF;
      this.setChanged();//required by notifyObservers()
      notifyObservers(new Double(this.tempF));
    }//end if
  }//end setTemp()
setTemp() is the only method in the class named ModelClass, so now we come to the definition of the class from which the Controller object is instantiated.

This class is named controlThread and implements the runnable interface so that it can be used to instantiate a Thread object.

The constructor for this class receives a reference to the Model object and saves it in an instance variable named refToModel. The constructor code is too simple to highlight here, but you can see it in the complete listing of the program near the end of this document.

Objects of this class are visual, and provide a TextField object into which the user can enter temperature data in Celsius.

As is the case in all Thread objects, the real work is done in the run() method, or in methods invoked by run().

Most of the code in the body of the run() method is used to construct the visual user interface in a Frame object. You have seen code of this type many times before. Therefore, much of it has been deleted from this section of interesting code fragments. You can view all of the code in the complete program listing that appears later in this lesson.

As you can see, this is pretty straightforward stuff at this point.
 
  public void run(){
    //Construct the visual display for the Control in a 
    // Frame object
    // ...
    TextField textField = new TextField(15);
    // ...
    //Register an action listener object on the TextField 
    // object that will be notified when the user presses 
    // the <Enter> key while the TextField has the focus.
    textField.addActionListener(
                              new ActionListenerClass());
    //...    
  }//end run()
Most of the actual work is in the Controller object is performed by the actionPerformed() method that is invoked when the user enters some data into the TextField object and presses the [Enter] key.

The actionPerformed() method is defined in a class named ActionListenerClass. This is a named inner class of the class named controlThread. It was made an inner class simply to make it easier to gain access to the refToModel variable that is used to send new data to the Model object (avoids passing a parameter to a constructor).

Objects of this class listen for action events on the TextField object. When an action event occurs, the text is read from the TextField, converted to a double value, and passed into the setTemp() method of the Model object.

As soon as the text data is read from the TextField object, the text field is cleared for entry of new data.

If the attempt to convert the incoming data to a valid double value fails, an exception is thrown and an error message is displayed in the text field.

If no exception is thrown, the new double value is sent to the Model object by invoking the setTemp() method on that object and passing the new value as a parameter.

Note that the methods of the Double wrapper class are used in the attempt to convert the input String data to a numeric double value.
 
    public void actionPerformed(ActionEvent e){
      String data = ((TextField)e.getSource()).getText();
      //Clear the TextField object for next entry
      ((TextField)e.getSource()).setText("");
      try{
        refToModel.setTemp(new Double(data).doubleValue());
      }catch(NumberFormatException excep){//on bad input
        ((TextField)e.getSource()).setText(//error message
                                      "Numeric Data Only");
      }//end catch block
    }//end actionPerformed()
Following this, two Thread classes are defined (classes that implement the Runnable interface) to serve as the two View objects. One of the View objects displays the temperature data in typical printed digital format. The other converts the data to a color and displays the color.

Again, the work is done in the run() methods of the two classes, and much of the work involves creating the visual Frame object for the display. Most of the code required to construct the display will be deleted from this portion of the lesson. It is available for you to view later in the complete program listing.

As before, the constructors for these two classes receive and save a reference to the Model object as an instance variable named refToModel. This reference is needed so that the View objects can register with the Model as observers. The constructor is too simple to show here.

An additional instance variable of type Label, named displayWindow, is also declared for later use. In one class, it is used to display the temperature in digital form. In the other class, the background color of the label is used to display a color that represents the temperature.

The first interesting code fragment is the code in the run() methods of both View classes that registers the object to be notified whenever a change occurs in the value of the temp property in the Model object. This registration is accomplished by invoking the addObserver() method on the reference to the Model object as shown below.

This is followed by some code to construct the visual Frame object in which the temperature data will be displayed. That code has been deleted from the following representation of the run() method.
 
  public void run(){
    refToModel.addObserver(this);//register
    //...
  }//end run()
Once an Observer object is registered on an Observable object, the update() method in the Observer object will be invoked whenever the notifyObservers() method is invoked on the Observable object. The parameters to the update() method consist of two objects: one object to identify the Observable object, and the other parameter to contain the values being observed.

Each of the View objects contains an update() method and this is where the temperature data is formatted for display in the two visual Frame objects created and maintained by the View objects.

The update() methods in the two View classes are similar. I am going to show you the version that displays the temperature data in color because it is the most interesting of the two. The other one simply uses the setText() method of the Label object to display the incoming temperature, although some casting and the use of the Double wrapper class is required to disassemble the incoming object.

For both cases, the update() method is invoked (behind the scenes) by the Model object to notify the View object that the value of the property named temp maintained by the Model has changed. The new value is encapsulated in a Double object by the Model object and passed to the update() method as an object of type Object known locally as arg.

This particular view displays the temperature as a color with a temperature of 255 or greater being pure red, a temperature of 0 or lower being pure blue, and temperatures in between resulting in a proportional mixture of red and blue. The following code fragment shows how this is accomplished.
 
  public void update(Observable o, Object arg){
    double temp = ((Double)arg).doubleValue();
    if(temp > 255.0) temp = 255.0;//clip at 255
    if(temp < 0.0) temp = 0.0;//clip at zero
    int red = (int)temp;
    int blue = (int)(255-temp);
    //Set the green contribution to the color to zero.
    displayWindow.setBackground(new Color(red,0,blue));
  }//end update()  
}//end class view2Thread
A complete listing of the program follows.

Program Listing

See the earlier text in this lesson for an operational description of this program. Some of the interesting code fragments are highlighted in boldface.
 
/*File Mvc01.java  Copyright 1997, R.G.Baldwin
This program illustrates the use of the Observer interface
and the Observable class in the implementation of the
Model-View-Controller (MVC)paradigm.

When you run this program, three Frame objects will appear
on the screen in a column.  The top Frame object is the
Control object that lets you enter temperature data into
a TextField object.  This object also lets you terminate
the program by clicking its close box.

The two bottom Frame objects display different Views of
the temperature data.  One displays the data in standard
digital format.  The other converts the temperature to a
color and displays the color.

This program was tested using JDK 1.1.3 under Win95.

=========================================================*/

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

//=======================================================//
class Mvc01{//controlling class
  ModelClass refToModel;//reference to the Model object
  //-----------------------------------------------------//
  
  static public void main(String[] args){
    new Mvc01();//Instantiate this object.
  }//end main
  //-----------------------------------------------------//
    
  Mvc01(){//constructor
    //Instantiate an object of the Model class on the main 
    // thread.
    refToModel = new ModelClass();  

    //Spawn two View threads, and one Control thread.
    // First instantiate the thread objects.
    Thread view1Thread = 
           new Thread(new view1Thread(refToModel),"View1");
    Thread view2Thread = 
           new Thread(new view2Thread(refToModel),"View2");
    Thread control1Thread = 
       new Thread(new controlThread(refToModel),"Control");

    // Now start the threads running.    
    view1Thread.start();
    view2Thread.start();
    control1Thread.start(); 
  }//end constructor
}//end class Mvc01
//=======================================================//

//This class is used to instantiate an object that 
// represents the Model in the MVC paradigm. This Model
// converts incoming temperature data in degrees Celsius
// to temperature in degrees Fahrenheit and makes those
// temperature values  available to any Views that are 
// registered for notification when the value changes.
//
// Because this class extends Observable, it also knows
// how to register Observers to be notified when the
// value of interest changes, and to notify Observers when
// that happens.
class ModelClass extends Observable{
  double tempF;
  //-----------------------------------------------------//
  
  //This is the method by which the Control provides new
  // input data to the Model. This method also notifies
  // registered View objects when the value of the temp
  // property has changed.
  synchronized void setTemp(double tempC){
    //Convert from Celsius to Fahrenheit
    double tempF = 1.8 * tempC + 32;
    //Confirm that value has change, and if so notify
    // View objects.
    if(tempF != this.tempF){
      this.tempF = tempF;
      this.setChanged();//required by notifyObservers()
      notifyObservers(new Double(this.tempF));
    }//end if
  }//end setTemp()
}//end ModelClass
//=======================================================//

//This class is used to instantiate an object to serve as
// the Control in the MVC paradigm.  Values entered into
// a TextField object are sent to the Model
class controlThread implements Runnable{
  ModelClass refToModel;//Reference to the Model object.
  //-----------------------------------------------------//
  
  controlThread(ModelClass refToModel){//constructor
    this.refToModel = refToModel;
  }//end constructor
  //-----------------------------------------------------//
  
  public void run(){
    //Construct the visual display for the Control in a 
    // Frame object
    Frame control = new Frame(
                          "Copyright 1997, R.G.Baldwin");
    control.setLayout(new FlowLayout());
    control.setBounds(0,0,300,135);
    control.add(new Label(
      "Control:  Enter temperature in Celsius here"));
    TextField textField = new TextField(15);
    textField.setBackground(Color.yellow);
    control.add(textField);
    control.add(new Label(
                      "Close this Frame to terminate."));
    control.setVisible(true);

    //Register an action listener object on the TextField 
    // object that will be notified when the user presses 
    // the <Enter> key while the TextField has the focus.
    textField.addActionListener(
                              new ActionListenerClass());
    
    //Instantiate an anonymous inner-class listener object
    // to terminate program when the user clicks the close
    // box on the Frame object.
    control.addWindowListener(new WindowAdapter(){
             public void windowClosing(WindowEvent e){
               System.exit(0);}});//end addWindowListener
  }//end run()
  //=====================================================//

  //This is a listener class that is a named inner class 
  // of the class named controlThread.  It was made
  // an inner class to make it easier to gain access
  // to the refToModel variable that is used to send new
  // data to the Model.
  
  //Objects of this class listen for action events on the
  // TextField object.  When an action event occurs, the
  // text is read from the TextField, converted to a
  // double value, and passed into the setTemp() method of
  // the Model object.
  class ActionListenerClass implements ActionListener{
    public void actionPerformed(ActionEvent e){
      String data = ((TextField)e.getSource()).getText();
      //Clear the TextField object for next entry
      ((TextField)e.getSource()).setText("");
      try{
        refToModel.setTemp(
                           new Double(data).doubleValue());
      }catch(NumberFormatException excep){//on bad input
        ((TextField)e.getSource()).setText(//error message
                                      "Numeric Data Only");
      }//end catch block
    }//end actionPerformed()
  }//end inner class named ActionListenerClass      
    
}//end class controlThread
//=====================================================//

//This class is used to instantiate a thread  object
// that is a View in the MVC paradigm.  This particular
// View displays the temp property of the Model in 
// digital format.  Note that this is a Thread class.
class view1Thread implements Observer, Runnable{
  Label displayWindow;     
  ModelClass refToModel;
  //-----------------------------------------------------//
  
  view1Thread(ModelClass refToModel){//constructor
    this.refToModel = refToModel;//save the reference
  }//end constructor
  //-----------------------------------------------------//
  
  public void run(){
    //Register this object to be notified whenever
    // a change occurs in the value of the temp property
    // in the Model object.
    refToModel.addObserver(this);//register
    
    //Create a display panel for the View
    Frame display = new Frame("View1 - Digital View");
                display.setLayout(new FlowLayout());
                display.add(new Label(
                      "Fahrenheit View of Temperature: "));
    displayWindow = new Label("       ");
    display.add(displayWindow);
    display.setBounds(0,135,300,100);
    display.setVisible(true);
  }//end run()
  //-----------------------------------------------------//
  
  //This method is invoked by the Model to notify that
  // the value of the temp property maintained by the
  // Model has changed.  The new value is passed in as arg.
  public void update(Observable o, Object arg){
    displayWindow.setText("" + ((Double)arg).doubleValue());
  }//end update()  
}//end class view1Thread
//=======================================================//

//This class is used to instantiate a thread object that
// is a View in the MVC paradigm.  This particular View
// displays the property value of the Model object in
// color format: more red for warmer and more blue for
// cooler.  Note that this is a Thread class.
class view2Thread implements Observer, Runnable{
  Label displayWindow;
  ModelClass refToModel;
  //-----------------------------------------------------//
  
  view2Thread(ModelClass refToModel){//constructor
    this.refToModel = refToModel;//save the reference
  }//end constructor
  //-----------------------------------------------------//
    
  public void run(){
    //Register this object to be notified whenever a 
    // change occurs in the value of the temp property
    // in the Model object.
    refToModel.addObserver(this);//register
    
    //Create a display panel for the View
    Frame display = new Frame("View2 - Color View");
    display.setLayout(new FlowLayout());
    displayWindow = new Label(
              "                                      ");
    display.add(displayWindow);
    display.add(new Label(
              "     Blue means Cold, Red means Hot   "));
    display.setBounds(0,235,300,100);
    display.setVisible(true);      
  }//end run()
  //-----------------------------------------------------//
  
  //This method is invoked by the Model object to notify
  // the View that the value of the property named temp
  // maintained by the Model has changed.  The new value
  // is passed in as arg. 
  public void update(Observable o, Object arg){
    //This view displays the temperature as a color
    // with a temperature of 255 or greater being
    // pure red, a temperature of 0 or lower being
    // pure blue, and temperatures in between 
    // resulting in a proportional mixture of red and 
    // blue.
    double temp = ((Double)arg).doubleValue();
    if(temp > 255.0) temp = 255.0;
    if(temp < 0.0) temp = 0.0;
    int red = (int)temp;
    int blue = (int)(255-temp);
    //Set the green contribution to the color to zero.
    displayWindow.setBackground(new Color(red,0,blue));
  }//end update()  
}//end class view2Thread
//=======================================================//
-end-