Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
This month we'll build on several subjects covered in prior columns -- including graphics, observers and observables, events, and components and containers.
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 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.

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 |
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 |
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.
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.
Graphics class