16.8. (Optional) Case Study: Bouncing Ball |
This section presents an applet that displays a ball bouncing in a panel. Use two buttons to suspend and resume the movement, and use a scroll bar to control the bouncing speed, as shown in Figure 16.13.
Here are the major steps to complete this example.
1. | Create a subclass of JPanel named Ball to display a ball bouncing, as shown in Listing 16.8. |
2. | Create a subclass of JPanel named BallControl to contain the ball with a scroll bar and two control buttons Suspend and Resume , as shown in Listing 16.9. |
3. | Create an applet named BounceBallApp to contain an instance of BallControl and enable the applet to run standalone, as shown in Listing 16.10. |
The relationship among these classes is shown in Figure 16.14.
1 import javax.swing.Timer; 2 import java.awt.*; 3 import javax.swing.*; 4 import java.awt.event.*; 5 6 public class Ball extends JPanel { 7 private int delay = 10 ; 8 9 // Create a timer with delay 1000 ms 10 protected Timer timer = new Timer(delay, new TimerListener()); 11 12 private int x = ; private int y = ; // Current ball position 13 private int radius = 5 ; // Ball radius 14 private int dx = 2 ; // Increment on ball's x-coordinate 15 private int dy = 2 ; // Increment on ball's y-coordinate 16 17 public Ball() { 18 timer.start(); 19 } 20 21 private class TimerListener implements ActionListener { 22 /** Handle the action event */ 23 public void actionPerformed(ActionEvent e) { 24 repaint(); 25 } 26 } 27 28 protected void paintComponent(Graphics g) { 29 super .paintComponent(g); 30 31 g.setColor(Color.red); 32 33 // Check boundaries 34 if (x < radius) dx = Math.abs(dx); 35 if (x > getWidth() - radius) dx = -Math.abs(dx); 36 if (y < radius) dy = Math.abs(dy); 37 if (y > getHeight() - radius) dy = -Math.abs(dy); 38 39 // Adjust ball position 40 x += dx; 41 y += dy; 42 g.fillOval(x - radius, y - radius, radius * 2 , radius * 2 ); 43 } 44 45 public void suspend() { 46 timer.stop(); // Suspend timer 47 } 48 49 public void resume() { 50 timer.start(); // Resume timer 51 } 52 53 public void setDelay( int delay) { 54 this .delay = delay; 55 timer.setDelay(delay); 56 } 57 } |
Using Timer to control animation was introduced in §14.6, "Animation Using the Timer Class." Ball extends JPanel to display a moving ball. The timer listener implements ActionListener to listen for ActionEvent (line 21). Line 10 creates a Timer for a Ball . The timer is started in line 18 when a Ball is constructed . The timer fires an ActionEvent at a fixed rate. The listener responds in line 24 to repaint the ball to animate ball movement. The center of the ball is at ( x , y ), which changes to ( x + dx , y + dy ) on the next display. The suspend and resume methods (lines 45 “51) can be used to stop and start the timer. The setDelay(int) method (lines 53 “56) sets a new delay.
1 import javax.swing.*; 2 import java.awt.event.*; 3 import java.awt.*; 4 5 public class BallControl extends JPanel { 6 private Ball ball = new Ball(); 7 private JButton jbtSuspend = new JButton( "Suspend" ); 8 private JButton jbtResume = new JButton( "Resume" ); 9 private JScrollBar jsbDelay = new JScrollBar(); 10 11 public BallControl() { 12 // Group buttons in a panel 13 JPanel panel = new JPanel(); 14 panel.add(jbtSuspend); 15 panel.add(jbtResume); 16 17 // Add ball and buttons to the panel 18 ball.setBorder( new javax.swing.border.LineBorder(Color.red)); 19 jsbDelay.setOrientation(JScrollBar.HORIZONTAL); 20 ball.setDelay(jsbDelay.getMaximum()); 21 setLayout( new BorderLayout()); 22 add(jsbDelay, BorderLayout.NORTH); 23 add(ball, BorderLayout.CENTER); 24 add(panel, BorderLayout.SOUTH); 25 26 // Register listeners 27 jbtSuspend.addActionListener( new ActionListener() { 28 public void actionPerformed(ActionEvent e) { 29 ball.suspend(); 30 } 31 }); 32 jbtResume.addActionListener( new ActionListener() { 33 public void actionPerformed(ActionEvent e) { 34 ball.resume(); 35 } 36 }); 37 jsbDelay.addAdjustmentListener( new AdjustmentListener() { 38 public void adjustmentValueChanged(AdjustmentEvent e) { 39 ball.setDelay(jsbDelay.getMaximum() - e.getValue()); 40 } 41 }); 42 } 43 } |
The BallControl class extends JPanel to display the ball with a scroll bar and two control buttons. When the Suspend button is clicked, the ball's suspend() method is invoked to suspend the ball movement (line 29). When the Resume button is clicked, the ball's resume() method is invoked to resume the ball movement (line 34). The bouncing speed can be changed using the scroll bar.
1 import java.awt.*; 2 import java.awt.event.*; 3 import java.applet.*; 4 import javax.swing.*; 5 6 public class BounceBallApp extends JApplet { 7 public BounceBallApp() { 8 add( new BallControl()); 9 } 10 } |
The BounceBallApp class simply places an instance of BallControl in the applet. The main method is provided in the applet (not displayed in the listing for brevity) so that you can also run it standalone.