Programming Exercises
For Chapter 7
THIS PAGE CONTAINS programming exercises based on
material from Chapter 7 of this on-line
Java textbook. Each exercise has a link to a discussion of one possible solution of that
exercise.
Exercise 7.1:
Exercise 5.2 involved a class,
StatCalc.java, that could compute
some statistics of a set of numbers. Write an applet that uses
the StatCalc class to compute and display statistics of
numbers entered by the user. The applet will have an instance
variable of type StatCalc that does the computations.
The applet should include a JTextField
where the user enters a number. It should have four labels that
display four statistics for the numbers that have been entered:
the number of numbers, the sum, the mean, and the standard deviation.
Every time the user enters a new number, the statistics displayed
on the labels should change. The user enters a number by
typing it into the JTextField and pressing return.
There should be a "Clear" button that clears out all the data.
This means creating a new StatCalc object and resetting
the displays on the labels. My applet also has an "Enter" button
that does the same thing as pressing the return key in the
JTextField. (Recall that a JTextField generates
an ActionEvent when the user presses return, so your applet
should register itself to listen for ActionEvents from the
JTextField.) Here is my solution to this problem:
See the solution!
Exercise 7.2:
Write an applet with a JTextArea where the user can enter
some text. The applet should have a button. When the user clicks
on the button, the applet should count the number of lines in the
user's input, the number of words in the user's input, and the
number of characters in the user's input. This information should
be displayed on three labels in the applet. Recall that if
textInput is a JTextArea, then you can get the
contents of the JTextArea by calling the function
textInput.getText(). This function returns a String
containing all the text from the JTextArea. The number of
characters is just the length of this String. Lines
in the String are separated by the new line character,
'\n', so the number of lines is just the number of new line characters
in the String, plus one. Words are a little harder to
count. Exercise 3.4 has
some advice about finding the words in a String. Essentially,
you want to count the number of characters that are first characters
in words. Don't forget to put your JTextArea in a JScrollPane.
Scrollbars should appear when the user types more text than will
fit in the available area.
Here is my applet:
See the solution!
Exercise 7.3:
The RGBColorChooser applet
lets the user set the red, green, and blue levels in a color by
manipulating sliders. Something like this could make a useful
custom component. Such a component could be included in a program to allow
the user to specify a drawing color, for example. Rewrite the
RGBColorChooser as a component. Make it a subclass of
JPanel instead of JApplet. Instead of doing the
initialization in an init() method, you'll have to do it
in a constructor. The component should have a method, getColor(),
that returns the color currently displayed on the component.
It should also have a method, setColor(Color c), to set
the color to a specified value. Both these methods would be useful
to a program that uses your component.
In order to write the setColor(Color c) method, you
need to know that if c is a variable of type Color,
then c.getRed() is a function that returns an integer
in the range 0 to 255 that gives the red level of the color.
Similarly, the functions c.getGreen() and c.getBlue()
return the blue and green components.
Test your component by
using it in a simple applet that sets the component to a random
color when the user clicks on a button, like this one:
See the solution!
Exercise 7.4:
In the Blackjack game BlackjackGUI.java
from Exercise 6.8,
the user can click on the "Hit", "Stand", and "NewGame" buttons
even when it doesn't make sense to do so. It would be better
if the buttons were disabled at the appropriate times. The
"New Game" button should be disabled when there is a game
in progress. The "Hit" and "Stand" buttons should be disabled
when there is not a game in progress. The instance variable
gameInProgress tells whether or not a game is in progress,
so you just have to make sure that the buttons are properly
enabled and disabled whenever this variable changes value.
Make this change in the Blackjack program. This applet uses
a nested class, BlackjackCanvas, to represent the board.
You'll have to do most of your work in that class. In order to
manipulate the buttons, you will have to use instance variables
to refer to the buttons.
I strongly advise writing a subroutine that can be called
whenever it is necessary to set the value of
the gameInProgress variable.
Then the subroutine can take responsibility for
enabling and disabling the buttons.
Recall that if bttn is a variable of type
JButton, then bttn.setEnabled(false)
disables the button and bttn.setEnabled(true) enables
the button.
See the solution! [A working applet can be found here.]
Exercise 7.5:
Building on your solution to the preceding exercise, make it possible for the user
to place bets on the Blackjack game. When the applet starts, give the user $100.
Add a JTextField to the strip of controls along the bottom of the applet.
The user can enter the bet in this JTextField. When the game begins,
check the amount of the bet. You should do this when the game begins, not
when it ends, because several errors can occur: The contents of the JTextField
might not be a legal number. The bet that the user places might be more money than
the user has, or it might be <= 0. You should detect these errors and show an
error message instead of starting the game. The user's bet should be an
integral number of dollars. You can convert the user's input into an integer, and
check for illegal, non-numeric input, with a try...catch statement of
the form
try {
betAmount = Integer.parseInt( betInput.getText() );
}
catch (NumberFormatException e) {
. . . // The input is not a number.
// Respond by showing an error message and
// exiting from the doNewGame() method.
}
It would be a good idea to make the JTextField uneditable while the game
is in progress. If betInput is the JTextField, you can make it
editable and uneditable by the user with the commands
betAmount.setEditable(true) and betAmount.setEditable(false).
In the paintComponent() method, you should include commands to display the amount
of money that the user has left.
There is one other thing to think about: The applet should not start a new game
when it is first created. The user should have a chance to set a bet amount
before the game starts. So, in the constructor for the canvas class, you should not
call doNewGame(). You might want to display a message such as
"Welcome to Blackjack" before the first game starts.
See the solution! [A working applet can be found here.]
Exercise 7.6:
The StopWatch component from Section 7.4
displays the text "Timing..." when the stop watch is running. It would
be nice if it displayed the elapsed time since the stop watch
was started. For that, you need to create a Timer. Add
a Timer to the original source code, StopWatch.java,
to display the elapsed time in seconds. Create the timer in
the mousePressed() routine when the stop watch is started.
Stop the timer in the mousePressed() routine when the stop watch
is stopped. The elapsed time won't be very accurate anyway, so just
show the integral number of seconds. You only need to set the text a
few times per second. For my Timer method, I use a delay of 100 milliseconds
for the timer. Here is an applet that tests my solution
to this exercise:
See the solution!
Exercise 7.7:
The applet at the end of Section 7.7 shows
animations of moving symmetric patterns that look something like
the image in a kaleidescope. Symmetric patterns are pretty.
Make the SimplePaint3 applet do symmetric, kaleidoscopic
patterns. As the user draws a figure, the applet should be able to
draw reflected versions of that figure to make symmetric pictures.
The applet will have several options for the type of symmetry
that is displayed. The user should be able to choose one of
four options from a JComboBox menu. Using the "No symmetry" option,
only the figure that the user draws is shown. Using "2-way symmetry",
the user's figure and its horizontal reflection are shown.
Using "4-way symmetry", the two vertical reflections are added.
Finally, using "8-way symmetry", the four diagonal reflections are
also added. Formulas for computing the reflections are given below.
The source code SimplePaint3.java
already has a drawFigure() subroutine that draws all the figures.
You can add a putMultiFigure() routine to draw a figure and some or
all of its reflections. putMultiFigure should call the existing
drawFigure to draw the figure and any necessary reflections. It decides which reflections to
draw based on the setting of the symmetry menu. Where the mousePressed,
mouseDragged, and mouseReleased methods call
drawFigure, they should call putMultiFigure instead.
The source code also has a repaintRect() method that calls repaint()
on a rectangle that contains two given points. You can treat this in the same
way as drawFigure(), adding a repaintMultiRect() that calls
repaintRect() and replacing each call to repaintRect() with
a call to repaintMultiRect(). Alternatively, if you are willing to let
your applet be a little less efficient about repainting, you could simply replace
each call to repaintRect() with a simple call to repaint(), without
parameters. This just means that the applet will redraw a larger area than it
really needs to.
If (x,y) is a point in a component that is width pixels wide
and height pixels high, then the reflections of this point are
obtained as follows:
The horizontal reflection is (width - x, y)
The two vertical reflections are (x, height - y) and (width - x, height - y)
To get the four diagonal reflections, first compute the diagonal reflection of (x,y) as
a = (int)( ((double)y / height) * width );
b = (int)( ((double)x / width) * height );
Then use the horizontal and vertical reflections of the point (a,b):
(a, b)
(width - a, b)
(a, height - b)
(width - a, height - b)
(The diagonal reflections are harder than they would be if the canvas were square.
Then the height would equal the width, and the reflection of (x,y) would just
be (y,x).)
To reflect a figure determined by two points, (x1,y1) and (x2,y2),
compute the reflections of both points to get the reflected figure.
This is really not so hard. The changes you have to make to the source
code are not as long as the explanation I have given here.
Here is my applet. Don't forget to try it with the symmetry
menu set to "8-way Symmetry"!
See the solution!
Exercise 7.8:
Turn your applet from the previous exercise into a stand-alone
application that runs as a JFrame. (If you didn't do the
previous exercise, you can do this exercise with the original
SimplePaint3.java.)
To make the exercise
more interesting, remove the JButtons and JComboBoxes
and replace them with a menubar at the top of the frame. You can
design the menus any way you like, but you should have at least the same
functionality as in the original program.
As an improvement, you might add an "Undo" command.
When the user clicks on the "Undo" button, the previous drawing operation will
be undone. This just means returning to the image as it was before the
drawing operation took place. This is easy to implement, as long
as we allow just one operation to be undone. When the off-screen canvas,
OSI, is created, make a second off-screen canvas, undoBuffer,
of the same size. Before starting any drawing operation,
copy the image from OSI to undoBuffer. You can do this with
the commands
Graphics undoGr = undoBuffer.getGraphics();
undoGr.drawImage(OSI, 0, 0, null);
When the user clicks "Undo", just swap the values of OSI
and undoBuffer and repaint. The previous image will appear
on the screen. Clicking on "Undo" again will "undo the undo."
As another improvement, you could make it possible for the user
to select a drawing color using a JColorChooser dialog box.
Here is a button that opens my program in its own window. (You don't have to
write an applet to launch your frame. Just create the frame in the
program's main() routine.)
See the solution!