Not because it is very sophisticated, but because it is simple, this program serves as an example of some of the things we've covered in this chapter, and also, in its subclasses, provides a springboard for other discussions. This class describes a series of old-fashioned (i.e., common in the 1970s and 1980s) pen plotters. A pen plotter, in case you've never seen one, is a device that moves a pen around a piece of paper and draws things. It can lift the pen off the paper or lower it, and it can draw lines, letters, and so on. Before the rise of laser printers and ink-jet printers, pen plotters were the dominant means of preparing charts of all sorts, as well as presentation slides (this was, ah, well before the rise of programs like Harvard Presents and Microsoft PowerPoint). Today few companies still manufacture pen plotters, but I use them here because they are simple enough to be well understood from this brief description. I'll present a high-level class that abstracts the key characteristics of a series of such plotters made by different vendors. It would be used, for example, in an analytical or data-exploration program to draw colorful charts showing the relationships found in data. But I don't want my main program to worry about the gory details of any particular brand of plotter, so I'll abstract into a Plotter class, whose source is as follows: /** * Plotter abstract class. Must be subclassed * for X, DOS, Penman, HP plotter, etc. * * Coordinate space: X = 0 at left, increases to right. * Y = 0 at top, increases downward (same as AWT). */ public abstract class Plotter { public final int MAXX = 800; public final int MAXY = 600; /** Current X co-ordinate (same reference frame as AWT!) */ protected int curx; /** Current Y co-ordinate (same reference frame as AWT!) */ protected int cury; /** The current state: up or down */ protected boolean penIsUp; /** The current color */ protected int penColor; Plotter( ) { penIsUp = true; curx = 0; cury = 0; } abstract void rmoveTo(int incrx, int incry); abstract void moveTo(int absx, int absy); abstract void penUp( ); abstract void penDown( ); abstract void penColor(int c); abstract void setFont(String fName, int fSize); abstract void drawString(String s); /* Concrete methods */ /** Draw a box of width w and height h */ public void drawBox(int w, int h) { penDown( ); rmoveTo(w, 0); rmoveTo(0, h); rmoveTo(-w, 0); rmoveTo(0, -h); penUp( ); } /** Draw a box given an AWT Dimension for its size */ public void drawBox(java.awt.Dimension d) { drawBox(d.width, d.height); } /** Draw a box given an AWT Rectangle for its location and size */ public void drawBox(java.awt.Rectangle r) { moveTo(r.x, r.y); drawBox(r.width, r.height); } } Note the variety of abstract methods. Those related to motion, pen control, or drawing are left out, due to the number of different methods for dealing with them. However, the method for drawing a rectangle (drawBox) has a default implementation, which simply puts the currently selected pen onto the paper at the last-moved-to location, draws the four sides, and raises the pen. Subclasses for "smarter" plotters will likely override this method, but subclasses for less-evolved plotters will probably use the default version. This method also has two overloaded convenience methods for cases where the client has an AWT Dimension for the size or an AWT Rectangle for the location and size. To demonstrate one of the subclasses of this program, consider the following simple " driver" program. The Class.forName( ) near the beginning of main is discussed in Recipe 25.2; for now you can take my word that it simply creates an instance of the given subclass, which we store in a Plotter reference named "r" and use to draw the plot: /** Main program, driver for Plotter class. * This is to simulate a larger graphics application such as GnuPlot. */ public class PlotDriver { /** Construct a Plotter driver, and try it out. */ public static void main(String[] argv) { Plotter r ; if (argv.length != 1) { System.err.println("Usage: PlotDriver driverclass"); return; } try { Class c = Class.forName(argv[0]); Object o = c.newInstance( ); if (!(o instanceof Plotter)) throw new ClassNotFoundException("Not instanceof Plotter"); r = (Plotter)o; } catch (ClassNotFoundException e) { System.err.println("Sorry, "+argv[0]+" not a plotter class"); return; } catch (Exception e) { e.printStackTrace( ); return; } r.penDown( ); r.penColor(1); r.moveTo(200, 200); r.penColor(2); r.drawBox(123, 200); r.rmoveTo(10, 20); r.penColor(3); r.drawBox(123, 200); r.penUp( ); r.moveTo(300, 100); r.penDown( ); r.setFont("Helvetica", 14); r.drawString("Hello World"); r.penColor(4); r.drawBox(10, 10); } } We'll see more examples of this Plotter class and its relatives in several upcoming chapters. |