import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.event.*;
import geometri.*;
import java.util.*;
/**
* A small animation of constructing different geometrical forms,
* where color and postion are random.
* Thereafter it is possible to move all forms to the upper
* left corner of the drawing area, i.e. moving them
* pixel by pixel to origo. All forms are drawn in order of
* their size, with the biggest form first and smallest last.
*
* Point have been increased to 2 pixels in diameter
* and leaves a trace on its way to origo.
* When a Point is choosen, each second time it become black,
* which will be checked in a HashSet,
* in order to test the methods of equals and
* hashCode.
*
* @author (Bror Bjerner/Christer Carlsson)
* @version (nov 2014)
*/
public class MoveToUpperLeftCorner
extends JFrame
implements ActionListener {
// Forms that are choosen, ThickPoint and BigFirst further down in this file
private List points = new LinkedList();
private Set pointSet = new HashSet();
private List tracePoints = new LinkedList();
private SortedSet forms = new TreeSet(new BigFirst());
private boolean nextBlack = false;
// Buttons for each form that can be choosen, a button to start the moving and a
// button to restart the whole animation
private JButton point = new JButton("Thick point");
private JButton line = new JButton("Line");
private JButton square = new JButton("Square");
private JButton rectangle = new JButton("Rectangle");
private JButton circle = new JButton("Circle");
private JButton oval = new JButton("Oval");
private JButton startMove = new JButton("Start moving");
private JButton restart = new JButton("Restart");
// Create a new drawing area. Class DrawingArea defined further down in this file.
// Must be an instance field, since it contains a Timer.
private DrawingArea drawingArea = new DrawingArea();
/**
* The whole basic picture is constructed in the constructor.
*/
public MoveToUpperLeftCorner() {
// Make all listeners active.
point.addActionListener(this);
line.addActionListener(this);
square.addActionListener(this);
rectangle.addActionListener(this);
circle.addActionListener(this);
oval.addActionListener(this);
startMove.addActionListener(this);
restart.addActionListener(this);
// Colour the buttons
point.setBackground( Color.yellow );
line.setBackground( Color.yellow );
square.setBackground( Color.yellow );
rectangle.setBackground( Color.yellow );
circle.setBackground( Color.yellow );
oval.setBackground( Color.yellow );
startMove.setBackground( Color.magenta );
restart.setBackground( Color.orange );
// Place the buttons
JPanel buttons = new JPanel();
buttons.add( point );
buttons.add( line );
buttons.add( square );
buttons.add( rectangle );
buttons.add( circle );
buttons.add( oval );
buttons.add( startMove );
buttons.add( restart );
// Place buttons and drawingArea into the frame
Container content = getContentPane();
content.add( drawingArea, BorderLayout.CENTER );
content.add( buttons, BorderLayout.SOUTH );
setSize(760,780);
/* Use this if you want to check vertical and horisontal lines
try { Use this to check
forms.add( new Line( 10, 10, 10, 60, new Color(50,75,200)));
forms.add( new Line( 20, 20, 60, 20, new Color(50,200,100)));
}
catch ( IllegalPositionException ipe ) {
System.out.println("Something is rotten in Denmark.");
}
*/
// Fix the frames close button
setDefaultCloseOperation( EXIT_ON_CLOSE );
// Show the frame at start.
setVisible(true);
} // contructor MoveToUpperLeftCorner
/**
* All actions performed when a button is pressed.
*/
public void actionPerformed(ActionEvent e) {
// Coordinates and colour are choosed at random.
int x = (int)Math.round( Math.random()*600);
int y = (int)Math.round( Math.random()*600);
Color c = new Color( (int)Math.round(Math.random()*255),
(int)Math.round(Math.random()*255),
(int)Math.round(Math.random()*255) );
try { if ( e.getSource() == point ) {
ThickPoint p;
if (nextBlack)
p = new ThickPoint( x, y, new Color(0,0,0));
else
p = new ThickPoint( x, y, c );
nextBlack = ! nextBlack;
if ( pointSet.contains( p ) )
JOptionPane.showMessageDialog( this, "Point with this colour already exists, try again." );
else {
pointSet.add(p); // just in order to check hashCode !!
points.add( p );
tracePoints.add( new TracePoint(p, p.getColor()) );
JOptionPane.showMessageDialog( this, "A new random thick point is created" );
}
}
else if ( e.getSource() == line ) {
if ( forms.add( new Line( x,
y,
(int)Math.round( Math.random()*720),
(int)Math.round( Math.random()*720),
c )) )
JOptionPane.showMessageDialog( this, "A new random line is created." );
else
JOptionPane.showMessageDialog( this, "Line: Form with this size already exists, try again" );
}
else if ( e.getSource() == square ) {
int length = Integer.parseInt(
JOptionPane.showInputDialog("Choose side length (1-500):"));
if ( ! forms.add( new Square( x, y, length, c )) )
JOptionPane.showMessageDialog( this, "Square: Form with this size already exists, try again" );
}
else if ( e.getSource() == rectangle ) {
int width = Integer.parseInt(
JOptionPane.showInputDialog("Choose width (1-500)"));
int heigth = Integer.parseInt(
JOptionPane.showInputDialog("Choose heigth (1-500)"));
if ( ! forms.add( new Rectangle( x, y, width, heigth, c )) )
JOptionPane.showMessageDialog( this, "Rectangle: Form with this size already exists, try again" );
}
else if ( e.getSource() == circle ) {
int diameter = Integer.parseInt(
JOptionPane.showInputDialog("Choose diameter (1-500)"));
if ( ! forms.add( new Circle( x, y, diameter, c ) ) )
JOptionPane.showMessageDialog( this, "Circle: Form with this size already exists, try again" );
}
else if ( e.getSource() == oval ) {
int width = Integer.parseInt(
JOptionPane.showInputDialog("Choose width (1-500)"));
int heigth = Integer.parseInt(
JOptionPane.showInputDialog("Choose heigth (1-500)"));
if ( ! forms.add( new Oval( x, y, width, heigth, c )) )
JOptionPane.showMessageDialog( this, "Oval: Form with this size already exists, try again" );
}
else if ( e.getSource() == startMove ) {
// Start the timer of the drawing area
drawingArea.start();
}
else if ( e.getSource() == restart ) {
// Remove all geometrical forms from the drawing area
points.clear();
pointSet.clear();
forms.clear();
tracePoints.clear();
}
}
catch( IllegalPositionException ipe ) {
JOptionPane.showMessageDialog(
this, "Illegal position, try again.");
}
catch( NumberFormatException nfe ) {
JOptionPane.showMessageDialog(
this, "Only positive integers allowed, try again.");
}
repaint();
} // actionPerformed
// Move the position one pixle closer to origo, both x and y coordinates.
// The boolean value returned indicates if the position has changed,
// i.e. if the position differed from (0,0) !!
private boolean moveForm( GeometricalForm f ) {
int x = f.getX();
int y = f.getY();
if ( x == 0 && y == 0 )
return false;
else
try { f.place( Math.max( x-1, 0 ), Math.max( y-1, 0 ));
}
catch( IllegalPositionException ipe ) {} // Can not happen !!
return true;
} // moveForm
// make a drawing area containg a timer, which is used to move
// all forms i the drawing arean is moved step by step to origo.
private class DrawingArea extends JPanel
implements ActionListener {
// private List tracePoints = new LinkedList();
private boolean notInPlace;
private javax.swing.Timer tim = new javax.swing.Timer( 20, this);
public DrawingArea() {
setSize(700,700);
setBackground( Color.white );
} // kostruktor DrawingArea
public void start() {
notInPlace = true;
for ( ThickPoint p : points )
tracePoints.add( new TracePoint(p,p.getColor()) );
tim.start();
} // start
public void stop() {
tracePoints.clear();
tim.stop();
} // stop
public void paint( Graphics g ) {
super.paint(g);
for( GeometricalForm f : forms )
f.fill(g);
for( ThickPoint p : points )
p.fill(g);
for( TracePoint p : tracePoints )
p.fill(g);
} // paint
public void actionPerformed(ActionEvent ae) {
if ( notInPlace ) {
notInPlace = false;
for ( ThickPoint p : points )
if ( moveForm( p ) )
notInPlace = true;
for ( ThickPoint p : points )
tracePoints.add( new TracePoint(p,p.getColor()) );
for ( GeometricalForm f : forms )
if ( moveForm( f ) )
notInPlace = true;
repaint();
}
else
stop();
}
} // class DrawingArea
// A comparator who change the order in the sorted set of
// geometrical forms, i.e. den biggest form
// first and the smallest form last.
private class BigFirst implements Comparator {
public int compare( GeometricalForm f1,
GeometricalForm f2 ) {
return f2.compareTo( f1 );
}
}
/**
* Start the animation.
*/
public static void main( String[] args ) {
new MoveToUpperLeftCorner();
}
} // class MoveToUpperLeftCorner
// In order to make points more visible in the drawing area
class ThickPoint extends Point {
public ThickPoint( int x, int y, Color c )
throws IllegalPositionException {
super( x, y, c);
} // constructor Point
public ThickPoint( Point p, Color c ) {
super( p, c);
} // constructor Point
// Dubbles the thickness of the point.
public void fill( Graphics g ) {
g.setColor( getColor() );
g.fillOval( getX(), getY(), 4, 4);
} // fill
} // class ThickPoint
// In order to show the trace of the points in the drawing area
class TracePoint extends Point {
public TracePoint( int x, int y, Color c )
throws IllegalPositionException {
super( x, y, c);
} // constructor Point
public TracePoint( Point p, Color c ) {
super( p, c);
} // constructor Point
// Dubbles the thickness of the point.
public void fill( Graphics g ) {
g.setColor( getColor() );
g.fillOval( getX(), getY(), 2, 2);
} // fill
} // class TracePoint