Building an Application

Now that you've seen the basic concepts, it's time to put them to work. In this section we'll create a simple example application: a number guessing game. The object of the game is for the user to guess a randomly generated integer between 1 and 100 (inclusive) in the fewest number of tries. Each time the user makes an incorrect guess, the application will give the user a hint as to whether the guess was greater than or less than the correct number. When the user correctly guesses the number, a "Congratulations!" message will be displayed and the user will be given the option to play again.

Number Guess Game Control Flow

Source Code: The number guessing game is provided as part of the standard Echo2 distribution. In the Echo2 archive, the source files for the game may be found in the folder NextApp_Echo2 / SourceCode / src / tutorialapp / numberguess. Of particular interest is the ApplicationInstance, located at NextApp_Echo2 / SourceCode / src / tutorialapp / numberguess / src / java / echo2tutorial / numberguess / NumberGuessApp.java. You will want to have a copy of the source code handy for this lesson.

NumberGuessApp

The user interface code of the Guess-A-Number game is divided into three classes, all of which are found in the NumberGuessApp.java source file. The public class NumberGuessApp provides the required ApplicationInstance implementation. The GamePane and CongratulationsPane classes are both derived from the Echo ContentPane component, and represent the number-guessing and end-of-game screens respectively.

State Management: In this example, the NumberGuessApp also serves to manage the high-level state of the application, i.e., starting new games and displaying the end-of-game congratulations message. Two methods have been created to control this state, startNewGame() and congratulate().

Initialization: The init() method of the ApplicationInstance simply creates the main Window instance and invokes the startNewGame() method to initialize a new game for the user.

Derived Components: The GamePane and CongratulationsPane classes both extend from ContentPane. Each of these components overrides its constructor to configure itself by creating and adding child Components and setting properties upon instantiation. The practice of extending Components in this fashion is encouraged.

The GamePane

The GamePane is a component which handles a single "number guessing session". On construction, a GamePane generates the secret random number which must be guessed. It then adds a Column container-component to itself to separate child Components vertically. Various Labels indicating the status of the game, a TextField into which guessed are entered, and a Button to submit guesses are then added to the Column. An additional Button is added to provide the option to reset and start a new game.

Event Handling: The GamePane class itself implements the ActionListener interface. It will register itself as an ActionListener on both its "Submit Guess" and "Start New Game" buttons. When the user clicks either of them, the actionPerformed() method will be invoked and provided with an ActionEvent describing the button click. The implementation will determine which button has been clicked by analyzing the "Action Command" provided by the ActionEvent, which will correspond to the same value set on the Buttons when they were configured using the setActionCommand() method.

Handling "Submit Guess" Button Clicks: If the actionPerformed() method receives an event with the command "submit guess", indicating the "Submit Guess" button was clicked, then the processGuess() method of the GamePane is invoked. The processGuess() method will then investigate the value entered in the guess-entry TextField.

Processing Guesses: The processGuess() method will first check if the entered guess is wholly invalid, i.e., if the user accidentally entered something other than a number, and displays an error message if necessary by adjusting the text of the "status label". If the guess is in fact a value between 1 and 100, the next question to be answered is whether or not it is correct. If the user has managed to pick the correct number, the congratulate() method of the NumberGuessApp is invoked. Otherwise, the method determines whether the guess was too high or too low and updates the Labels that display the number of guesses made and the prompt message informing the user to make a guess between a range of sensible values.

Handling "New Game" Button Clicks: If the actionPerformed() method receives an event with the command "new game", indicating the "Start a New Game" button was clicked, then the startNewGame() method of NumberGuessApp will be invoked. The startNewGame() method would then destroy the current GamePane and replace it with a new one (causing a new random number to be generated and zeroing out the number of failed attempts).

Obtaining the current ApplicationInstance: In order to either restart the game or display the congratulatory message screen, a method on the ApplicationInstance must be invoked. There are two ways to obtain a reference to the relevant ApplicationInstance: First, it can be obtained by invoking the getApplicationInstance() method on any Component that is currently "registered" to it, meaning that the Component is part of a hierarchy that is being currently displayed in the ApplicationInstance's user interface. The second method is to invoke the static method ApplicationInstance.getActive(), which will return the ApplicationInstance relevant to the current thread. In both cases the returned value must be cast to the appropriate derived type, i.e., NumberGuessApp in this case. In the NumberGuessApp class, the latter method of retrieving the ApplicationInstance has been used.

The CongratulationsPane

The CongratulationsPane is an extremely simple ContentPane which simply displays a "Congratulations!" banner in addition to showing the user how many tries it to took for him/her to successfully guess the secret number. The pane provides a single button which may be used to start a new game. Event handling is accomplished using the identical means introduced in the discussion of the GamePane.