import javax.swing.*; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; /** * Class Canvas - a class to allow for simple graphical * drawing on a canvas. * * ---> This is the primitives-free version of Canvas! <--- * * @author Bruce Quig * @author Michael Kolling (mik) * @author Dave Musicant - made some local changes * @author Amy Csizmar Dalal - more minor local changes * @author Jeff Ondich - added setFontSize and getInkColor * @author David Liben-Nowell - renamed fillX() and height/width parameters * * 1.7.0: primitive-free version. * 1.7.1: renamed wait()->pause(). * 1.7.2: added eraseFilledX(), renamed internal variables. * * @version 1.7.2 * date: 05.04.2006 */ public class Canvas { private JFrame frame; protected CanvasPane canvas; private Graphics2D graphic; private Color backgroundColor; private Color inkColor; private Image canvasImage; /** * Create a Canvas with default height, width and background color * (300, 300, white). * @param title title to appear in Canvas Frame */ public Canvas(String title) { this(title, 300, 300, Color.white); } /** * Create a Canvas with default title, height, width and background color * ("Canvas", 300, 300, white). */ public Canvas() { this("Canvas", 300, 300, Color.white); } /** * Create a Canvas with default background Color (white). * @param title title to appear in Canvas Frame * @param width the desired width for the canvas * @param height the desired height for the canvas */ private Canvas(String title, Integer width, Integer height) { this(title, width, height, Color.white); } /** * Create a Canvas. * @param title title to appear in Canvas Frame * @param width the desired width for the canvas * @param height the desired height for the canvas * @param bgColor the desired background color of the canvas */ private Canvas(String title, Integer width, Integer height, Color bgColor) { frame = new JFrame(); canvas = new CanvasPane(); frame.setContentPane(canvas); frame.setTitle(title); canvas.setPreferredSize(new Dimension(width, height)); backgroundColor = bgColor; inkColor = Color.black; frame.pack(); // Added by acd: this is a hack that will allow other components, // like buttons, to be added to the canvas and be visible. // basically, it's saying "when you repaint, don't fill the entire // canvas with the background color", i.e. leave the buttons and // stuff alone! canvas.setOpaque(false); // end of hack frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { setVisible(false); System.exit(0); } }); if(graphic == null) { // first time: instantiate the offscreen image and fill it with // the background color Dimension size = canvas.getSize(); canvasImage = canvas.createImage(size.width, size.height); graphic = (Graphics2D)canvasImage.getGraphics(); graphic.setColor(backgroundColor); graphic.fillRect(0, 0, size.width, size.height); graphic.setColor(inkColor); } } /** * Sets the "pen" (outline) color for the Canvas. * @param newColor The color to which to set the pen/drawing tool. */ public void setInkColor(Color newColor) { inkColor = newColor; graphic.setColor(inkColor); } /** * Returns the current pen color. */ public Color getInkColor() { return inkColor; } /** * Set the canvas visibility and brings canvas to the front of screen * when made visible. This method can also be used to bring an already * visible canvas to the front of other windows. * @param visible Boolean value representing the desired visibility of * the canvas (true or false) */ public void setVisible(Boolean visible) { /*if (visible) frame.show(); else frame.hide();*/ /* EDITED BY ACD: show() and hide() are deprecated in Java 1.5; replace with setVisible(Boolean) */ frame.setVisible(visible); } /** * Provide information on visibility of the Canvas. * @return true if canvas is visible, false otherwise */ public Boolean isVisible() { return frame.isVisible(); } /** * Draw a given shape onto the canvas. * @param shape the shape object to be drawn on the canvas */ private void draw(Shape shape) { graphic.draw(shape); canvas.repaint(); } /** * Fill the internal dimensions of a given shape with the current * foreground color of the canvas. * @param shape the shape object to be filled */ private void fill(Shape shape) { graphic.fill(shape); canvas.repaint(); } /** * Erase the whole canvas. */ public void erase() { Color original = graphic.getColor(); graphic.setColor(backgroundColor); Dimension size = canvas.getSize(); graphic.fill(new Rectangle(0, 0, size.width, size.height)); graphic.setColor(original); canvas.repaint(); } /** * Erase a given shape's interior on the screen. * @param shape the shape object to be erased */ private void erase(Shape shape) { Color original = graphic.getColor(); graphic.setColor(backgroundColor); graphic.fill(shape); // erase by filling background color graphic.setColor(original); canvas.repaint(); } /** * Erases a given shape's outline on the screen. * @param shape the shape object to be erased */ private void eraseOutline(Shape shape) { Color original = graphic.getColor(); graphic.setColor(backgroundColor); graphic.draw(shape); // erase by drawing background color graphic.setColor(original); canvas.repaint(); } /** * Draws an image onto the canvas. * @param image the Image object to be displayed * @param x x coordinate for Image placement * @param y y coordinate for Image placement * @return returns Boolean value representing whether the image was * completely loaded */ private Boolean drawImage(Image image, Integer x, Integer y) { Boolean result = graphic.drawImage(image, x, y, null); canvas.repaint(); return result; } /** * Draws a String on the Canvas. * @param text the String to be displayed * @param x x coordinate for text placement * @param y y coordinate for text placement */ public void drawString(String text, Integer x, Integer y) { graphic.drawString(text, x, y); canvas.repaint(); } /** * Erases a String on the Canvas. * @param text the String to be displayed * @param x x coordinate for text placement * @param y y coordinate for text placement */ public void eraseString(String text, Integer x, Integer y) { Color original = graphic.getColor(); graphic.setColor(backgroundColor); graphic.drawString(text, x, y); graphic.setColor(original); canvas.repaint(); } /** * Draws a line on the Canvas. * @param x1 x coordinate of start of line * @param y1 y coordinate of start of line * @param x2 x coordinate of end of line * @param y2 y coordinate of end of line */ public void drawLine(Integer x1, Integer y1, Integer x2, Integer y2) { graphic.drawLine(x1, y1, x2, y2); canvas.repaint(); } /** * Draws a rectangle on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void drawRectangle(Integer x, Integer y, Integer width, Integer height) { graphic.draw(new Rectangle(x, y, width, height)); canvas.repaint(); } /** * Draws a filled rectangle on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void drawFilledRectangle(Integer x, Integer y, Integer width, Integer height) { graphic.fill(new Rectangle(x, y, width, height)); canvas.repaint(); } /** * Draws a polygon on the Canvas. * @param xs array of x coordinates of polygon points * @param ys array of y coordinates of polygon points * @param size the number of points (vertices) in the polygon */ public void drawPolygon(Integer[] xs, Integer[] ys, Integer size) { Integer length = xs.length; int[] primitiveXs = new int[length]; int[] primitiveYs = new int[length]; for (Integer i = 0; i < length; i++) { primitiveXs[i] = xs[i]; primitiveYs[i] = ys[i]; } graphic.draw(new Polygon(primitiveXs,primitiveYs,size)); canvas.repaint(); } /** * Draws a filled polygon on the Canvas. * @param xs array of x coordinates of polygon points * @param ys array of y coordinates of polygon points * @param size the number of points (vertices) in the polygon */ public void drawFilledPolygon(Integer[] xs, Integer[] ys, Integer size) { Integer length = xs.length; int[] primitiveXs = new int[length]; int[] primitiveYs = new int[length]; for (Integer i = 0; i < length; i++) { primitiveXs[i] = xs[i]; primitiveYs[i] = ys[i]; } graphic.fill(new Polygon(primitiveXs,primitiveYs,size)); canvas.repaint(); } /** * Erases a rectangle on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void eraseRectangle(Integer x, Integer y, Integer width, Integer height) { eraseOutline(new Rectangle(x, y, width, height)); } /** * Erases a filled rectangle on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void eraseFilledRectangle(Integer x, Integer y, Integer width, Integer height) { erase(new Rectangle(x, y, width, height)); } /** * Draws an oval on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void drawOval(Integer x, Integer y, Integer width, Integer height) { graphic.draw(new Ellipse2D.Double(x, y, width, height)); canvas.repaint(); } /** * Draws a filled oval on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void drawFilledOval(Integer x, Integer y, Integer width, Integer height) { graphic.fill(new Ellipse2D.Double(x, y, width, height)); canvas.repaint(); } /** * Erases an oval on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void eraseOval(Integer x, Integer y, Integer width, Integer height) { eraseOutline(new Ellipse2D.Double(x, y, width, height)); } /** * Erases a filled oval on the Canvas. * @param x x coordinate of top left corner * @param y y coordinate of top left corner * @param width width * @param height height */ public void eraseFilledOval(Integer x, Integer y, Integer width, Integer height) { erase(new Ellipse2D.Double(x, y, width, height)); } /** * Sets the foreground color of the Canvas. * @param newColor the new color for the foreground of the Canvas */ private void setForegroundColor(Color newColor) { graphic.setColor(newColor); } /** * Returns the current color of the foreground. * @return the color of the foreground of the Canvas */ private Color getForegroundColor() { return graphic.getColor(); } /** * Sets the background color of the Canvas. * @param newColor the new color for the background of the Canvas */ private void setBackgroundColor(Color newColor) { backgroundColor = newColor; graphic.setBackground(newColor); } /** * Fills in the Canvas (background) with the specified color. * @param newColor the new color for the background of the Canvas */ public void fillBackground(Color newColor) { Dimension size = canvas.getSize(); backgroundColor = newColor; graphic.setColor(backgroundColor); graphic.fillRect(0, 0, size.width, size.height); graphic.setColor(inkColor); } /** * Returns the current color of the background * @return the color of the background of the Canvas */ private Color getBackgroundColor() { return backgroundColor; } /** * changes the current Font used on the Canvas * @param newFont new font to be used for String output */ public void setFont(Font newFont) { graphic.setFont(newFont); } /** * Returns the current font of the canvas. * @return the font currently in use **/ public Font getFont() { return graphic.getFont(); } /** * Sets the point size of the current font to the specified value. * The style and font family remain the same. * * @param newSize the new point size */ public void setFontSize( Integer newSize ) { Font f = graphic.getFont().deriveFont( (float)newSize ); setFont( f ); } /** * Sets the size of the canvas. * @param width new width * @param height new height */ public void setSize(Integer width, Integer height) { canvas.setPreferredSize(new Dimension(width, height)); Image oldImage = canvasImage; canvasImage = canvas.createImage(width, height); graphic = (Graphics2D)canvasImage.getGraphics(); graphic.setColor(backgroundColor); graphic.fillRect(0, 0, width, height); graphic.setColor(inkColor); graphic.drawImage(oldImage, 0, 0, null); frame.pack(); } /** * Returns the size of the canvas. * @return The current dimension of the canvas */ private Dimension getSize() { return canvas.getSize(); } /** * Waits for a specified number of milliseconds before finishing. * This provides an easy way to specify a small delay which can be * used when producing animations. * @param milliseconds the number */ public void pause(Integer milliseconds) { try { Thread.sleep(milliseconds); } catch (Exception e) { // ignoring exception at the moment } } /************************************************************************ * Nested class CanvasPane - the actual canvas component contained in the * Canvas frame. This is essentially a JPanel with added capability to * refresh the image drawn on it. * MODIFIED by acd: changed visibility to protected (from private) * to allow subclassing (basically, so we can add mouse listeners to * the canvas), and added the call to super.paint() (an additional hack * to allow us to add components like buttons and menus to the canvas). */ protected class CanvasPane extends JPanel { public void paint(Graphics g) { g.drawImage(canvasImage, 0, 0, null); super.paint(g); } } }