package CSLib; import java.awt.*; import java.awt.event.*; /** * DrawingBox is a frame upon which many of the * java.awt.Graphics operations can be performed. As a * frame, it exists as a separate window, and the operations on it may be * performed from anywhere -- not just from within a paint * method (as is normal with a frame's Graphics object). * (However, to be used effectively as a teaching aid, operations on a * DrawingBox should be performed from within * a single method, which later can be converted to a paint * method.) *

* Care must be taken that when this frame is obscured, that * subsequently it can repaint itself. An off-screen Graphics * context keeps an up-to-date copy of this frame's Graphics * at all times. The origin of the coordinate system is translated so that * it is in the upper left of the drawable portion of the * frame. Consequently, DrawingBox behaves more like a * Canvas object that occupies the drawable portion of a frame. *

* In order to distinguish the Frame from its drawable portion, * methods getDrawableWidth and getDrawableHeight * are provided. *

* DrawingBox uses inner classes DBMouseAdapter * (extending java.awt.event.MouseAdapter) to implement mouse * listeners, and DBMouseMotionAdapter (extending * java.awt.event.MouseMotionAdapter) to implement mouse * motion listeners. * * @see ClosableFrame * @see java.awt.Graphics * * @author M. Dennis Mickunas * */ public class DrawingBox extends ClosableFrame { /** * the Graphics object affiliated with this Frame */ private Graphics g; /** * the size of the user's screen */ Dimension screenSize; /** * an off-screen image of everything that is done to g */ private Image buffer; /** * the Graphics affiliated with the off-screen image */ private Graphics gContext; /** * Constructs a DrawingBox with the default title. */ public DrawingBox () { this ("DrawingBox"); } /** * Constructs a DrawingBox with a specific title. * * @param title the string to use as this DrawingBox title. * * @see java.awt.Graphics#translate(int, int) * @see java.awt.Container#getInsets() */ public DrawingBox (String title) { super(title); screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setBackground(Color.white); // By default, set size to 1/2 screen wide by 1/2 screen high. setSize(screenSize.width/2, screenSize.height/2); setVisible(true); g = getGraphics(); validate(); setFont(new Font("Courier", Font.PLAIN, 12)); // Create an off-screen image, and get its Graphics object buffer = createImage(screenSize.width, screenSize.height); gContext = buffer.getGraphics(); gContext.setColor(Color.white); gContext.fillRect(0, 0, screenSize.width, screenSize.height); gContext.setColor(Color.black); // Translate the origin to the upper-left corner of the drawable area. g.translate(getInsets().left, getInsets().top); addMouseListener(new DBMouseAdapter()); addMouseMotionListener(new DBMouseMotionAdapter()); } /** * DBMouseAdapter is an inner class that implements * the Mouse listener for DrawingBox. It does this * by extending the Java convenience wrapper MouseAdapter. *

* Each MouseEvent must be translated to correspond * to the translated coordinate system of the DrawingBox. * This translation remains in effect for any downstream mouse * listeners. * * @see java.awt.event.MouseAdapter * @see java.awt.event.MouseEvent#translatePoint(int int) * @see java.awt.Container#getInsets() */ public class DBMouseAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { e.translatePoint(-getInsets().left, -getInsets().top); } public void mouseEntered(MouseEvent e) { e.translatePoint(-getInsets().left, -getInsets().top); } public void mouseExited(MouseEvent e) { e.translatePoint(-getInsets().left, -getInsets().top); } public void mousePressed(MouseEvent e) { e.translatePoint(-getInsets().left, -getInsets().top); } public void mouseReleased(MouseEvent e) { e.translatePoint(-getInsets().left, -getInsets().top); } } /** * DBMouseMotionAdapter is an inner class that implements * the Mouse motion listener for DrawingBox. It does this * by extending the Java convenience wrapper * MouseMotionAdapter. *

* Each MouseEvent must be translated to correspond to the * translated coordinate system of the DrawingBox. This * translation remains in effect for any downstream mouse motion listeners. * * @see java.awt.event.MouseMotionAdapter * @see java.awt.event.MouseEvent#translatePoint(int int) * @see java.awt.Container#getInsets() */ public class DBMouseMotionAdapter extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { e.translatePoint(-getInsets().left, -getInsets().top); } public void mouseMoved(MouseEvent e) { e.translatePoint(-getInsets().left, -getInsets().top); } } /** * Paints the drawing box. This will be called when the drawing box must * be restored. The off-screen image in buffer has a true * copy of what was drawn in the drawing box. * * @see java.awt.Container#getInsets() */ public void paint (Graphics g) { // Restore the DrawingBox from the offscreen cache, // making sure that the insets are avoided. if (buffer!=null) g.drawImage(buffer, getInsets().left, getInsets().top, this); } /** Returns the current drawable width (less insets) of this drawing box. * * @see java.awt.Container#getInsets() * * @return the current drawable width of this drawing box. */ public int getDrawableWidth () { return getSize().width-getInsets().left-getInsets().right; } /** Returns the current drawable height (less insets) of this drawing box. * * @see java.awt.Container#getInsets() * * @return the current drawable height of this drawing box. */ public int getDrawableHeight () { return getSize().height-getInsets().top-getInsets().bottom; } /** * Sets the drawable size of this drawing box by setting a smaller size, * then increasing it by the amount of the insets. * * @see java.awt.Container#getInsets() * * @param width the desired drawable width * @param height the desired drawable height */ public void setDrawableSize (int width, int height) { super.setSize(width, height); super.setSize(width+getInsets().left+getInsets().right, height+getInsets().top+getInsets().bottom); } /** * Gets this drawing box's current color. * * @return this drawing box's current color. * * @see java.awt.Color * @see java.awt.Graphics#getColor */ public Color getColor () { return g.getColor(); } /** * Sets this drawing box's color. * * @param c the desired drawing box's color. * * @see java.awt.Color * @see java.awt.Graphics#setColor */ public void setColor (Color c) { g.setColor(c); gContext.setColor(c); } /** * Draws the outline of a circular or elliptical arc covering the specified rectangle.

* The resulting arc begins at startAngle and extends for arcAngle degrees, using the * current color. Angles are interpreted such that 0 degrees is at the 3 o'clock position. A * positive value indicates a counter-clockwise rotation while a negative value indicates a * clockwise rotation.

* The center of the arc is the center of the rectangle whose upper left hand corner is * located at (x, y) and whose size is specified by the width and height arguments.

* The resulting arc covers an area width + 1 pixels wide by height + 1 pixels tall.

* The angles are specified relative to the non-square extents of the bounding rectangle such * that 45 degrees always falls on the line from the center of the ellipse to the upper right * corner of the bounding rectangle. As a result, if the bounding rectangle is noticeably * longer in one axis than the other, the angles to the start and end of the arc segment will be * skewed farther along the longer axis of the bounds. * Parameters: * @param x - the x coordinate of the upper-left corner of the arc to be drawn. * @param y - the y coordinate of the upper-left corner of the arc to be drawn. * @param width - the width of the arc to be drawn. * @param height - the height of the arc to be drawn. * @param startAngle - the beginning angle. * @param arcAngle - the angular extent of the arc, relative to the start angle. */ public void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle) { gContext.drawArc (x, y, width, height, startAngle, arcAngle); g.drawArc (x, y, width, height, startAngle, arcAngle); } /** * Draws a line, using the current color, between the points * (x1,y1) and (x2,y2) * in this drawing box's coordinate system. * * @param x1 the first point's x coordinate. * @param y1 the first point's y coordinate. * @param x2 the second point's x coordinate. * @param y2 the second point's y coordinate. * * @see java.awt.Graphics#drawLine */ public void drawLine (int x1, int x2, int y1, int y2) { gContext.drawLine (x1, x2, y1, y2); g.drawLine (x1, x2, y1, y2); } /** * Draws the outline of the specified rectangle. * The left and right edges of the rectangle are at * x and x+width. * The top and bottom edges are at * y and y+height. * The rectangle is drawn using this drawing box's current color. * * @param x the x coordinate * of the rectangle to be drawn. * @param y the y coordinate * of the rectangle to be drawn. * @param width the width of the rectangle to be drawn. * @param height the height of the rectangle to be drawn. * * @see java.awt.Graphics#drawRect */ public void drawRect (int x, int y, int width, int height) { gContext.drawRect (x, y, width, height); g.drawRect (x, y, width, height); } /** * Fills the specified rectangle. * The left and right edges of the rectangle are at * x and x+width-1. * The top and bottom edges are at * y and y+height-1. * The resulting rectangle covers an area * width pixels wide by * height pixels tall. * The rectangle is filled using this drawing box's current color. * * @param x the x coordinate * of the rectangle to be filled. * @param y the y coordinate * of the rectangle to be filled. * @param width the width of the rectangle to be filled. * @param height the height of the rectangle to be filled. * * @see java.awt.Graphics#fillRect */ public void fillRect (int x, int y, int width, int height) { gContext.fillRect (x, y, width, height); g.fillRect (x, y, width, height); } /** * Draws the outline of a circle. * The result is a circle with center at (x,y) * and a given radius. * * @param x the x coordinate of the center * of the circle to be drawn. * @param y the y coordinate of the center * of the circle to be drawn. * @param radius the radius of the circle to be drawn. * * @see java.awt.Graphics#drawOval */ public void drawCircle (int x, int y, int radius) { gContext.drawOval (x-radius, y-radius, 2*radius, 2*radius); g.drawOval (x-radius, y-radius, 2*radius, 2*radius); } /** * Draws the outline of a circle. * The result is a circle with center at p * and a given radius. * * @param p the point giving the center of the * circle to be drawn. * @param radius the radius of the circle to be drawn. * * @see CSLib#drawCircle(int, int, int) */ public void drawCircle (Point p, int radius) { drawCircle (p.x, p.y, radius); } /** * Fills a circle with center at (x,y) * and with a given radius using this drawing box's current color. * * @param x the x coordinate of the center * of the circle to be filled. * @param y the y coordinate of the center * of the circle to be filled. * @param radius the radius of the circle to be filled. * * @see java.awt.Graphics#fillOval */ public void fillCircle (int x, int y, int radius) { gContext.fillOval (x-radius, y-radius, 2*radius, 2*radius); g.fillOval (x-radius, y-radius, 2*radius, 2*radius); } /** * Fills a circle with center at point p * and with a given radius, using this drawing box's current color. * * @param p the point giving the center of the * circle to be filled. * @param radius the radius of the circle to be filled. * * @see CSLib#fillCircle(int, int, int) */ public void fillCircle (Point p, int radius) { fillCircle(p.x, p.y, radius); } /** * Draws the text given by the specified string, using this * drawing box's current font and color. The baseline of the * leftmost character is at position (x,y) in this * drawing box's translated coordinate system. * * @param str the string to be drawn. * @param x the x coordinate. * @param y the y coordinate. * * @see java.awt.Graphics#drawString */ public void drawString (String str, int x, int y) { gContext.drawString (str, x, y); g.drawString (str, x, y); } /** * Fills an oval bounded by the specified rectangle with this * drawing box's current color. * * @param x the x coordinate of the upper left corner * of the oval to be filled. * @param y the y coordinate of the upper left corner * of the oval to be filled. * @param width the width of the oval to be filled. * @param height the height of the oval to be filled. * * @see java.awt.Graphics#fillOval */ public void fillOval (int x1, int y1, int width, int height) { gContext.fillOval (x1, y1, width, height); g.fillOval (x1, y1, width, height); } /** * Draws the outline of an oval. * The result is an ellipse that fits within the rectangle * specified by the x, y, * width, and height arguments. * * @param x the x coordinate of the upper left * corner of the oval to be drawn. * @param y the y coordinate of the upper left * corner of the oval to be drawn. * @param width the width of the oval to be drawn. * @param height the height of the oval to be drawn. * * @see java.awt.Graphics#drawOval */ public void drawOval (int x1, int y1, int width, int height) { gContext.drawOval (x1, y1, width, height); g.drawOval (x1, y1, width, height); } /** * Clears the specified rectangle by filling it with the background * color of the current drawing box. * * @param x the x coordinate of the rectangle to clear. * @param y the y coordinate of the rectangle to clear. * @param width the width of the rectangle to clear. * @param height the height of the rectangle to clear. * * @see java.awt.Graphics#setColor * @see java.awt.Graphics#fillRect * @see java.awt.Graphics#clearRect */ public void clearRect (int x, int y, int width, int height) { gContext.setColor(Color.white); gContext.fillRect (x, y, width, height); gContext.setColor(g.getColor()); g.clearRect (x, y, width, height); } /** * Clears the entire drawing box. * * @see java.awt.Graphics#setColor * @see java.awt.Graphics#fillRect * @see java.awt.Graphics#clearRect */ public void clear() { gContext.setColor(Color.white); gContext.fillRect (0, 0, screenSize.width, screenSize.height); gContext.setColor(g.getColor()); g.clearRect(0, 0, getDrawableWidth(), getDrawableHeight()); } /** * Draws the specified image with its top-left corner at * (x,y) in this drawing box's coordinate system. *

* This method waits for the image to be fully loaded. * * @param img the specified image to be drawn. * @param x the x coordinate. * @param y the y coordinate. * * @see java.awt.Graphics#drawImage * @see java.awt.Image * @see java.awt.MediaTracker */ public void drawImage (Image img, int x, int y) { // Wait for the image to be fully loaded. MediaTracker checker = new MediaTracker(this); checker.addImage(img, 0); try { checker.waitForID(0);} catch (InterruptedException e){}; // Now draw it. gContext.drawImage(img, x, y, this); g.drawImage(img, x, y, this); } }