| This applet demonstrates a simple animation of a dropped ball. 
              A subclass of JPanel 
              called DropPanel 
              calculates the position of the ball for each increment in frame 
              time and redraws it. The Runnable 
              applet creates a thread that invokes the run() 
              method in the applet. The run() 
              holds a loop that tells the DropPanel 
              to update the ball position and redraw itself. Then the loop pauses 
              for 25 milliseconds using the static sleep() 
              method in the Thread 
              class.  The applet builds a basic interface to hold the DropPanel 
              and a button to initiate a drop. Note how the button is disabled 
              during the drop.   
              
                 
                  | DropApplet.java 
                      + DropPanel.java
 |   
                  | import 
                    javax.swing.*; import java.awt.*;
 import java.awt.event.*;
 
 /**
 * This applet implements Runnable and uses a thread
 * to create a simple dropped ball demonstration.
 **/
 public class DropApplet extends JApplet
 implements 
                    Runnable, ActionListener{
 // Will use thread reference as a flag
 Thread fThread = null;
 DropPanel fDropPanel = null;
 JButton fDropButton = null;
 
 /** Constructor builds the interface. **/
 public void init () {
 Container content_pane = getContentPane 
                    ();
 content_pane.setLayout (new BorderLayout 
                    ());
 
 // Create an instance of DropPanel
 fDropPanel = new DropPanel ();
 
 // Add the DropPanel to the content 
                    pane.
 content_pane.add ("Center",fDropPanel);
 
 // Create a button and add it
 fDropButton = new JButton ("Drop");
 fDropButton.addActionListener (this);
 content_pane.add ("South",fDropButton);
 
 } // init
 
 /** Start when browser is loaded or button pushed. 
                    **/
 public void start () {
 // If the thread reference not null 
                    then a
 // thread is already running. Otherwise, 
                    create
 // a thread and start it.
 if (fThread == null){
 fThread = 
                    new Thread (this);
 fThread.start 
                    ();
 }
 } // start
 
 /** Applet's stop method used to stop thread.**/
 public void stop () {
 // Setting thread to null will cause 
                    loop in
 // run () to finish and kill the 
                    thread.
 fThread = null;
 } // stop
 
 /** Button command. **/
 public void actionPerformed (ActionEvent ae){
 if (fDropPanel.isDone ()) start ();
 }
 
 /** The thread loops to draw each frame of drop.**/
 public void run () {
 // Disable button during drop
 fDropButton.setEnabled (false);
 
 // Initialize the ball for the drop.
 fDropPanel.reset ();
 
 // Loop through animation frames
 while ( fThread != null){
 // Sleep 25msecs between 
                    frames
 try{ Thread.sleep (25);
 } catch  (InterruptedException 
                    e) { }
 // Repaint drop panel 
                    for each new frame
 fDropPanel.repaint ();
 if ( fDropPanel.isDone 
                    ()) fThread = null;
 }
 // Enable button for another drop
 fDropButton.setEnabled (true);
 } /// run
 
 } // class DropApplet
 |   
                  | import 
                      javax.swing.*;import java.awt.*;
 
 /** This JPanel subclass animates the dropping of a ball.**/
 public class DropPanel extends JPanel {
 
 // Parameters for the drop
 double fY = 0.0, fVy = 0.0, fYConvert = 0.0;
 int fXPixel = 0, fYPixel = 0, fRadius = 0, fDiam 
                      = 0;
 // Flag for drop status
 boolean fDropDone = false;
 // starting point for ball in cm
 double fY0 = 1000.0;
 // Frame dimensions.
 int fFrameHt = 100, fFrameWd = 100;
 
 // Reset parameters for a new drop
 void reset () {
 
 fFrameHt = getHeight ();
 fFrameWd = getWidth ();
 
 fXPixel = getWidth ()/2;
 fY = fY0; fVy = 0;
 
 // Conversion factor from cm to 
                      pixels
 // Start the ball about 20% from 
                      the top
 // of the frame
 fYConvert = fFrameHt /  (1.2 
                      * fY0);
 
 // Choose a size for the ball relative
 fRadius =  (int) (  (0.1 
                      * fY0) * fYConvert);
 fDiam = 2 * fRadius;
 
 setBackground (Color.WHITE);
 
 fDropDone=false;
 
 } // reset
 
 /** Draw the ball at its current position. **/
 public void paintComponent  (Graphics 
                      g){
 super.paintComponent (g);
 
 // Clip so no part of the ball is 
                      drawn
 // outside of the frame.
 g.setClip  (0, 0, fFrameWd-1, 
                      fFrameHt-1);
 
 // Determine position after this 
                      time increement
 calcPosition  ();
 g.setColor  (Color.RED);
 
 // Now draw a solid color circle.
 g.fillOval  (fXPixel-fRadius,fYPixel-fRadius,fDiam,fDiam);
 }
 
 void calcPosition  () {
 // Increment by 25 millseconds per 
                      frame
 double dt = 0.025;
 
 // Calculate position and velocity 
                      at each step
 fY = fY + fVy * dt - 490.* dt * 
                      dt;
 fVy = fVy  -  980.0 
                      * dt;
 
 // Convert to the pixel coordinates
 fYPixel = fFrameHt -  (int) 
                      (fY * fYConvert);
 
 // Reverse direction when ball hits 
                      bottom.
 if ((fYPixel + fRadius) >=  (fFrameHt-1)) 
                      {
 fVy = Math.abs  (fVy);
 // Subtract 
                      friction loss
 fVy -= 
                      0.1*fVy;
 // Stop 
                      when speed at bottom drops below arbitrary limit
 if  (fVy 
                      < 15.0) {
 fDropDone=true;
 }
 }
 } // clacPosition
 
 /** Provide a flag on drop status. **/
 public boolean isDone  () {
 return fDropDone;
 }
 
 } // class DropPanel
 |    See the Java 2D version of this applet in the Chapter 
                8: Supplements section. 
   Latest update April 29, 2004 |