
I have a very specific question regarding my Hangman program.
You will probably want to run the program yourself to understand the issue I am having.
The problem arises when the counter (variable that holds the wrong number of guesses) reaches six. At this point the user has used up all their allotted guesses and is given the option to play again. If the user opts to play again, the askQuestion method is called, in which a JOptionPane gets a String from the user that is to be the new word to be guessed.
After the user types in a word and clicks OK, the JOptionPane is for some reason painted onto the Panel.
This is the issue I am having. It disappears after you submit a letter as a guess, but is a very unsightly error while it exists. I have included a screenshot above. Here is my code:
//********************************************************
// HangmanPanel.java
//
// Creates your run-of-the mill hangman game.
//********************************************************
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class HangmanPanel extends JPanel
{
private JLabel inputLabel; // Input field for letter guesses
private String word; // Variable to hold answer word
private String guessed = "Guessed: "; // Holds letters already guessed
private String l, text = ""; // l: Variable to hold letter guess; text: Tells user whether their guess was correct
private JTextField letter; // Text Field for Input Label
private int counter = 0; // Incremented when wrong guess is made; controls drawing of hangman
private String underscore = ""; // Shows answer as sequence of underscores, which are replaced with correct guesses
private boolean playing = true;
//------------------------------------------
// Sets up the hangman panel.
//------------------------------------------
public HangmanPanel()
{
setBackground (Color.white);
setPreferredSize (new Dimension(300, 300));
askQuestion();
inputLabel = new JLabel ("Enter a letter.");
add (inputLabel);
letter = new JTextField (1);
add (letter);
letter.addActionListener(new TempListener());
}
public void askQuestion()
{
word = JOptionPane.showInputDialog ("Enter the word.");
for (int i = 0; i < word.length(); i++)
{
underscore += "-";
}
repaint();
}
//----------------------------------
// Paints a hanging man.
//----------------------------------
public void paintComponent (java.awt.Graphics page)
{
super.paintComponent (page);
final int xBound = 200, yBound = 20;
if (playing)
{
page.setColor (Color.black);
page.fillRect(xBound + 30, yBound + 80, 60, 10); // Stand
page.fillRect (xBound +55, yBound, 10, 80); // Gallows Pole
page.fillRect(xBound + 25, yBound, 40, 5);
page.fillRect(xBound + 25, yBound, 3, 20); // Rope
if (counter > 0)
page.fillOval(xBound + 18, yBound + 15, 16, 16); // Head
if (counter > 1)
page.fillRect(xBound + 24, yBound + 23, 5, 30); // Torso
if (counter > 2)
page.drawLine(xBound + 23, yBound + 40, xBound + 13, yBound + 30); // Right Arm
if (counter > 3)
page.drawLine(xBound + 29, yBound + 40, xBound + 39, yBound + 30); // Left Arm
if (counter > 4)
page.drawLine(xBound + 23, yBound + 53, xBound + 18, yBound + 63); // Right Leg
if (counter > 5)
{
page.drawLine(xBound + 29, yBound + 53, xBound + 34, yBound + 63); // Left Leg
text = "";
counter=0;
underscore = "";
guessed = "Guessed: ";
//page.drawString("Play Again?", 50, 130);
int again = JOptionPane.showConfirmDialog (null, "Do Another?");
if (again == JOptionPane.YES_OPTION)
askQuestion();
else
playing = false;
}
page.drawString(guessed, 20, 130);
page.drawString(underscore, 20, 110);
page.drawString(text, 20, 250);
}
else
page.drawString("Goodbye", 50, 50);
}
private class TempListener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{
l = letter.getText(); // Stores letter guess as a string
letter.setText(""); // Clears Text Field
char let = l.charAt(0); // Creates a char variable for letter guess
guessed = guessed + let + " ";
int index = word.indexOf(let);
if (index != -1)
{
text = "Correct";
underscore = underscore.substring(0,index) + word.substring(index, index+1) + underscore.substring(index+1); // Replaces underscore with found letter
String substring = word.substring(index+1);
int index2 = substring.indexOf(let);
while (substring.indexOf(let) != -1)
{
index2 = substring.indexOf(let);
index = index + index2 + 1;
underscore = underscore.substring(0,index) + word.substring(index, index+1) + underscore.substring(index+1);
substring = word.substring(index+1);
}
}
else
{
text = "Wrong";
counter++;
}
if (underscore.indexOf('-') == -1)
{
text = "You Win!";
//askQuestion
}
repaint();
}
}
}
Here is the HangmanFrame class. It is not relevant to my question, I include it only for those that want to run the program:
import javax.swing.JFrame;
public class HangmanFrame
{
//----------------------------------------------
// Creates the main frame of the program.
//----------------------------------------------
public static void main (String[] args)
{
JFrame frame = new JFrame ("Hangman");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
HangmanPanel panel = new HangmanPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
And here is my Search class, which is also not directly related to my question:
public class Search{
public static Comparable linearSearch (String word, String letter, int start)
{
while (!found && index < word.length())
{
if (word.charAt(index) == letter.charAt(0))
found = true;
else
index++;
}
if (found)
return index;
else
return null;
}
}
I apologize for the formatting issues there, I tried my best. Anyways I hope someone can point me in the right direction, I suspect the issue could be fixed with a call to repaint() but I have been unable to do so. Also wanted to mention that there are obviously many other flaws with this program; it is far from robust. That is because it is far from finished. You don’t have to bring these issues to my attention, I will work on them after I get this bug sorted out. Thanks for giving this a look!
EDIT: My problem is fixed, however I’d still like to keep this open for a little while to see if anyone could elucidate exactly why my original code did not work.
The problem may be related to the fact that you display
JOptionPane.showConfirmDialoginpaintComponentmethod. The method is responsible for component painting. Avoid putting program logic into that method. Painting operations should be fast and optimized for better performance and user experience. Popping up a modal dialog from this method is not a good idea. Moreover, you cannot control when this method will be called. Callingrepaint()only schedules the component’s update request.Check out Performing Custom Painting tutorial for details and examples. Also look at Painting in AWT and Swing.