Solution for
Programming Exercise 6.2


THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.

Exercise 6.2: Improve your dice applet from the previous exercise so that it also responds to keyboard input. When the applet has the input focus, it should be hilited with a colored border, and the dice should be rolled whenever the user presses a key on the keyboard. This is in addition to rolling them when the user clicks the mouse on the applet. Here is an applet that solves this exercise:


Discussion

The modifications that have to be made to the program from the previous exercise are fairly small. The applet has to handle key presses, so it must implement the KeyListener interface, and it must register itself to listen for key events by calling addKeyListener() in its init() method. The keyPressed() method just has to roll the dice, by calling the same roll() subroutine that is used by the mousePressed() routine.

The border of the applet changes from blue to red when the applet has the input focus. In order to implement this, the applet must process focus events. So it needs to implement the FocusListener interface and register itself to listen for focus events. A boolean-valued instance variable, focussed, is set to true when the applet gains the focus and to false when the applet loses the focus. This processing of focus events is identical to what was outlined in Section 6.5.

There is one thing that is easy to forget: On some platforms, an applet does not automatically receive the input focus when the user clicks on it. It has to request the focus by calling the requestFocus() method. This is done in the mousePressed() routine, in response to a mouse click on the applet. If you forget this, your applet will work on some platforms, but on others it will never get the input focus and the keyboard will never work.

In the following solution, modifications to the code are shown in red.


The Solution

    
    /*
       Shows a pair of dice that are rolled when the user clicks on the
       applet.  The dice are also rolled whenever the user presses a key
       on the keyboard, assuming that the applet has the input focus.
       It is assumed that the applet is 100-by-100 pixels.  A clicking
       sound is played when the dice are rolled.
    */
    
    import java.awt.*;
    import java.awt.event.*;
    import java.applet.*;
    
    public class ClickableDice2 extends Applet 
                   implements MouseListener, FocusListener, KeyListener {
    
       int die1 = 4;  // The values shown on the dice.
       int die2 = 3;
       
       boolean focussed;  // True when this applet has the input focus.
                          // (The color of the applet's border changes
                          // when this is true.)
       
    
       public void init() {
              // To initialize the applet, register the applet to listen
              // for mouse events on itself.  Also set a light blue
              // background color.
          addMouseListener(this);
          addKeyListener(this);
          addFocusListener(this);
          setBackground( new Color(200,200,255) );
       }
       
    
       public void paint(Graphics g) {
              // The paint method draws a blue border and then
              // draws the two dice.
          if (focussed)
             g.setColor( Color.red );
          else
             g.setColor( Color.blue );
          g.drawRect(0,0,99,99);
          g.drawRect(1,1,97,97);
          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;
          play(getCodeBase(), "click.au");
          repaint();
       }
       
       
       public void focusGained(FocusEvent evt) {
             // When the applet gets the input focus, record that
             // fact and repaint the applet with red border.
          focussed = true;
          repaint();
       }
       
    
       public void focusLost(FocusEvent evt) {
             // When the applet loses the input focus, record that
             // fact and repaint the applet with blue border.
          focussed = false;
          repaint();
       }
       
       
       public void keyPressed(KeyEvent evt) {
            // When the user presses any key on the keyboard,
            // roll the dice;
          roll();
       }
       
    
       public void mousePressed(MouseEvent evt) {
             // When the user clicks the applet, roll the dice.
             // Also, request the input focus.
          roll();
          requestFocus();
       }
       
    
       public void mouseReleased(MouseEvent evt) { }
       public void mouseClicked(MouseEvent evt) { }    // Empty methods,
       public void mouseEntered(MouseEvent evt) { }    //   required by
       public void mouseExited(MouseEvent evt) { }     //   the interfaces.
       public void keyReleased(KeyEvent evt) { }
       public void keyTyped(KeyEvent evt) { }
       
    
    } // end class ClickableDice


[ Exercises | Chapter Index | Main Index ]