Java Ball World and Cannon Game Examples

These notes cover a bit of additional material from Chapters 5 and 6 of the text Understanding Object-Oriented Programming with Java, beyond what was in the slides.

Output: pass a Graphics object to a paint method or other drawing method. See the class Graphics for lots of useful methods. (This is very similar to the way Smalltalk handles graphical output.)

Frame: a top-level window with a title and a border. Examples of use: BallWorld, MultiBallWorld in Chapter 5; CannonGame and CannonWorld in Chapter 6. These are all subclasses of Frame.

Miscellaneous stuff to note: use of static (class) messages in System.exit(0), Math.sin(radianAngle), Color.red, Integer.valueOf(str)

Input: event model. Most modern window managers, including Java's, use an event model.

Historical comparison: mouse handling on the Xerox Alto. There were methods available to the programmer to query the current state of the mouse (position, buttons up or down). Problems: need to do polling, which makes it more difficult to write systems that support multiple concurrent activities; mouse button state and mouse position sampled at slightly different times.

In Java, we add various input widgets to the frame -- for example, a scrollbar and a "fire" button in CannonWorld. A layout manager positions these within the frame. The Java runtime takes care of distributing the events to the appropriate widget.

However, we need to supply code that is to be run when the button is pushed or the scrollbar is adjusted. This is done by supplying an implementation of ActionListener or AdjustmentListener respectively.

The listeners in the CannonWorld are activated only when the user presses a button or finishes moving a slider. There are also listeners (for example MouseMotionListener) that support actions such as dragging.

Another point of interest: the use of inner classes for FireButtonListener and ScrollBarListener. The inner class is lexically scoped inside the enclosing class -- so the name FireButtonListener isn't known outside CannonWorld. The code in the inner class can access the fields defined by the enclosing class. Note that these fields of the enclosing class will always be meaningful, since we can't access the inner class to instantiate it without going through an instance of the enclosing class.

This is analogous to lexical scoping in Scheme and other languages, albeit with classes and objects.

Scheme example:

;; version with a nested named function
(define (multiply-each s coeff)
  (define (mult n)
    (* coeff n))
  (map mult s))

;; or a version with an anonymous function:
(define (multiply-each s coeff)
  (map (lambda (n) (* coeff n)) s))
Advantages of using inner classes: don't clutter up package name space; easy access to fields and methods of enclosing context.