Image maps were a neat addition to the Web a few years ago. Rather than a list of textual links, you could open up an URL by clicking a particular part of an image. These image maps still have limitations, however, because they are not very interactive. You can create a Java image map, however, that contains hotspots-areas that light up when the mouse passes over them. You can also add context-sensitive help, which is always a nice thing to have.
To create an image map with hot spot, you need a way to define what a "hot spot" is. You could simply create a class that represented an area of the image. This class would also be responsible for displaying whatever should appear when the mouse passes over the hot spot. Listing 7.8 shows an abstract class that defines the methods necessary to implement such a class.
Listing 7.8 Source Code for ImageRegion.java
import java.awt.*;
// ImageRegion is an abstract definition of the region // area supported by the ImageMap class.
public abstract class ImageRegion extends Object {
public ImageRegion() {
Chapter 7 -- Creating Smarter Forms
// select is called when you click the mouse within a region public void select()
{ }
// mouseEnter is called when the mouse enters a region public void mouseEnter()
{ }
// mouseLeave is called when the mouse leaves a region public void mouseLeave()
{ }
// getBoundingBox should return the smallest rectangle that // completely encloses this region.
public abstract Rectangle getBoundingBox(); // inside returns true if x,y is within this region public abstract boolean inside(int x, int y); // paint is used to draw any hotspot popup information public void paint(Graphics g)
{ } }
Because the ImageRegion class is an abstract class, you need something concrete to actually implement a region. You will almost certainly need to define a rectangular region at some point. Actually, it is trivial to extend a rectangular region to be a polygon region. Listing 7.9 shows an implementation of ImageRegion that supports polygon regions.
Listing 7.9 Source Code for ImageRegionPoly.java
import java.awt.*;
// ImageRegionPoly implements a rectangular region for // use with the ImageMap class.
public class ImageRegionPoly extends ImageRegion {
Polygon boundary;
public ImageRegionPoly() {
Chapter 7 -- Creating Smarter Forms
boundary = new Polygon(); }
public ImageRegionPoly(Polygon p) {
boundary = p; }
public Rectangle getBoundingBox() {
return boundary.getBoundingBox(); }
public boolean inside(int x, int y) {
return boundary.inside(x, y); }
}
You may also have a need for a circular region. The ImageRegionCircle class in Listing 7.10 implements a circular region.
Listing 7.10 Source Code for ImageRegionCircle.java
import java.awt.*;
// ImageRegionCircle defines a circular region for use // with the ImageMap class.
public class ImageRegionCircle extends ImageRegion {
Point center; int radius;
public ImageRegionCircle() {
center = new Point(0, 0); radius = 0;
}
public ImageRegionCircle(Point center, int radius) {
this.center = center; this.radius = radius; }
Chapter 7 -- Creating Smarter Forms
{
return new Rectangle(center.x - radius, center.y - radius, 2*radius, 2*radius);
}
// Use the distance formula to determine if a point is inside or not. // If the distance between x,y and the center of the region is <= the // radius of the circle, the point is within the region.
public boolean inside(int x, int y) {
int xd = center.x - x; int yd = center.y - y;
int dist = (int) Math.sqrt(xd*xd+yd*yd); return dist <= radius;
} }
Now that you have a method for defining a region in an image, you need a way to display an image, add these regions to it, and track the mouse to see when it hits a region. The ImageMap class in Listing 7.11 does just that. It also shows you how to define a canvas that displays an image.
Listing 7.11 Source Code for ImageMap.java
import java.awt.*; import java.util.*;
// The image map is a canvas that displays an image and supports // hotspots. The hotspots are defined by subclasses of ImageRegion. // There can only be one hotspot active at a time. Whenever a hotspot // is active, its paint method is called so it can paint any popup // information. You could display a little box of text saying what // the hotspot does, for instance. The default paint method for a // hotspot does nothing.
public class ImageMap extends Canvas { Image image; Vector regions; ImageRegion selectedRegion; boolean moved;
public ImageMap(Image image) {
this.image = image;
Chapter 7 -- Creating Smarter Forms
regions = new Vector(); moved = true;
}
// The size of the Canvas is defined by the size of the image. public Dimension minimumSize()
{
return new Dimension(image.getWidth(this), image.getHeight(this));
}
public Dimension preferredSize() {
return minimumSize(); }
public Dimension size() {
return minimumSize(); }
public void addRegion(ImageRegion region) {
regions.addElement(region); }
public void removeRegion(ImageRegion region) { regions.removeElement(region); if (region == selectedRegion) { selectedRegion = null; } }
// To repaint this canvas, redraw the image. Then, if there is a hotspot // active, call that hotspot's paint method.
public void paint(Graphics g) {
// Draw the image
g.drawImage(image, 0, 0, this); if (selectedRegion != null) {
// Find the bounding box for the current region (hotspot) Rectangle r = selectedRegion.getBoundingBox(); // Create a graphics context for the bounding box
Graphics regionGraphics = g.create(r.x, r.y, r.width, r.height);
Chapter 7 -- Creating Smarter Forms
selectedRegion.paint(regionGraphics); }
}
// Flicker-free update
public void update(Graphics g) {
paint(g); }
The next section of the ImageMap class demonstrates a very important concept in object-oriented design. The ImageMap
class implements a framework that allows you to plug in different ImageRegion objects. You can add many new types of
ImageRegion objects without changing the ImageMap class itself. It is very important to correctly assign class
responsibilities in your design. In this case, the ImageMap class is responsible for displaying the master image, or background image. It is also responsible for tracking mouse movements and passing them on to affected regions. The
ImageRegion class is responsible for displaying itself on the map if necessary, and for responding to a mouse click.
Tip
When designing classes for an application, you want to be able to add functionality by adding new classes, and not by changing existing classes. Try to identify things that may change and let those things be implemented by a separate class.
Listing 7.11 Source Code for ImageMap.java (continued)
// Need to watch the mouse movement to see if the mouse hits // a hotspot or not.
public boolean mouseMove(Event evt, int x, int y) {
moved = true; // kludge to handle mouse-click problem // Quick shortcut here, see if you're still in the current region if ((selectedRegion != null) &&
selectedRegion.inside(x, y)) { return true;
}
// If there's a current region and you're not in it, tell the old // region that the mouse left it.
if (selectedRegion != null) { selectedRegion.mouseLeave(); selectedRegion = null;
}
Chapter 7 -- Creating Smarter Forms
// Check all the regions to see if the mouse is within any of them. // If two overlap, it's on a first come, first served basis - that is, // the first region that was added has priority.
Enumeration e = regions.elements(); while (e.hasMoreElements()) {
ImageRegion r = (ImageRegion) e.nextElement(); // See if the mouse's x,y is within the region's area
if (r.inside(x, y)) { selectedRegion = r; r.mouseEnter(); break; } } repaint(); return true; }
// Mouse down handles mouse clicks, and also will keep track // of mouse movement
public boolean mouseDown(Event evt, int x, int y) {
// The moved flag is a kludge. Sometimes you'll get more than // one mouse click. Assume that if the mouse doesn't move // between clicks, the user doesn't want more than one click. if (!moved) return true;
moved = false; // Quick shortcut here
if ((selectedRegion != null) && selectedRegion.inside(x, y)) { selectedRegion.select(); return true; } if (selectedRegion != null) { selectedRegion.mouseLeave(); selectedRegion = null; } Enumeration e = regions.elements(); while (e.hasMoreElements()) {
ImageRegion r = (ImageRegion) e.nextElement(); if (r.inside(x, y)) {
selectedRegion = r; r.mouseEnter(); r.select();
Chapter 7 -- Creating Smarter Forms break; } } repaint(); return true; } }
You may have noticed that the implementations of the image regions were incredibly small and didn't really seem to do anything. You are correct on both counts. To get any benefit out of the regions, you have to create subclasses that actually do something.
Suppose you want to create a map that has a set of circular hotspots that light up with the name of the city in that section of the map. You need to keep track of the name of the city and also implement a paint method that displays the city name. Because an image map isn't very useful if you can't select items, your city hotspot should also do something when you click it. Listing 7.12 shows a circular region that represents a city. When you click the region, it pops up an OK dialog box telling you which city you clicked.
Listing 7.12 Source Code for CityRegion.java
import java.awt.*;
// This class implements a special version of the
// ImageRegionCircle class to represent cities on a map. // When the mouse gets within range of a city, the city name // is displayed. When you click the city, it pops up a dialog // box telling you what city you clicked.
public class CityRegion extends ImageRegionCircle {
String name;
public CityRegion() {
}
// You can specify either x,y to create a CityRegion or a Point public CityRegion(String name, int x, int y)
{
// Set up the region as a circle with a radius of 30 pixels super(new Point(x, y), 30); // radius of 30 this.name = name;
}
Chapter 7 -- Creating Smarter Forms
public CityRegion(String name, Point p) {
// Set up the region as a circle with a radius of 30 pixels super(p, 30); // radius of 30
this.name = name; }
// Paint is called when the mouse is within this city's bounding // area - for this class, defined as a circle of radius 30
// We just draw the city's name in blue. Note that the graphics
// area is bounded by the bounding box for the region (actually, the // smallest rectangle that will enclose the area because the regions // can be non-rectangular).
public void paint(Graphics g) {
g.setColor(Color.blue); g.drawString(name, 0, 35); }
// If you click a city, you'll get a dialog box public void select()
{
OKDialog.createOKDialog("You selected the city of "+name); }
}
Now that all the pieces of the puzzle are in, you can create an the image map for displaying these cities. Listing 7.13 shows
the CityApplet class.
Listing 7.13 Source Code for CityApplet.java
import java.awt.*; import java.applet.*;
// This applet demonstrates the use of the ImageMap class // It loads a map of the U.S.A. and creates a set of regions
// for the map. The regions are implemented in the CityRegion class. // The numbers for the city coordinates are approximate, and were // determined through ocular analysis (I eyeballed the map).
public class CityApplet extends Applet {
public void init() {
Chapter 7 -- Creating Smarter Forms
// Load the map image
Image usaImage = getImage(getDocumentBase(), "usa.gif"); // Be naughty and use the MediaTracker to make sure the map is loaded MediaTracker mt = new MediaTracker(this);
mt.addImage(usaImage, 0);
try {
mt.waitForAll();
} catch (Exception ignore) { }
// Create an image map object for the image
ImageMap imageMap = new ImageMap(usaImage); // Add city regions to the image map
imageMap.addRegion(new CityRegion("Atlanta", 323, 202)); imageMap.addRegion(new CityRegion("New York", 377, 118)); imageMap.addRegion(new CityRegion("L.A.", 45, 196));
imageMap.addRegion(new CityRegion("San Fran", 34, 164)); imageMap.addRegion(new CityRegion("Seattle", 52, 74)); imageMap.addRegion(new CityRegion("Dallas", 218, 236)); imageMap.addRegion(new CityRegion("Chicago", 277, 123)); imageMap.addRegion(new CityRegion("Miami", 367, 270)); imageMap.addRegion(new CityRegion("Denver", 102, 143)); // Add the image map to the applet
add(imageMap); }
}
Figure 7.5 shows the output from this applet.
Figure 7.5 : Image maps in Java can implement hot spots.
file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/f7-2.gif
file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/f7-4.gif
Chapter 8 -- Reading and Writing Files from an Applet