CPSC 170 Lab 4
Interfaces, More Listeners, & GUIs
As usual, create a lab4 subdirectory for today's lab, open this
document in FireFox, and start emacs.
Checkboxes and Radio Buttons
Up until now, you hav been creating simple GUIs with panels, textboxes and
buttons. Recall that these programs used ActionListeners to carry out
certain actions when a button was pressed. In today's exercise you will see
two new GUI components (checkboxes and radio buttons)
along with their listeners (ItemListeners and ActionListeners respectively).
The files StyleOptions.java and
StyleOptionsPanel.java
are adapted from Listings 5.22 and 5.23 of the text. (A variable
fontSize is used rather than an integer literal in various instances
and the variable style is an instance variable rather than local to the
itemStateChanged method). Save these files to your directory and compile and
run StyleOptions.java to see how it works. This is the driver;
StyleOptionsPanel.java contains the code for the GUI.
Now you will add a set
of 3 radio buttons to let the user choose among three font sizes. The
method of adding the radio buttons will be very similar to that in the
QuoteOptionPanel class (Listing 5.25 of the text), so study this example
before you continue.
Do the following to add the radio buttons to the GUI:
- Declare three objects small, medium, and
large of type JRadioButton.
- Instantiate the button objects labeling them "Small Font," "Medium Font,"
"Large Font." Initialize the large font button to true. Set the
background color of the buttons to cyan.
- Instantiate a button group object and add the buttons to
it.
- Radio buttons produce action events so you need to add an inner
class (name it SizeListener) to implement ActionListener and
listen for radio button clicks. The code for actionPerformed
can be similar to that in the QuoteListener in Listing 5.25. (Or if you prefer,
you can use the isSelected method to see which button was selected
instead of getting and checking the source.)
You need to set the fontSize variable (use 16 for small,
24 for medium, and 32 for large) in the if statement, then call the
setFont method to set the font for the saying object.
- In StyleGUI() instantiate a SizeListener and add it
to each button. Also add each button to the panel.
- Compile and run the program. Note that as the font size changes
the checkboxes and buttons re-arrange themselves in the panel. To
fix this, you could put each of the major components into separate
panels (you don't have to right now). There are also other ways to address
this problem that we will address later in the course.
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 JPanel
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.
More Mouse Events
Create a new directory in your lab 4 directory called Cards. Download the
file Cards.tgz to that directory and extract it
using the command
tar xzf Cards.tgz
You will find that this file contained
- a slightly updated version of the card class
(it now contains a "getBlankIcon" method).
- a slightly updated version of the card images
(it now contains a blank card and a back of card).
- a complete version of PileOfCards.java (from last week's lab)
- a CardPanel class that functions similar to last week's lab except
that there are two JLabels to display the cards.
- the driver program CardGame.java
Run the program to understand how it works.
In the previous examples, we attached a mouselistener to the whole panel.
It is often more beneficial to attach mouse listeners to individual GUI
components.
In this case, we would like to attach a mouse listener to each of the JLabels so that when
the mouse clicks on the picture of a card, the program prints out the name of
the card. This may seem easy at first, but there are a couple of hurdles that
you will have to overcome to make this work nicely. Here is the general
idea.
- In the CardPanel constructor, make the "CardListener" object and add it
to both of the JLabels. Again, you shouldn't create two separate listeners
-- use the same object for both.
- In the CardPanel class, create an inner class called CardListener that
implements a Mouse Listener.
- In the mouseClicked method, determine which of the cards was pressed
(hint: getSource) and print it out.
What is wrong with this solution? Try to figure out the problem
before you implement it. If you can't, that is ok too, try
implementing it and see where it goes wrong.
How do you fix the problem? See if you can think of a solution and then talk
to me or the lab assistant to discuss your ideas.
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 lab4 directory with the command
tar czf lab4.tgz .
and e-mail them to me (hughes@roanoke.edu)