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();
}
}