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 JPanel, and place a "Roll" button at the bottom of the applet. The dice should be rolled when the user clicks the Roll button. Your applet should look and work like this one:

Sorry, but your browser
doesn't support Java.

(Note: Since there was only one button in this applet, I added it directly to the applet's content pane, rather than putting it in a "buttonBar" panel and adding the panel to the content pane.)


Discussion

In the applets from Exercise 6.1 and Exercise 6.2, a dice canvas filled the whole applet, and the applet responded directly to mouse clicks on the dice canvas. For this version of the dice applet, the user rolls the dice by clicking on a button. It does not respond to clicks on the dice canvas. In this applet, there are two components: the dice canvas and the button. The button is an object of type JButton, while the dice canvas is an object belonging to a nested class named DiceCanvas that is almost the same as the DiceCanvas class in Exercise 6.1.

In outline, the structure of this applet is similar to HelloWorldJApplet.java from Section 6.6. The init() method creates the two components and adds them to the content pane of the applet. The button is added to the content pane with the command

            getContentPane().add(button, BorderLayout.SOUTH);

The constant BorderLayout.SOUTH specifies that the button goes at the bottom of the applet. The position of the dice canvas in the content pane is specified by the constant BorderLayout.CENTER:

            getContentPane().add(dice, BorderLayout.CENTER);

This means that the dice canvas will occupy all the space in the applet that is not occupied by the button.

In order to respond when the user presses the button, some object must listen for ActionEvents from the button. As usual, any object can do this. In my solution, the applet does the listening (although an anonymous class might be more attractive). 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.

I made one small change in the paintComponent() method that draws the dice canvas. In the solution to Exercise 6.1, I assumed that the size of the canvas was 100-by-100. Now, however, I don't know exactly how big the button is, so I don't know exactly how tall the canvas will be. To allow for variations in the size, the paintComponent() method uses the getSize() method to get the actual size of the canvas. This information is used to draw the two-pixel border around the canvas:

            g.drawRect(0, 0, getSize().width - 1, getSize().height - 1);
            g.drawRect(1, 1, getSize().width - 3, getSize().height - 3);

The Solution


    /*
       Shows a pair of dice that are rolled when the user clicks on a
       button  It is assumed that the applet is 100 pixels wide.  The
       height of the applet should be more than 100 pixels, to allow
       space for the button.  A clicking sound is played when the dice 
       are rolled.
    */

    
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class DiceWithButton extends JApplet implements ActionListener {
    
       int die1 = 4;  // The values shown on the dice.
       int die2 = 3;
       
       DiceCanvas dice;  // An object belonging to the nested class
                         // DiceCanvas, which is used as the drawing
                         // surface on which the dice are displayed.
    
       public void init() {
              // To initialize the applet, create the drawing surface
              // object and add it to the applet's content pane.
              // Also create a button and add it to the content pane.
              // Set the applet to listen for events from the button.
              // And set the background color of the DiceCanvas.

          dice = new DiceCanvas();
          getContentPane().add(dice, BorderLayout.CENTER);
          dice.setBackground( new Color(200,200,255) );  // light blue

          JButton button = new JButton("Roll!");
          button.addActionListener(this);
          getContentPane().add(button, BorderLayout.SOUTH);

       } // end init();
       
    
       void drawDie(Graphics g, int val, int x, int y) {
             // Draw a die with upper left corner at (x,y).  The die is
             // 35 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;
          play(getCodeBase(), "click.au");
          dice.repaint();
       }
       
    
       public void actionPerformed(ActionEvent evt) {
             // This will be called by the system when the user
             // clicks the button.  Respond by rolling the dice.
          roll();
       }
       
    
       class DiceCanvas extends JPanel {
            // A nested class to represent the drawing surface
            // on which the dice are displayed.
          public void paintComponent(Graphics g) {
                 // The paint method draws a blue border and then
                 // draws the two dice.
             super.paintComponent(g);  // fill with background color.
             g.setColor( Color.blue );
             g.drawRect(0, 0, getSize().width - 1, getSize().height - 1);
             g.drawRect(1, 1, getSize().width - 3, getSize().height - 3);
             drawDie(g, die1, 10, 10);
             drawDie(g, die2, 55, 55);
          }
       }
    
    } // end class DiceWithButton


[ Exercises | Chapter Index | Main Index ]