Week Four Assignment
UI Cleanup:
- Go into the Form Editor and reposition the "Guess a number between 1 and 100 to the top left cell.
- Reposition the guessText JLabel Component to the first row, third column so it is just to the right of the label. (Jigloo should resize the cells - if it doesn't just reposition so it all looks good)
- Add a new JLabel named "guessCountLabel" and put "You've made 0 guesses so far" as the Text. Place this component belot the "Guess a number...." JLabel.
- Save your work!
Now let's make the program take a guess from the user!
In order to get the guessText JTextField respond to user input we have to put a "listener" on the field. What this does is exactly what
it implies. It "listens". There are several types of listeners. What we will use is an EventListener.
- Open the Java Perspective so you can look at the code. From the Menu at the top select Window -> Open Perspective -> Java Perspective
- From the Outline section (on the right side of Eclipse), select initGUI() method. It will take you to the source for that method. Arrow up above the line and make a few more new lines before initGUI();
- Type "private FocusListener guessFocusListener = new FocusListener() {};" and hit enter
- Eclipse will not like this. This is because FocusListener is not an object, but an Interface. This is a HUGE concept point and to fully understand it will take quite a few months of practice.
Let's suffice with this: An interface is like a definition. It defines what methods are typical of an object. There isn't any functionality in an interface just methods that are required if you decide
to "extend" the interface. To put this into other terms.... A Car is a pretty abstract thing. Because it such a broad thing and cars are so unique it might be considered an Interface. If you want to create a
car, you would want to extend the Car Interface to make sure that you cover all your bases in what the typical uses of a car would be. Cars have four wheels, and tend to move. Something that is common among all
cars is that they need to have a way for steering. So a method on the car interface might be "provideSteering". Any object that extends the Car interface would need to Implement the "provideSteering" method
as defined in the Car interface.
So we have created a new object that needs to implement methods on the FocusListener Interface. That is why Eclipse is making things red. Let's take advantage of the power of Eclipse and click the
red "X' to the left of the Source Editor. You should see a small window with the suggestion "Add unimplemented Methods". Select that option!
- This will add two empty methods. I personally don't like how Eclipse adds "TODO" lines. You can select to clean up after Eclipse by removing the TODO line along with all the white space it creates.
- We need to get the value the user entered in the guessText field. So to capture that we'll listen for when they hit the [TAB] key after they've entered their value. Tab is the typical way to go from field
to field in most applications. So the method that we need to add code to is the focusLost() method. Focus means the cursor is resting in that object. When the user hits Tab, the focus moves to the next component and the
focus is "lost" from the guessText field. Remove the TODO line from the focusLost() method and enter:
- public void focusLost(FocusEvent e) {
     String guessString = e.getSource();
}};
In order to get the value from the guessText JTextField, we have to reference the Object itself. That is done by referencing, the e.getSource() method. That returns to us the actual JTextObject itself. That isn't the value entered, but the Object itself.
In order to get the value, we need to call getText() method from the JTextField.
The problem here is the getSource() returns an Object, which is the broadest thing alive. The reason why FocusEvent isn't smart enough to know the exact object type is because buttons, drop down menus, etc can have focus,
So we need to "Cast" the Object to a JTextField. That is easy. Just before the "e.getSource()" enter "(JTextField)" so it looks like this:
- String guessString = ((JTextField)e.getSource());
- Save your work!
- What this does is convert the Object that getSource returns into a JTextField object. Because we did that we can now use many
methods that JTextFields have. Such as "getText()" which returns the value of the JTextField component. So add the following:
- String guessString = ((JTextField)e.getSource()).getText();
- We now have the value the user entered. But we need to analyze that and do something with it. So lets store that value outside of the focusLost method so the value can be referenced and worked with.
So at the top where the class level variables are entered enter:
- private String guessString = null;
- Because we made a class level String object that is named the same as what is in the focusListener, and will use that to store the value of the guess remove the "String" declaration inside the focusLost() method.
- Now whenever we hit Tab out of the guessText label the value will be stored in the guessString object and we can compare to the randomNumber generated in the constructor.
* * * * * * * * * * Questions/Break/Intermission * * * * * * * * *
We've actually covered a bunch of concepts here. To test what we've done so far let's output the value that the user entered from the focusLost() method, and we'll remove the output later.
- In the focusLost() method, after the line where it assigns the guessString, create a new line and enter:
- Click the red "x" and select the "Create method analyzeGuess()" option. This creates the method for us. We will put all our code for comparing the guess with the randomNumber in here later.
- However Eclipse, put the method within the guessFocusListener. We want this method outside of the listener because we need to output to the user if they are correct or not, and update the JLabel we created today.
This jLabel is not accessible from within the guessFocusListener. So highlight the entire analyzeGuess() method and hit CTRL + X and then position your cursor outside the guessFocusListener and hit CTRL+V.
- For now in the newly created analyzeGuess() method, just put in:
- private void analyzeGuess() {
     System.out.println("The user guessed: " + guessString);
}
- So we've created a focusListener, but we haven't tied it to the guessText component yet, so scroll down to the initGUI() method and find the guessText
Just below where it creates it with new JTextField(); put in a new line and enter:
- guessText.addFocusListener(guessFocusListener);
- Save your work!
- Run the program and look for the output to the console once you hit tab out of the guessText field.
Our program is still a very long way from being complete. There are still alot of "bugs" that we need to code for. The best applications are those where
"dummies" can use them and the program is smart enough to filter out all the input that they really shouldn't enter.
For example, the guess should be a number, but it will accept any key pressed on the keyboard, even letters. If we don't program for this scenario, when we
compare the value entered and the number, the program will crash. But for this week, we'll let the concepts we've discussed soak in a little. Do the following homework.
Homework
- When the user tabs out of the guessText field the System.out.println shows the value. After the System.out.println try agin clear out this value for the user so they don't have to.
Right now the user has to select the text they guessed previously and hit delete, or backspace. That's a pain. Clear out the text for them in the analyzeGuess method after the System.out.println.
HINT: getText is for getting, setText is for setting
- Visit the links in the "Concepts discussed" below and read before you're bored or overwhelmed.
Concepts discussed
- Listeners
- Interfaces
If you have questions please email me!