/** * File: HW1_Sample.java * Author: Marsette Vona * Created: 1/19/10 **/ import javax.swing.*; import java.awt.*; import java.awt.geom.*; import java.awt.font.*; import java.util.Random; /** *

This is an example using the Java2D API for CS4300 Homework 1, a 2D * "sampler" program.

* *

To compile: javac HW1_Sample.java

* *

To generate doc: javadoc -d doc HW1_Sample.java

* *

To run: java HW1_Sample [arrangement], where arrangement is either A, B, * or empty to use the default.

* *

{@link #main} creates a singleton instance of HW1_Sample. The * constructor then takes over, and crates a frame populated with five {@link * Rect} in a BorderLayout. The arrangement of the content of the * rects is determined by command line argument, and can be "A" (the default) * or "B".

**/ public class HW1_Sample { /** base size for rectangles **/ public static final int SIZE = 256; /** drawing clear color **/ public static final Color BACKGROUND_COLOR = Color.WHITE; /** rect border color **/ public static final Color BORDER_COLOR = Color.BLACK; /** *

Random number generator.

* *

Always reset with same seed at start of each redraw, so drawing is * deterministic.

**/ static final Random random = new Random(); /** *

An on-screen rectangle that knows its preferred size and how to paint * itself.

**/ public abstract class Rect extends JComponent { /** *

Creates a new rect and sets its preferred size and border.

* *

The actual drawing is done in {@link #paint2D}, which subclasses * should implement.

* * @param preferredWidth the preferred (and initial) width * @param preferredHeight the preferred (and initial) height **/ public Rect(int preferredWidth, int preferredHeight) { setPreferredSize(new Dimension(preferredWidth, preferredHeight)); setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); } /** *

Clear the rect to {@link #BACKGROUND_COLOR}.

**/ public void clear(Graphics2D g2d) { g2d.setBackground(BACKGROUND_COLOR); g2d.clearRect(0, 0, getWidth(), getHeight()); } /** *

{@link #clear} and then {@link #paint2D}.

**/ public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; clear(g2d); Stroke strokeWas = g2d.getStroke(); Color colorWas = g2d.getColor(); AffineTransform xformWas = g2d.getTransform(); random.setSeed(1234); paint2D(g2d); g2d.setStroke(strokeWas); g2d.setColor(colorWas); g2d.setTransform(xformWas); } /** *

Subclasses should implement this to actually do the painting.

* *

Stroke, color, and transform of g2d will be automatically * saved before painting and restored afterwards.

**/ public abstract void paint2D(Graphics2D g2d); } /** base class for long rects **/ public abstract class LongRect extends Rect { /** sets preferred dims based on {@link #SIZE} **/ public LongRect() { super(SIZE*4, SIZE); } } /** base class for tall rects **/ public abstract class TallRect extends Rect { /** sets preferred dims based on {@link #SIZE} **/ public TallRect() { super(SIZE, SIZE*2); } } /** a specific long painting **/ public class LongRectA extends LongRect { /** *

Draws a text string.

**/ public void paint2D(Graphics2D g2d) { int[] styles = new int[] {Font.PLAIN, Font.ITALIC, Font.BOLD}; int fontStyle = styles[rndi(0,3)]; int fontSize = rndi(8, 64); Font font = new Font(Font.DIALOG, fontStyle, fontSize); //select random font. This can take a long time. // Font[] allFonts = // GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); // if (allFonts.length > 0) { // font = // allFonts[rndi(0, allFonts.length)].deriveFont(fontStyle, fontSize); // } g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); TextLayout tl = new TextLayout("CS4300 Homework 1 Sample", font, g2d.getFontRenderContext()); int w = getWidth(), h = getHeight(); Rectangle2D tlb = tl.getBounds(); tl.draw(g2d, (float) (w/2.0-tlb.getWidth()/2.0), (float) (h/2.0-tlb.getHeight()/2.0)); } } /** a specific long painting **/ public class LongRectB extends LongRect { /** *

Draws a set of random curved paths.

**/ public void paint2D(Graphics2D g2d) { int w = getWidth(), h = getHeight(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Path2D.Float p = new Path2D.Float(); double x1, y1, x2, y2, x3, y3; for (int i = 0; i < 200; i++) { g2d.setStroke(new BasicStroke(rndf(0.0, 8.0), //width BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2d.setColor(rndColor()); p.reset(); x1 = rndf(0, w); y1 = rndf(0, h); p.moveTo(x1, y1); x3 = x1; y3 = y1; for (int j = 0; j < rndi(0, 32); j++) { x1 = x3 + rndf(-32, 32); y1 = y3 + rndf(-32, 32); x2 = x1 + rndf(-32, 32); y2 = y1 + rndf(-32, 32); x3 = x2 + rndf(-32, 32); y3 = y2 + rndf(-32, 32); p.curveTo(x1, y1, x2, y2, x3, y3); g2d.draw(p); } } } } /** a specific tall painting **/ public class TallRectA extends TallRect { /** *

Draws a set of random ellipses.

**/ public void paint2D(Graphics2D g2d) { AffineTransform xformWas = g2d.getTransform(); int w = getWidth(), h = getHeight(); Ellipse2D.Float e = new Ellipse2D.Float(); for (int i = 0; i < 200; i++) { g2d.setTransform(xformWas); g2d.transform(AffineTransform.getRotateInstance(rndf(0, Math.PI))); g2d.setColor(rndColor()); e.setFrame(rndi(0, w), rndi(0, h), rndi(16, 64), rndi(16, 64)); if (i%2 == 0) g2d.fill(e); else g2d.draw(e); } } } /** a specific tall painting **/ public class TallRectB extends TallRect { /** *

Draws a set of nested axis aligned rectangles with a color * gradient.

**/ public void paint2D(Graphics2D g2d) { int w = getWidth(), h = getHeight(); Color fromClr = rndColor(), toClr = rndColor(); Rectangle2D.Float r = new Rectangle2D.Float(); int n = 1 + ((w < h) ? w/2 : h/2); for (int x = 0, y = 0; (w >= 0) && (h >= 0); x++, y++, w -= 2, h -= 2) { float t = ((float) x)/((float) n); if (x%8 == 0) { g2d.setColor(new Color( (int) (fromClr.getRed()*(1.0f-t)+toClr.getRed()*t), (int) (fromClr.getGreen()*(1.0f-t)+toClr.getGreen()*t), (int) (fromClr.getBlue()*(1.0f-t)+toClr.getBlue()*t))); r.setRect(x, y, w, h); g2d.draw(r); } } } } /** a specific square painting **/ public class SquareRect extends Rect { /** sets preferred dims based on {@link #SIZE} **/ public SquareRect() { super(SIZE*2, SIZE*2); } /** *

Draws some random points and dashed line segments.

**/ public void paint2D(Graphics2D g2d) { int w = getWidth(), h = getHeight(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //draw random dashed lines Line2D.Float l = new Line2D.Float(); for (int i = 0; i < 100; i++) { g2d.setStroke(new BasicStroke(rndf(0.0, 8.0), //width BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, //miter limit new float[] {rndf(16.0, 64.0), //on rndf(16.0, 64.0)}, //off 0.0f)); //dash phase g2d.setColor(rndColor()); l.setLine(rndi(0, w), rndi(0, h), //start rndi(0, w), rndi(0, h)); //end g2d.draw(l); } //draw random points g2d.setStroke(new BasicStroke(1.0f)); int x, y; for (int i = 0; i < 100; i++) { g2d.setStroke(new BasicStroke(rndf(0.0, 32.0), //width BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2d.setColor(rndColor()); x = rndi(0, w); y = rndi(0, h); l.setLine(x, y, x, y); //one not very efficient way to draw a point g2d.draw(l); } } } /** *

Generate a random int in the interval [from,to).

**/ public static int rndi(int from, int to) { return from+(int)Math.floor(random.nextDouble()*(double)(to-from)); } /** *

Generate a random float in the interval [from,to).

**/ public static float rndf(double from, double to) { return (float)(from+random.nextDouble()*(to-from)); } /** *

Generate a random color.

**/ public static Color rndColor() { return new Color(rndi(0, 256), rndi(0, 256), rndi(0, 256)); } /** *

Constructor makes and packs the top-level JFrame.

* * @param arrangement "A" or "B", case insensitive, to set the arrangement of * rects **/ public HW1_Sample(String arrangement) { JFrame frame = new JFrame("HW1 Sample"); //shows in frame title bar //make the program exit when the window close button is clicked frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container c = frame.getContentPane(); //add rects in the specified arrangement if ("A".equals(arrangement.toUpperCase())) { System.out.println("using arrangement A"); addCanvasesA(c); } else if ("B".equals(arrangement.toUpperCase())) { System.out.println("using arrangement B"); addCanvasesB(c); } else { System.err.println("error: unknown arrangment \""+arrangement+"\""); System.exit(1); } //shrink-wrap the frame around the rects at their preferred sizes frame.pack(); //make the frame visible frame.setVisible(true); } /** *

Layout rects in arrangement A.

**/ public void addCanvasesA(Container c) { c.add(new LongRectA(), BorderLayout.NORTH); c.add(new LongRectB(), BorderLayout.SOUTH); c.add(new TallRectA(), BorderLayout.WEST); c.add(new TallRectB(), BorderLayout.EAST); c.add(new SquareRect(), BorderLayout.CENTER); } /** *

Layout rects in arrangement B.

**/ public void addCanvasesB(Container c) { c.add(new LongRectB(), BorderLayout.NORTH); c.add(new LongRectA(), BorderLayout.SOUTH); c.add(new TallRectB(), BorderLayout.WEST); c.add(new TallRectA(), BorderLayout.EAST); c.add(new SquareRect(), BorderLayout.CENTER); } /** Constructs a new {@link HW1_Sample} **/ public static void main(final String[] arg) { //since we'll be changing swing layout, do all the work inside the AWT //event thread SwingUtilities.invokeLater( new Runnable() { public void run() { new HW1_Sample((arg.length > 0) ? arg[0] : "A"); } } ); } }