Session 18


810:062
Computer Science II
Object-Oriented Programming


Opening Exercise

Define a ShadowBall class. A ShadowBall is a Ball that becomes darker after every hundredth time it moves.

A Ball's own Color instance variable can help the ShadowBall do its task. Java Colors respond to the message:

public Color darker()

      Creates a darker version of this color.

Notice that, in response to the message, a Color returns a darker version of itself; the Color doesn't change itself.


An Opening Solution -- Tested

A ShadowBall is a Ball. So our solution should be a subclass of Ball.

This means that I can use a ShadowBall any place that I use a Ball. So, I can test my new class in any Ball application, such as MultiBallWorld!

Here is a solution in which ShadowBall extends Ball. And here is a solution in which ShadowBall extends BoundedBall.

Notice that, in either case, the ShadowBall needs to see what its current color is and to change its own color. This means that Disk must have protected accessors.

Do you notice a pattern?

The two versions of ShadowBall pose an interesting dilemma... These classes are identical except for an argument to the constructor. How can we create a shadow ball that doesn't duplicate code in this way? Stay tuned -- we'll learn a neat technique for cutting this Gordian knot soon after the break!

Testing is necessary. Test your code early and often. Right now, we aren't writing JUnit tests, so we rely on running the graphical apps and observing their behavior.


Review: Inheritance in Java Graphics

Here is a catch phrase that captures how Java graphics work:

Don't call us. We'll call you.

Not only does MultiBallWorld inherit several methods that we use, but many of the methods in Frame sent messages whose messages we implement in MultiBallWorld! Consider:

    public void paint( Graphics g )      // in calls MultiBallWorld
    {
        for (int i = 0; i < BallArraySize; i++)
        {
            ballArray[i].paint( g );
            ballArray[i].move();
        }
        ...

        counter = counter + 1;
        if ( counter < 2000 )
           repaint();
        else
           System.exit(0);
    }


    public void paint( Graphics g )       // in class Ball
    {
        g.setColor( color );
        g.fillOval( location.x, location.y,
                    location.width, location.height );
    }

Much of the control for our application lies in the Frame and Graphics classes provided by the Java AWT. Our application has just enough control to "kick off" the action.

We'll explore the ideas that underlie this style of programming more deeply in the second half of the course.


Who's the Boss?

Object-oriented programming shifts program control from a top-level "main" program into a set of collaborating objects.

One object may be responsible for starting the action, or coordinating the action, but no one object is "in charge" -- at least of too much.

This way of designing a program makes it easier for us to write programs that shift control out of the program at all and into the hands of the user.


Event-Driven Programming

This style of programming is called event-driven because it builds program control around one or more events that the user causes.

Think of how a web server works...

The program retains low-level control of how to respond to each kind of event that the user can initiate.

Event-driven programming can also be done in environments with little or no user interaction. In such environments, the events are generated by other programs: objects that generate events to request services.


Event-Driven Programs in Java

In Java, the programmer defines objects called listeners that wait for and respond to user-initiated events.

A listener can be attached to any object capable of generating an event caused by the user:

We can also attach listeners to non-UI components, but we won't write that sort of program this semester.


A Simple First Example

Let's start off with something simple: a Button. Whenever the user presses the button, the balls will move.

Creating a button requires three steps:

The listener waits for the user to press the button and executes its actionPerformed() method whenever it is pressed.

We can add the button to one of five geographical locations in the frame: north, south, east, west, and center. Notice that the location is passed as a capitalized string.

Notice: The frame does not store its button in an IV. How can that work?

We define our listener class right inside the MultiBallWorldFrame class. Such use of an inner class is standard for listeners. They are an implementation detail of the class, so making them a part of the class -- a private part -- makes a lot of sense. Notice that, because the listener class is defined within the body of MultiBallWorldFrame, the listener object can access the private parts of the frame.


An Exercise: Freeze Tag!

Our simple first example shows how buttons and button listeners work in Java, but it results in a tedious "game": press the button, press the button, press the button, ....

How can we make the button an on/off switch for moving?

The idea is this: Press the button once to make the balls move. Press it again, and they stop moving. Press it again, and they start moving again. Press it again, ...

What does our listener have to do now? Our frame?

The frame can keep track of whether the balls are moving or not, and send them a move() when appropriate. All the listener has to do is tell the frame to toggle its ballsAreMoving? variable. Here is one way to do it.

Notice the toggle variable's name... A boolean variable should read well in an if or while statement.


Control in Event-Driven Programs

In this style of programming, the control structure of the program changes from:

Do this, then that, then this other thing.

to:

Respond to the user's action.


Wrap Up


Eugene Wallingford ..... wallingf@cs.uni.edu ..... March 10, 2005