> ### 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!

[ Chapter Index | Main Index ]