Computer Science 252
Problem Solving with Java
Fall 2013, The College of Saint Rose
NestedSquaresSizes Demo
A working demo of NestedSquaresSizes will appear below. Click inside the applet to interact with it.
NestedSquaresSizes BlueJ Project
Click here to download a BlueJ project for NestedSquaresSizes.
NestedSquaresSizes Source Code
The Java source code for NestedSquaresSizes is below. Click on a file name to download it.
import objectdraw.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Random; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.JPanel; /* * Example NestedSquaresSizes: draw nested squares objects * of various sizes, drag them around, and * * Jim Teresco, The College of Saint Rose, CSC 252, Fall 2013 * * $Id: NestedSquaresSizes.java 2230 2013-10-27 02:26:10Z terescoj $ */ public class NestedSquaresSizes extends WindowController implements ActionListener { // minimum and maximum sizes for our objects private static final int MIN_SIZE = 25; private static final int MAX_SIZE = 200; // standard dragging stuff private NestedSquares newestSquares; private boolean dragging; private Location lastMouse; // a slider to determine the size of the next box to // create private JSlider nextBoxSize; // a "set color" and "get info" button // used to modify or report on the newest // NestedSquares object in existence private JButton setColor, getInfo; // a label where the "info" will be reported private JLabel infoLabel; // we'll need some random numbers too private Random r = new Random(); public void begin() { setSize(500, 600); // get the content pane to which we can add items Container contentPane = getContentPane(); // we'll put our buttons and slider into a panel // at the bottom of the window JPanel southPanel = new JPanel(); // our buttons setColor = new JButton("Random Color"); southPanel.add(setColor); setColor.addActionListener(this); getInfo = new JButton("Get Info"); southPanel.add(getInfo); getInfo.addActionListener(this); // a slider to control sizes nextBoxSize = new JSlider(JSlider.HORIZONTAL, MIN_SIZE, MAX_SIZE, (MIN_SIZE + MAX_SIZE)/2); // with some labels for end amounts? southPanel.add(new JLabel(""+MIN_SIZE)); southPanel.add(nextBoxSize); southPanel.add(new JLabel(""+MAX_SIZE)); // add our panel in the south contentPane.add(southPanel, BorderLayout.SOUTH); // create a Label for information infoLabel = new JLabel("Info will appear here when you click \"Get Info\""); contentPane.add(infoLabel, BorderLayout.NORTH); contentPane.validate(); } public void onMousePress(Location point) { if (newestSquares != null && newestSquares.contains(point)) { dragging = true; lastMouse = point; } else { newestSquares = new NestedSquares(point.getX(), point.getY(), nextBoxSize.getValue(), canvas); } } public void onMouseDrag(Location point) { if (dragging) { newestSquares.move(point.getX() - lastMouse.getX(), point.getY() - lastMouse.getY()); lastMouse = point; } } public void onMouseRelease(Location point) { dragging = false; } // event handler to react to our buttons public void actionPerformed(ActionEvent e) { if (e.getSource() == getInfo) { // it's the get info button if (newestSquares != null) { int numLevels = newestSquares.squareCount(); double totalPerimeter = newestSquares.totalPerimeter(); infoLabel.setText("Newest has " + numLevels + " squares, total perimeter: " + totalPerimeter); } else { infoLabel.setText("Please create a nested squares first!"); } } else { // must be the setColor button if (newestSquares != null) { Color c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)); newestSquares.setColor(c); } } } }
import objectdraw.*; import java.awt.*; /* * Example NestedSquares: a recursive implementation of an object * consisting of nested squares, complete with contains and move * methods to support dragging. * * Jim Teresco, The College of Saint Rose, CSC 252, Fall 2013 * * $Id: NestedSquares.java 2230 2013-10-27 02:26:10Z terescoj $ */ public class NestedSquares { private static final int SIZE_CHANGE = 4; // instance variables to keep track of the outermost // square and then NestedSquares inside private FramedRect outline; private NestedSquares rest; // a recursive implementation: we draw nested squares // by creating the outermost square, then calling // THIS CONSTRUCTOR to draw the rest, which are really // just another set of nested squares, just a little bit // smaller and a little bit down and to the right. public NestedSquares(double x, double y, int size, DrawingCanvas c) { // draw one outline = new FramedRect(x, y, size, size, c); // draw more only if there are more to draw, otherwise // we remember rest as null (so we know the recursion // is over) -- if size is not greater than SIZE_CHANGE, // the next level would not exist, so we don't try to // draw it if (size > SIZE_CHANGE) { // draw the rest rest = new NestedSquares(x + SIZE_CHANGE/2, y+SIZE_CHANGE/2, size - SIZE_CHANGE, c); } else { // this will flag the end of the recursion rest = null; } } // contains is easy - we just check containment of the outline public boolean contains(Location point) { return outline.contains(point); } // move method will need to be recursive: we move the whole thing // by moving the outline, then moving the rest (using this method!) public void move(double dx, double dy) { outline.move(dx, dy); if (rest != null) { rest.move(dx, dy); } } // we will also be able to set the color public void setColor(Color c) { // we achieve this recursively outline.setColor(c); if (rest != null) { rest.setColor(c); } } // a recursive accessor method to count the number of nested squares public int squareCount() { // if this is the innermost, we have just the 1 if (rest == null) return 1; // otherwise we have the one (the outline) plus whatever // number is in the rest return 1 + rest.squareCount(); } // also compute the total perimeter of all of the nested squares public double totalPerimeter() { // first, compute the perimeter of the outermost square double outlinePerim = 4 * outline.getWidth(); // again, if this is the innermost, we have just this one to consider if (rest == null) return outlinePerim; // otherwise, we have this one plus the smaller ones inside of rest return outlinePerim + rest.totalPerimeter(); } }