Source of BounceThread.java


  1: /**
  2:    @version 1.32 2004-07-27
  3:    @author Cay Horstmann
  4: */
  5: 
  6: import java.awt.*;
  7: import java.awt.event.*;
  8: import java.awt.geom.*;
  9: import java.util.*;
 10: import javax.swing.*;
 11: 
 12: /**
 13:    Shows an animated bouncing ball.
 14: */
 15: public class BounceThread
 16: {
 17:    public static void main(String[] args)
 18:    {
 19:       JFrame frame = new BounceFrame();
 20:       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 21:       frame.setVisible(true);
 22:    }
 23: }
 24: 
 25: /**
 26:    A runnable that animates a bouncing ball.
 27: */
 28: class BallRunnable implements Runnable
 29: {
 30:    /**
 31:       Constructs the runnable.
 32:       @aBall the ball to bounce
 33:       @aPanel the component in which the ball bounces
 34:    */
 35:    public BallRunnable(Ball aBall, Component aComponent) 
 36:    { 
 37:       ball = aBall; 
 38:       component = aComponent;
 39:    }
 40: 
 41:    public void run()
 42:    {
 43:       try
 44:       {
 45:          for (int i = 1; i <= STEPS; i++)
 46:          {
 47:             ball.move(component.getBounds());
 48:             component.repaint();
 49:             Thread.sleep(DELAY);
 50:          }
 51:       }
 52:       catch (InterruptedException e)
 53:       {                    
 54:       }
 55:    }
 56: 
 57:    private Ball ball;
 58:    private Component component;
 59:    public static final int STEPS = 1000;
 60:    public static final int DELAY = 5;
 61: }
 62: 
 63: /**
 64:    A ball that moves and bounces off the edges of a 
 65:    rectangle
 66: */
 67: class Ball
 68: {
 69:    /**
 70:       Moves the ball to the next position, reversing direction
 71:       if it hits one of the edges
 72:    */
 73:    public void move(Rectangle2D bounds)
 74:    {
 75:       x += dx;
 76:       y += dy;
 77:       if (x < bounds.getMinX())
 78:       { 
 79:          x = bounds.getMinX();
 80:          dx = -dx;
 81:       }
 82:       if (x + XSIZE >= bounds.getMaxX())
 83:       {
 84:          x = bounds.getMaxX() - XSIZE; 
 85:          dx = -dx; 
 86:       }
 87:       if (y < bounds.getMinY())
 88:       {
 89:          y = bounds.getMinY(); 
 90:          dy = -dy;
 91:       }
 92:       if (y + YSIZE >= bounds.getMaxY())
 93:       {
 94:          y = bounds.getMaxY() - YSIZE;
 95:          dy = -dy; 
 96:       }
 97:    }
 98: 
 99:    /**
100:       Gets the shape of the ball at its current position.
101:    */
102:    public Ellipse2D getShape()
103:    {
104:       return new Ellipse2D.Double(x, y, XSIZE, YSIZE);
105:    }
106: 
107:    private static final int XSIZE = 15;
108:    private static final int YSIZE = 15;
109:    private double x = 0;
110:    private double y = 0;
111:    private double dx = 1;
112:    private double dy = 1;
113: }
114: 
115: /**
116:    The panel that draws the balls.
117: */
118: class BallPanel extends JPanel
119: {
120:    /**
121:       Add a ball to the panel.
122:       @param b the ball to add
123:    */
124:    public void add(Ball b)
125:    {
126:       balls.add(b);
127:    }
128: 
129:    public void paintComponent(Graphics g)
130:    {
131:       super.paintComponent(g);
132:       Graphics2D g2 = (Graphics2D) g;
133:       for (Ball b : balls)
134:       {
135:          g2.fill(b.getShape());
136:       }
137:    }
138: 
139:    private ArrayList<Ball> balls = new ArrayList<Ball>();
140: }
141: 
142: /**
143:    The frame with panel and buttons.
144: */
145: class BounceFrame extends JFrame
146: {
147:    /**
148:       Constructs the frame with the panel for showing the
149:       bouncing ball and Start and Close buttons
150:    */
151:    public BounceFrame()
152:    {
153:       setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
154:       setTitle("BounceThread");
155: 
156:       panel = new BallPanel();
157:       add(panel, BorderLayout.CENTER);
158:       JPanel buttonPanel = new JPanel();
159:       addButton(buttonPanel, "Start",
160:          new ActionListener()
161:          {  
162:             public void actionPerformed(ActionEvent event)
163:             {
164:                addBall();
165:             }
166:          });
167:       
168:       addButton(buttonPanel, "Close",
169:          new ActionListener()
170:          {
171:             public void actionPerformed(ActionEvent event)
172:             {
173:                System.exit(0);
174:             }
175:          });
176:       add(buttonPanel, BorderLayout.SOUTH);
177:    }
178: 
179:    /**
180:       Adds a button to a container.
181:       @param c the container
182:       @param title the button title
183:       @param listener the action listener for the button
184:    */
185:    public void addButton(Container c, String title, ActionListener listener)
186:    {
187:       JButton button = new JButton(title);
188:       c.add(button);
189:       button.addActionListener(listener);
190:    }
191: 
192:    /**
193:       Adds a bouncing ball to the canvas and starts a thread
194:       to make it bounce
195:    */
196:    public void addBall()
197:    {
198:       Ball b = new Ball();
199:       panel.add(b);
200:       Runnable r = new BallRunnable(b, panel);
201:       Thread t = new Thread(r);
202:       t.start();
203:    }
204: 
205:    private BallPanel panel;
206:    public static final int DEFAULT_WIDTH = 450;
207:    public static final int DEFAULT_HEIGHT = 350;  
208:    public static final int STEPS = 1000;
209:    public static final int DELAY = 3;
210: }
211: 
212: 
213: 
214: 
215: 
216: 
217: 
218: 
219: 
220: 
221: 
222: 
223: 
224: 
225: 
226: 
227: