scala/ScalaBook/chapter-07/animation.scala

import scala.swing._
import event._
import java.awt._

class BouncingBall extends Applet {
  object ui extends UI with Reactor with Runnable {    
    private var ballThread : Thread       = null
    private var offscreenImage : Image    = null
    private var offscreenGraph : Graphics = null
    private var appletDim : Dimension     = null
    private var appletInsets : Insets     = null
    private var xCoord                    = 20 
    private var yCoord                    = 30
    private var ballWidth                 = 30 
    private var ballHeight                = 30
    private var xReverse                  = false 
    private var yReverse                  = false
    private var lock                      = new AnyRef
    private var canvas : scala.swing.Panel= null
 
    override def init() = {
      canvas = new scala.swing.Panel {
        opaque = false
        override def paintComponent(g: java.awt.Graphics) {
          //Clear the offscreen graphics context  
          offscreenGraph.setColor(getBackground()) 
          offscreenGraph.fillRect(0,0,appletDim.width,appletDim.height)
            
          //Draw on the offscreen graphics context  
          offscreenGraph.setColor(Color.blue) 
          offscreenGraph.fillOval(xCoord,yCoord,ballWidth,ballHeight)
               
          //Draw the offscreen image to the visible graphics context  
          g.drawImage(offscreenImage,0,0,null)
          lock.synchronized {
            lock.notifyAll
          }
        }       
      } // canvas
      contents = canvas
      if (getBackground().equals(Color.white)) 
        setBackground(Color.lightGray)
      appletDim = getSize()
      appletInsets = getInsets()
      // Create the offscreen image and graphics context 
      offscreenImage = createImage(appletDim.width,appletDim.height)
      offscreenGraph = offscreenImage.getGraphics()
    }

    override def start() = {
       if (ballThread == null) {
         // Start the animation thread 
         ballThread = new Thread(this)
         ballThread.start()
       }
    }  

    override def stop() = {
      //Stop the animation thread */
      if (ballThread != null)
        ballThread = null
    }

    override def run(): Unit = 
      lock.synchronized {
         while(ballThread != null) {
           if (!xReverse) {
             xCoord += 1
             if ( (xCoord + ballWidth) >= 
                  (appletDim.width - appletInsets.left))
               xReverse = true
           }
           else {
             xCoord -= 1
             if ( xCoord <= appletInsets.right )
               xReverse = false
           }
           if ( !yReverse ) {
              yCoord += 1
              if ( (yCoord + ballHeight) >= 
                   (appletDim.height - appletInsets.bottom))
                 yReverse = true
           }
           else {
             yCoord -= 1
             if ( yCoord <= appletInsets.top )
               yReverse = false
           }
           canvas.repaint
           try { 
             lock.wait 
             Thread.sleep(10) 
           } catch {                                              
               case ex : InterruptedException => 
           }                                    
         } // while
      } //lock.synchronized
  } // ui
} // BouncingBall