As with the previous tuttle interfaces this class, which extends the Applet class, has the responsibility, in its init() method, of configuring itself, creating an instance of the TextTuttle class, creating an instance of the TextMenuTuttleInterface class to control the tuttle, creating a feedback area and then placing the interface into a well defined initial state so that, on its conclusion, the interface becomes visible to the user. The implmentation of the class, as far as the end of its constructor, is as follows.
0001 // Filename TextMenuTuttle.java. 0002 // Supplies a main application text menu 0003 // interface the TextTuttle class. 0004 // 0005 // Written for Java Interface book chapter 7. 0006 // Fintan Culwin, v 0.2, August 1997. 0007 0008 package TextMenuTuttle; 0009 0010 import java.awt.*; 0011 import java.applet.*; 0012 import java.awt.event.*; 0013 0014 import Tuttles.TextTuttle; 0015 import TextMenuTuttle.TextMenuTuttleInterface; 0016 0017 public class TextMenuTuttle extends Applet 0018 implements KeyListener { 0019 0020 private TextTuttle theTuttle; 0021 private TextMenuTuttleInterface theInterface; 0022 0023 private Panel feedbackPanel; 0024 private Label feedbackLabel; 0026 0027 0028 public void init() { 0029 0030 Panel tuttlePanel; 0031 0032 this.setLayout( new BorderLayout()); 0033 this.setFont( new Font( "TimesRoman", Font.BOLD, 14)); 0034 this.setBackground( Color.white); 0035 0036 tuttlePanel = new Panel(); 0037 theTuttle = new TextTuttle( this, 400, 400); 0038 tuttlePanel.add( theTuttle); 0039 0040 theInterface = new TextMenuTuttleInterface( this); 0041 0042 feedbackPanel = new Panel(); 0043 feedbackLabel = new Label(); 0044 feedbackPanel.add( feedbackLabel); 0045 0046 this.add( feedbackPanel, "North"); 0047 this.add( tuttlePanel, "Center"); 0048 this.add( theInterface, "South"); 0049 0050 this.feedback(); 0051 theInterface.setMenuState( TextMenuTuttleInterface.TOP_LEVEL_MENU); 0052 } // End init.
The majority of this constructor is largely comparable to the corresponding constructors from the previous tuttle interfaces. The significant differences are that an instance of the TextMenuTuttleInterface, called theInterface, is constructed on line 0040 and subsequently added to the applet Panel in its "South" location on line 0048. It has its state set to TOP_LEVEL_MENU, on line 0051, before the method concludes. This will ensure that the interface, when first visible to the user, is something like that shown in Figure 7.2.
The identity of this instance of the TextMenuTuttle class is passed to theInterface as it is constructed and, in order for this to be allowed, the TextMenuTuttle class has to implement the KeyListener interface, as stated on line 0019. The KeyListener interface requires the class to supply keyTyped(), keyPressed() and keyReleased() methods which will be called as appropriate when the user interacts with the keyboard. A KeyEvent instance will be passed as an argument to these methods which contains, amongst other things, an attribute called keyChar indicating which key on the keyboard was pressed. This class is only concerned with processing KeyTyped events and the implementation of the three KeyListener methods is as follows.
0057 public void keyTyped( KeyEvent event) { 0058 0059 char pressed = event.getKeyChar(); 0060 int newMenu = TextMenuTuttleInterface.TOP_LEVEL_MENU; 0061 0062 switch ( theInterface.menuStateIs()) { 0063 0064 case TextMenuTuttleInterface.TOP_LEVEL_MENU: 0065 newMenu = topLevelMenu( pressed); 0066 break; 0067 0068 case TextMenuTuttleInterface.MOVE_MENU: 0069 newMenu = moveMenu( pressed); 0070 break; 0071 0072 case TextMenuTuttleInterface.MOVE_FORWARD_MENU: 0073 newMenu = moveForwardMenu( pressed); 0074 break; 0075 ---- // Other cases omitted. 0116 case TextMenuTuttleInterface.EXIT_MENU: 0117 newMenu = exitMenu( pressed); 0118 break; 0119 0120 } // End switch menuState. 0121 0122 theInterface.setMenuState( newMenu); 0123 this.feedback(); 0124 } // End keyTyped. 0125 0126 public void keyPressed( KeyEvent event ) {} // End keyPressed. 0127 public void keyReleased( KeyEvent event ) {} // End keyReleased.
The keyTyped() method commences, on line 0059, by retrieving the identity of the key typed from the KeyEvent event and storing it in the local character variable pressed. A second local variable called newMenu of type int is declared on line 0060. This variable will be used to represent the menu which should be displayed after this KeyEvent has been processed and is initialised to a default value indicating that the TOP_LEVEL_MENU should be shown.
The major part of the method, between lines 0062 and 0120, is a switch structure containing a branch for every possible menu state; its selector expression is a call of the theInterface's menuStateIs() method. Each branch calls a private method, with a systematic name, to deal with the key pressed. For example if the application has just been started then it will be in the TOP_LEVEL_MENU state, as described above. If the user presses and releases the 't' key on the keyboard a keyEvent containing 'm' will be constructed and passed as the event argument to the keyTyped() method. The switch selector on line 0062 will identify the TOP_LEVEL_MENU state causing the branch on line 0065 to be taken, calling the topLevelMenu() method and passing as an argument the keyCharacter extracted from the event on line 0059. The topLevelMenu() method will process this character and return the identity of the menu state which the interface is to transit to. All other possible states have associated methods each of which takes as an argument the identity of the key pressed and returns the manifest value of the newMenu to be displayed; examples of these methods will be given below.
Following the end of the switch structure in the keyTyped() method, the setMenuState() method of theInterface is called passing as an argument the newMenu to be displayed. The final action of the keyTyped method is to update the feedback Panel shown at the top of the interface. The other two required methods of the KeyListener interface, keyPressed() and keyReleased() need not do anything are declared as dummy methods on lines 0126 and 0127 in order to satisfy the requirements of the KeyListener interface which this class implements.
The topLevelMenu() method, called from keyTyped() whenever the interface is in its TOP_MENU_STATE, is implemented as follows. It consists of a switch statement, containing a branch for each possible combination of key presses which the menu is to respond to. Each branch sets the value of the local variable newMenuState to indicate the appropriate menu state which the interface is to transit to. On line 0171 this value is returned from the method and, if none of the branches have been activated, will contain its default value TOP_LEVEL_MENU. The returned value will be used by the keyTyped() method to set the state of the menu. The effect is that if the user presses one of the expected keys then the interface will transit to the appropriate state otherwise it will remain in the TOP_LEVEL_MENU state.
0131 private int topLevelMenu( char pressed) { 0132 0133 int newMenuState = TextMenuTuttleInterface.TOP_LEVEL_MENU; 0134 0135 switch( pressed) { 0136 case 'M': 0137 case 'm': 0138 newMenuState = TextMenuTuttleInterface.MOVE_MENU; 0139 break; 0140 0141 case 'T': 0142 case 't': 0143 newMenuState = TextMenuTuttleInterface.TURN_MENU; 0144 break; 0145 --- // Other cases omitted. 0166 case 'E': 0167 case 'e': 0168 newMenuState = TextMenuTuttleInterface.EXIT_MENU; 0169 break; 0170 } // End switch. 0171 return newMenuState; 0172 } // End topLevelMenu
Following the example above which assumed that the user pressed 'm': this will cause the branch on line 0143 to be followed causing this method to return the value TURN_MENU on line 0171. As explained above this will result in the interface presenting the user with the text menu shown at the top of Figure 7.3. The next time the user uses the keyboard the keyPressed() method will result in a call of the moveMenu() method whose implementation is as follows.
0175 private int moveMenu( char pressed) { 0176 0177 int newMenuState = TextMenuTuttleInterface.MOVE_MENU; 0178 0179 switch( pressed) { 0180 case KeyEvent.VK_ESCAPE: 0181 newMenuState = TextMenuTuttleInterface.TOP_LEVEL_MENU; 0182 break; 0183 0184 case 'F': 0185 case 'f': 0186 newMenuState = TextMenuTuttleInterface.MOVE_FORWARD_MENU; 0187 break; 0188 0189 case 'B': 0190 case 'b': 0191 newMenuState = TextMenuTuttleInterface.MOVE_BACKWARD_MENU; 0192 break; 0193 } // End switch. 0194 return newMenuState; 0195 } // End moveMenu.
The implementation of this method is directly comparable to the implementation of the topLevelMenu() method above. It will respond to presses of the <ESCAPE> key by transiting back to the TOP_LEVEL_MENU state, the 'f' or 'F' key to the MOVE_FORWARD_MENU state and the 'b' or 'B' key to the MOVE_BACKWARD_MENU state, any other key will leave the interface in the MOVE_MENU state. The identity of the <ESCAPE> key is established, on line 0180, by using the manifest value VK_ESCAPE (Virtual Key Escape) supplied by the KeyEvent class. Assuming that the user presses the 'f' or 'F' key the interface will appear as shown at the bottom of figure 7.3 and the next KeyEvent generated will cause the KeyTyped() method to call the moveForwardMenu() method, implemented as follows.
0198 private int moveForwardMenu( char pressed) { 0199 0200 int newMenuState = TextMenuTuttleInterface.MOVE_FORWARD_MENU; 0201 0202 switch( pressed) { 0203 case KeyEvent.VK_ESCAPE: 0204 newMenuState = TextMenuTuttleInterface.MOVE_MENU; 0205 break; 0206 0207 case '5': 0208 theTuttle.doCommand("fd 5"); 0209 break; 0210 0211 case '1': 0212 theTuttle.doCommand("fd 10"); 0213 break; 0214 0215 case '2': 0216 theTuttle.doCommand("fd 25"); 0217 break; 0218 } // End switch. 0219 return newMenuState; 0220 } // End moveForwardMenu.
In this method pressing the <ESCAPE> key effects a transit back to the MOVE_MENU state and other key presses will leave the interface in the MOVE_FORWARD_MENU state. However pressing the '5', '1' or '2' key will cause the theTuttle doCommand() method to be called, passing as an argument a suitable command string. So if the user presses the '1' key the tuttle will move forward 10 steps. As the keyPressed() method concludes by calling the feedback() method, whose implementation does not differ from those presented in previous chapters, the new status of the tuttle will be reported at the top of the interface. The menu system will remain in the MOVE_FORWARD_MENU state until the <ESCAPE> key is pressed, allowing the user to rapidly move the tuttle in its current direction.
A consideration of the three methods described, and the corresponding moveBackwardAction() will show that the behavior of the interface is as described in the STD from Figure 7.4. The remaining parts of the TextMenuTuttle class are essentially identical with a specific method for each of the possible menu states, whose implementations are comparable to those presented above. The only significant difference is in the exitMenu() method, as follows, where pressing the 'y' or 'Y' key will cause the applet to terminate.
0512 private int exitMenu( char pressed) { 0513 0514 int newMenuState = theInterface.HELP_MENU; 0515 0516 switch( pressed) { 0517 case KeyEvent.VK_ESCAPE: 0518 newMenuState = theInterface.TOP_LEVEL_MENU; 0519 break; 0520 0521 case 'Y': 0522 case 'y': 0523 System.exit( 0); 0524 break; 0525 0526 case 'N': 0527 case 'n': 0528 newMenuState = theInterface.TOP_LEVEL_MENU; 0529 break; 0530 } // End switch. 0531 0532 return newMenuState; 0533 } // End exitMenu.
The operation of this system provides a demonstration of the correct implementation of the TextTuttle class which will be further demonstrated by the CommandLineTuttle class. Details of how to obtain the parts of the source code which have been omitted from this part of the chapter are contained in Appendix B.
TextMenuTuttle.java
TextMenuTuttle
7.5 The CommandLineTuttle interface
7.3 The TextMenuTuttleInterface