Newsletter sign-up
View all newsletters

Sign up for our Enterprise Java Newsletter

Enterprise Java

Examining HotSpot, an object-oriented drawing program

Learn how the pieces of the Java language and class library fit together through a study of this Java program

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
After spending several months looking at the parts of a system one piece at a time here in the in How To Java column, it's time to learn how to put them together and actually build something. The result is HotSpot.

This month we'll build on several subjects covered in prior columns -- including graphics, observers and observables, events, and components and containers.

The application

HotSpot is a simple, object-oriented drawing program. A drawing program allows a user to create a picture from a palette of simple geometric shapes. Once a shape has been placed on the drawing surface, the user can reselect it and adjust its size, shape, and position. In this respect, a drawing program differs from a paint program, in which a shape, once placed on the drawing surface, becomes nothing more than a colored collection of pixels.

Figure 1 shows a typical HotSpot drawing surface or "canvas." This canvas holds a single shape -- a square -- which has small gray boxes at its corners and center. These boxes are called hot spots, and they allow the user to manipulate the square.


Figure 1: A HotSpot canvas


Figure 2 illustrates the role hot spots play. The user selects a specific shape on the canvas by positioning the mouse over one of the hot spots and clicking on it. The user can then adjust the shape, size, and position of the selection by dragging the hot spot with the mouse.


Figure 2: Interaction with a HotSpot shape


The program HotSpot was named, obviously, after these hot spots. In keeping with the principles of object-oriented software design, each of the major components of the HotSpot program is represented by a Java language class. This set of components includes the canvas, the shapes, and even the hot spots.

Table 1 lists the classes that make up the HotSpot program. Class Shape and its subclasses represent the types of shapes that can be placed on a canvas. A Shape object contains a list of HotSpot objects that represent that shape's hot spots. Shape objects are managed by a ShapeMgr object, which is nothing more than a fancy subclass of class Canvas. The ShapeMgr object plays two roles: It manages a list of shapes and provides a place for them to draw themselves. The ShapeMgr object contains a HotSpotMgr object. In a manner similar to that of the ShapeMgr object, the HotSpotMgr object manages a list of HotSpot objects and also provides a convenient mechanism for locating the hot spot at a particular set of coordinates.



Shape public abstract class Shape implements Observer
RectangleShape public class RectangleShape extends Shape implements Observer
OvalShape public class OvalShape extends Shape implements Observer
LineShape public class LineShape extends Shape implements Observer
HotSpot public class HotSpot extends Observable
ShapeMgr public class ShapeMgr extends Canvas
HotSpotMgr public class HotSpotMgr
Main public class Main extends Applet
Dimensions public class Dimensions
Coordinates public class Coordinates


The pieces

By now two things should be obvious. First, HotSpot is not a particularly revolutionary drawing program. Second, a lot of thought was put into the design of HotSpot to ensure that it effectively demonstrates the material introduced in prior How To Java columns.

Table 2 illustrates the relationship between the classes in Table 1 and the subjects mentioned in the introduction. By structuring this article in this fashion, I hope to associate the subject matter of my earlier columns with these classes, thereby providing a concrete, relevant example of their place in the context of a "real" program.



graphics classes Shape and HotSpot
observers and observables classes Shape, HotSpot, and ShapeMgr
events class ShapeMgr
components and containers classes ShapeMgr and Main



Graphics

In addition to providing the internal representation of hot spots and shapes, class HotSpot and class Shape must provide for their graphical representation on a canvas. Internally, instances of class HotSpot and class Shape contain information about their respective positions. The classes provide a paint() method that uses this information to draw the graphical representation on a suitable surface. The code for the paint() method of class HotSpot is:

public void paint(Graphics g)
{
   g.fillRect(_coord.x - _dim.w / 2,
              _coord.y - _dim.h / 2,
              _dim.w - 1,
              _dim.h - 1);
}


The code for class RectangleShape's paint() method is:

public void paint(Graphics g)
{
   int x = _w < 0 ? _x + _w : _x;
   int y = _h < 0 ? _y + _h : _y;
   int w = _w < 0 ? -_w : _w;
   int h = _h < 0 ? -_h : _h;
   g.drawRect(x, y, w, h);
}


Since class Shape is abstract, class RectangleShape was selected as a representative non-abstract subclass of class Shape. Both methods require, as a parameter, an instance of class Graphics. The paint() method for class HotSpot uses the Graphics object's fillRect() method to draw a small rectangle on the canvas. The paint() method of class RectangleShape first ensures that the shape's width and height parameters are non-negative, and then calls the Graphics object's drawRect() method to draw a rectangle of the correct size. Each of class Shape's subclasses also provides a paint() method that functions like that of class RectangleShape's paint() method.

Observers and Observables

Consider the user's interaction with the drawing program once more. As the user changes the location of a hot spot with the mouse, both the position and size of the associated shape and the position of some of the shape's other hot spots change. Clearly the program needs some mechanism for passing information about one hot spot's change in position to the shape and to the other hot spots whose positions are dependent in some way on its position. Class Observable and interface Observer allow HotSpot to solve this problem. The following is the code for Class RectangleShape's update() method:

public void update(Observable obs, Object obj)
{
   Coordinates coordTL = _hsTL.getCoordinates();
   Coordinates coordTR = _hsTR.getCoordinates();
   Coordinates coordBL = _hsBL.getCoordinates();
   Coordinates coordBR = _hsBR.getCoordinates();
   Coordinates coordC = _hsC.getCoordinates();
   if (obs == _hsTL)
   {
      _x = coordTL.x;
      _y = coordTL.y;
      _w = coordBR.x - coordTL.x;
      _h = coordBR.y - coordTL.y;
   }
   else if (obs == _hsTR)
   {
      _y = coordTR.y;
      _w = coordTR.x - coordTL.x;
      _h = coordBR.y - coordTR.y;
   }
   else if (obs == _hsBL)
   {
      _x = coordBL.x;
      _w = coordBR.x - coordBL.x;
      _h = coordBL.y - coordTL.y;
   }
   else if (obs == _hsBR)
   {
      _w = coordBR.x - coordTL.x;
      _h = coordBR.y - coordTL.y;
   }
   else if (obs == _hsC)
   {
      _x = coordC.x - _w/2;
      _y = coordC.y - _h/2;
   }
   _hsTL.setCoordinates(new Coordinates(_x, _y));
   _hsTR.setCoordinates(new Coordinates(_x + _w, _y));
   _hsBL.setCoordinates(new Coordinates(_x, _y + _h));
   _hsBR.setCoordinates(new Coordinates(_x + _w, _y + _h));
   _hsC.setCoordinates(new Coordinates(_x + _w/2, _y + _h/2));
}


Each of the subclasses of class Shape implements the Observer interface, which means that each of these classes must implement an update() method that takes as a parameter an instance of class Observable. The code above shows how this method was implemented for class RectangleShape. The update() method determines the coordinates of each of the shape's hot spots and recalculates all of their positions based on the hot spot whose position changed.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.