Solution for
Programming Exercise 6.3
THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.
Exercise 6.3: In Exercise 6.1, above, you wrote a pair-of-dice applet where the dice are rolled when the clicks on the applet. Now make a pair-of-dice applet that uses the methods discussed in Section 6.6. Draw the dice on a "canvas", and place a "Roll" button below the canvas. The dice should be rolled when the user clicks the Roll button. Your applet should look and work like this one:
(Note: Since there was only one button in this applet, I added it directly to the applet, rather than putting it in a "buttonBar" panel and adding the panel to the applet.)
Discussion
In the applets from Exercise 6.1 and Exercise 6.2, the dice were drawn directly on the applet, and the applet responded directly to mouse clicks on itself. For this version of the dice applet, the user rolls the dice by clicking on a button. The button is an object of type Button, which is contained in the applet. The dice are drawn on a separate "canvas," not directly on the applet. The canvas is another object which is contained in the applet. The canvas belongs to the class DiceCanvas, which I defined as a subclass of the standard Canvas class. In outline, the structure of this applet is similar to ColoredHelloWorldApplet2.java from Section 6.6.
In order to respond to user events, some object must listen for ActionEvents from the button. Any object can do this. In my solution, the applet does the listening. So, the applet class implements the ActionListener interface, defines an actionPerformed method that rolls the dice, and registers itself to listen for ActionEvents from the button. (Note: Originally, I tired to have the canvas listen for button events. This didn't work because I wanted to play a sound as part of the response to the ActionEvent. A Canvas object does not have any method for playing a sound. Only an Applet can play sounds. So, the actionPerformed method had to go in the Applet class.)
The DiceCanvas class is very similar to the applet class, ClickableDice, from Exercise 6.1. However, it does not implement MouseListener or respond to mouse events. It just sits there passively until someone -- the main DiceWithButtons applet class -- tells it to roll. Also, it doesn't play the sound when the dice are rolled. I had to move that function to the applet class.
The Solution
/* Shows a pair of dice that are rolled when the user clicks on a "Roll" button. It is assumed that the applet is sized so that the canvas on which the dice are drawn is about 100 by 100 pixels. A clicking sound is played when the dice are rolled. This file defines two classes: A main applet class, DiceWithButton, and a canvas class, DiceCanvas. The DiceCanvas class is not public and is not meant to be used outside this file. */ import java.awt.*; import java.awt.event.*; import java.applet.*; public class DiceWithButton extends Applet implements ActionListener{ // This applet class sets things up, and it responds to clicks // on the Roll button by telling the DiceCanvas to roll the dice. DiceCanvas dice; // A canvas that displays the dice. // (This has to be an instance variable // because I use it in the actionPerformed // method.) public void init() { // Initialize the applet by setting its layout manager to // be a BorderLayout and creating the two components that // are shown on the applet. setBackground(Color.blue); setLayout(new BorderLayout(2,2)); // Use BorderLayout with // 2 pixels between components. dice = new DiceCanvas(); // Canvas to show the dice. add(dice, BorderLayout.CENTER); // Dice go in large, center // area of the applet. Button rollBttn = new Button("Roll!"); // The roll button. rollBttn.addActionListener(this); // Applet listens to this button. rollBttn.setBackground(Color.lightGray); add(rollBttn, BorderLayout.SOUTH); // The button occupies a strip // along the bottom. } // end init() public Insets getInsets() { // leave a 2-pixel border around the edges of the applet. return new Insets(2,2,2,2); } public void actionPerformed(ActionEvent evt) { // Respond to a click on the "Roll" button by rolling the dice // and playing a sound. dice.roll(); play(getCodeBase(), "click.au"); } } // end class DiceWithButton //--------------------------------------------------------------- class DiceCanvas extends Canvas { // This canvas class displays the dice. The dice are // rolled by calling this class's roll() method. int die1 = 4; // The values shown on the dice. int die2 = 3; DiceCanvas() { // Constructor. To initialize the canvas, set a // light blue background color. setBackground( new Color(200,200,250) ); } public void paint(Graphics g) { // The paint method draws the two dice. drawDie(g, die1, 10, 10); drawDie(g, die2, 55, 55); } void drawDie(Graphics g, int val, int x, int y) { // Draw a die with upper left corner at (x,y). The die is // 3 5 by 35 pixels in size. The val parameter gives the // value showing on the die (that is, the number of dots). g.setColor(Color.white); g.fillRect(x, y, 35, 35); g.setColor(Color.black); g.drawRect(x, y, 34, 34); if (val > 1) // upper left dot g.fillOval(x+3, y+3, 9, 9); if (val > 3) // upper right dot g.fillOval(x+23, y+3, 9, 9); if (val == 6) // middle left dot g.fillOval(x+3, y+13, 9, 9); if (val % 2 == 1) // middle dot (for odd-numbered val's) g.fillOval(x+13, y+13, 9, 9); if (val == 6) // middle right dot g.fillOval(x+23, y+13, 9, 9); if (val > 3) // bottom left dot g.fillOval(x+3, y+23, 9, 9); if (val > 1) // bottom right dot g.fillOval(x+23, y+23, 9,9); } void roll() { // Roll the dice by randomizing their values. Tell the // system to repaint the applet, to show the new values. // Also, play a clicking sound to give the user more feedback. die1 = (int)(Math.random()*6) + 1; die2 = (int)(Math.random()*6) + 1; repaint(); } } // end class DiceCanvas
[ Exercises | Chapter Index | Main Index ]