CPSC 170 Lab 3
Sorting and Events

As usual, create a lab3 subdirectory for today's lab, open this document in FireFox, and start emacs.

Thinking about Events

Earlier in this class (and last semester), we started to learn about event-based programming. The general idea is that things can happen during the execution of the program that we wish to respond to. To capture these events , we establish listeners . A listener is simply a block of code that is executed when a certain event occurs. For example, to respond to a button being pushed, we define an ActionListener. Since we want to respond to different events in different ways, we would like to extend the capabilities of the ActionListener to suit our needs.

However! ActionListeners only do one thing - respond to an "actionPerformed". Moreover, since we are always going to specify what to do in case there was an "actionPerformed", the actionListener is actually abstract! We have an abstract class, where all methods are abstract - this is a good candidate for an interface! Therefore, when we define a class to respond to events, we don't extend ActionListener, we ___________________________________ ActionListener.

Timers

We typically think of events as being something that the user has done, i.e. clicking on a button, but that is not always the case. We might also be interested in generating events at regular intervals. For example, we might want a program that checks for new e-mail every 15 minutes. To acheive this, we use a Timer object. A timer object has an interval, measured in milliseconds, and a listener that defines the code to be executed after the interval of time has elapsed. (see page 469-473 for more details)

Download the file drawBars.tgz . Uncompress it using the command

tar xzf drawBars.tgz
This should containt three files: bars.java, drawBars.java and drawBars.html Compile drawBars.java and run the file using the appletviewer. Observe what it does (be patient, there is a timer in there!)

You should have noticed that the bars changed color, one by one -- if you didn't know better, you would expect that there was a for loop or a while loop controlling the color change. Examine the code to find out what is really going on. Before you move on, you should make sure that you understand:

Sorting

Often when we sort, especially small lists, the computer is done before we know it (and that's a good thing). However, since we are just getting started with sorting, it is useful to break down the sorting process to allow us to get a better sense of what is happening.

We are going to sort the bars (according to height), using a selection sort (refer to the code on p 501 or your class notes). Instead of doing the entire sort at once, we are going to use the timer to delay processing and see incremental steps. To achieve this you should:

Print drawBars.java and bars.java to turn in.

Mouse Events

Programs can also respond to mouse events -- moving and clicking the mouse -- that are not tied to any particular GUI component. Java divides these into two categories: mouse events and mouse motion events. A MouseListener (a class that implements the MouseListener interface) must provide bodies for methods corresponding to each of the mouse events. A MouseMotionListener (implementing the MouseMotionListener interface) must provide bodies for methods corresponding to each of the mouse motion events. These events are described in section 7.9 of the text.

  1. File MousePlay.java contains a program that displays a message saying when the mouse button is pressed and released. It uses MousePlayPanel.java to define the JPanel that is actually displayed. Save these files to your directory, run MousePlay to see how it works, and open MousePlayPanel in emacs. Note that MousePlayPanel has an inner class MousePlayListener that implements MouseListener by giving bodies for the five MouseListener methods. Even though nothing is done when the mouse is clicked or when it enters or exits, those methods still appear with empty bodies -- this is required for the MouseListener interface to be implemented.

    Modify MousePlayPanel so that it also prints appropriate messages when the mouse is clicked, when it enters the panel, and when it exits. Play with the resulting program until you understand how the mouse events are generated.

  2. Files Dots.java and DotsPanel.java contain revised versions of the code in listings 7.18 and 7.19 in the text. Dots draws a dot every time the uses presses the mouse button; only the current dot is shown in the revised version. Save these files to your directory and run Dots to see how it works. Then modify DotsPanel as follows:
    1. Make the dots that appear alternately red and green. To do this, you will need to make the following changes:
      • Add an instance variable to hold the dot color.
      • Add an instance variable to count the number of dots that have been drawn.
      • When the mouse is pressed, in addition to setting the draw point you need to update the counter and change the dot color to green if the counter is odd, to red if it is even. Then call repaint.
    2. Modify your code so that the dot is drawn where the mouse is released, not where it is pressed.

    Print DotsPanel.java to turn in.

  3. File Circles.java sets up a GUI that creates and draws a circle as defined in Circle.java of random size and color at each mouse press Each circle replaces the one before it. The code to handle the mouse press and do the drawing is in CirclePanel.java. Save these files to your directory, compile them and run them and experiment with the GUI. Then modify these files as described below.
    1. This program creates a new circle each time -- you can tell because each circle is a different color and size. Write a method void move(Point p) for your Circle class that takes a Point and moves the circle so its center is at that point. Now modify your CirclesListener class (defined inside CirclePanel) so that instead of creating a new circle every time the user presses the mouse, if a circle already exists it moves the existing circle to the point where the user pressed (the "presspoint"). If no circle exists, a new one should be created at the presspoint. So now a circle of the same color and size should move around the screen.

    2. Write a method boolean isInside(Point p) for your Circle class that takes a Point and tells whether it is inside the circle. A point is inside the circle if its distance from the center is less than the radius. Recall that the distance between two points (x1,y1) and (x2,y2) is sqrt((x2-x1)2+(y2-y1)2.

    3. Now modify the mousePressed method of CirclesListener so that the GUI behaves as follows:
      • If there is no circle (i.e., it is null) and the user presses anywhere, a new (random) circle should be drawn at the presspoint.
      • If there is a circle on the screen and the user presses inside that circle, the circle should go away. (Hint: To make the circle go away, set it to null and repaint.)
      • If there is a circle on the screen and the user presses somewhere else, the circle should move to that point (no change from before).
      So the logic for mousePressed should look like this:

        
        if there is currently no circle
           create a new circle at the presspoint
        else if the click is inside the circle
           make the circle go away
        else
           move the circle to the presspoint
      
        repaint
      

    4. Add bodies for the mouseEntered and mouseExited methods so that when the mouse enters the applet the background turns white, and when it exits the background turns blue. Remember that you can set the background color with the setBackground method.

    5. Now modify the code in CirclePanel.java so that a circle is drawn when the user presses a mouse, but the user can drag it around as long as the mouse button is depressed. If the mouse button is released and then pressed again, it deletes or moves the circle as before. You will need to make the following changes:
      1. In the CirclePanel constructor, make the CirclesListener object listen for both mouse events and mouse motion events. Don't create two separate listeners -- use the same object for both.

      2. Make the CirclesListener class implement the MouseMotionListener interface in addition to the MouseListener interface. This requires two steps:
        • Note in the header that CirclesListener implements MouseMotionListener.
        • Add bodies for the two MouseMotionListener methods, mouseDragged and mouseMoved. In mouseDragged, simply move the circle to the point returned by the getPoint method of the MouseEvent and repaint. (Remember that you already wrote a move() method for the Circle class.) Provide an empty body for mouseMoved.

      Print CirclesListener.java and Circle.java to turn in.

HAND IN: