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:
- How much time lapses between color changes?
- How does the timer know which bar to alter?
- How do we know that all the bars have changed color?
- What does the timer do after all the bars have changed color?
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:
- Modify bars.java to make it implement Comparable. Remember from class
that a Comparable interface uses one method - compareTo.
- Create a method: private int minIndex(int start) -- takes
an index start and returns the index of the
smallest bar in the list starting at index start.
- Create a method: private void swap(int i, int j) -- takes
two indices and swaps the values in the list at those indices.
- Modify the refreshListener to implement a selection sort.--
At the conclusion of each timer event, you should see that
one more bar is correctly positioned. To make things easier to follow, you
should also change the color of the corectly positioned bars to blue.
Note - your final code won't be too much different than it does now, right?
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.
- 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.
- 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:
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
- 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.
-
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:
- 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.
- 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:
- Printouts of your programs - make sure that your name is included in the
header comments (not just written on)
- Tar the files in your lab3 directory with the command
tar czf lab3.tgz .