CS 124, Spring 2013
Lab 12: GUI Hangman

In Exercise 2 of Lab 4, you worked on a simple command-line version of Hangman. In this lab, you will work on a GUI version of the game. The GUI version is event-driven. In this case, the events come from buttons. Things happen when the user clicks buttons, and your program has to respond to button clicks by changing the state of the program in appropriate ways. You can find a completed version of the game in the executable jar file /classes/cs124/HangmanComplete.jar.

You should start a new project named lab12. To the src folder of the project, add the three files from the directory /classes/cs124/lab12-files: Hangman.java, WordList.java, and wordlist.txt. In the lab, you will only work on Hangman.java. I handed out a copy of Hangman.java in class, with some extra comments added. Hopefully, you have taken some time to look it over and think about it. WordList.java is used in Hangman.java, and you don't have to modify it; it defines a class that manages the list of words that are available for the program. The file wordlist.txt contains the actual list of words. I made this file by writing a program that selected 500 random words of length 5 through 12 from a much longer list. I then eliminated most of the really obscure words and proper names from the list. (You could substitute your own list of words, if you want. You could even use the full list of words, /classes/cs124/wordlist-full.txt.)

This lab is due next Thursday, as usual.

Alphabet Buttons

Open the file Hangman.java. This starter file already does a significant amount of work, but it lacks the set of alphabet buttons that the user will click in order to guess letters while playing the game. You need to create those buttons and add them to the GUI. They must also be added to the ArrayList alphabetButtons, which is used to keep track of the buttons so that they can be manipulated later in the program. All this is done in the constructor of the Hangman class, where the other buttons are already created.

To hold the alphabet buttons, you will have to create a subpanel, that will be added in turn to the main panel. You should check out how this is already done for the bottom subpanel, which holds the three buttons at the bottom of the window. Do the same thing for a "top" panel, which should be added to the BorderLayout.NORTH position in the main panel.

The top panel is supposed to show two rows of buttons, with 13 buttons in each row. To do this, it needs a type of layout manager called a GridLayout. You can install the layout manager by saying

top.setLayout( new GridLayout(2,13) );

Once you have the top panel, you should create 26 buttons, showing the text "A", "B", "C", ..., "Z". For each button, you should construct the button, set the buttonHandler to listen for clicks from the button, add it to the top panel, and add it to the alphabetButtons. For one button, you could do it like this:

JButton button = new JButton("A");
button.addActionListener(buttonHandler);
top.add(button);
alphabetButtons.add(button);

But you don't really want to write four lines of code for each button, do you? You can use a loop. (Hint: The variable in a for loop can be of type char. And if you have a char ch, you can get a string containing that char using "" + ch.)

You should be able to run the program at this point. You should see the alphabet buttons, and if you click one, you should see a message in the display.

(Note: When I tried this on my Mac, I got the nasty surprise that the buttons wanted to be too big, and the width of the window got stretched out too much. To fix this, I told the buttons to use a different preferred size by saying

button.setPreferredSize(new Dimension(30,35));

for each of the alphabet buttons. This was not a problem on Linux.)

Programming the Game Logic

With the GUI complete, you just need to program the game! There are two parts to this: Saying what happens in response to button clicks, and drawing the display. You do the first in the actionPerformed() method in the nested ButtonHandler class. You do the second in the paintComponent() method in the nested Display class. You will probably also want to add a few more methods to the class to perform some of the more complex or repeated tasks in the game.

In the actionPerformed method, you need to know which button was pressed. There are two ways of identifying the button: By the "source" of the ActionEvent, or by the "action command" of the ActionEvent. The source is the JButton object itself. The action command is the String of text displayed on that button. In the actionPerformed() method, these values have already been extracted from the event and stored in the local variables whichButton and cmd. I suggest that you use cmd to tell which button was pressed. (You will need whichButton just a bit later.)

The three buttons on the bottom of the window have action commands "Next word", "Give up", and "Quit". "Next word" is only meant to be used between games, to start a new game. "Give up" is meant to be used during a game, if the user wants to give up on that word (which should count as a loss.) "Quit" ends the program.

If cmd is not from one of the buttons on the bottom of the window, then it has to be from one of the alphabet buttons. The user clicks on one of those buttons to guess a letter. This is the heart of the game and is where a lot of processing takes place. For example, you need to check whether the letter is in the word. You have to add the letter to the string of guessed letters. The game should end if the user has completed the word or if the user has made too many bad guesses. The message should be changed to tell the user what has happened. Also, you should disable the button that was clicked so that the user can't choose the same letter again. You can do this by saying

whichButton.setEnabled(false);

Since the game can end in several ways, and there are several things that have to be done whenever the game ends, I suggest that you write an endGame method to do those things.

At the same time that you work on the game logic in the actionPerformed() method, you will also want to start working on drawing the display. Note that the paintComponent() method already draws the message in the display. Just by changing the value of message, you can get some idea about what is going on. In the end, though, it will have to draw more. The most essential thing is to draw the secret word, showing only those letters that the user has guessed. It's nice to draw the hanged man, but that is not required to get full credit for the lab. A major idea is that the paintComponent() method draws the entire picture, taking into account the values of all the state variables (such as badGuesses, word, guesses, and gameOver). You do not try to make changes to the existing picture; you simply make changes to the state variables, and then the whole picture gets redrawn using the new values.

If you don't remember Lab 4 well, you might find it useful to look it over again -- and look over the code that you wrote for it -- for some hints about how to do some of the basic tasks that you have to do in the GUI program. But remember that the overal flow of control in the program is entirely different.

Making a jar File

Perhaps you would like to turn your program into a jar file, which will make it easier for you (or your friends and family) to run it. This is easy to do in Eclipse.

Right-click anywhere in the Project Explorer pane, and choose "Export..." from the pop-up menu (or just select "Export..." from the "File" menu.)

In the Export dialog box, open up the "Java" section and click on "Runnable JAR File" to select it. Click "Next".

The next dialog box has a pop-up menu named "Launch Configurations". Each entry shows the name of a main class that you have run and the project that it is in. Select the one for the program that you want to turn into a jar file (Hangman in this case).

Just below that, select a name and location for the jar file. Hit the "Browse..." button to make this easier. The name of the file should end with ".jar". For example: Hangman.jar

Click "Finish" to create the jar file. You might get a message that the "JAR export finished with warnings". Warnings are OK.

You can do the same thing with any program -- such as the game that you wrote for Lab 011.

(On our Linux systems, for some reason, jar files have to be marked as "executable" if you want to be able to run them by clicking the icon. To do that for Hangman.jar, for example, on the command line, cd into the directory that contains Hangman.jar, and say

chmod  +x  Hangman.jar

Or, in a file browser window, right-click the Hangman.java icon, select "Properties" at the bottom of the pop-up menu, go to the "Permissions" tab, and check the box labeled "Allow executing file as program".)