摆动线程问题?

时间:2014-01-02 14:49:47

标签: java multithreading swing user-interface

我有一个用Java编写的游戏,可以在命令行上完美运行。但是,我一直在为它构建一个GUI,并且一直在改变它,因此它在GUI上运行,但我遇到了问题。这是一个刽子手游戏,允许玩家猜字母,试图猜测刽子手的话。如果玩家做出正确的猜测,游戏会显示某个消息,如果玩家猜错,游戏会显示不同的消息。虽然我已经使用GUI版本进行了两次猜测,但游戏停止了工作...我已经尝试修复它几天但没有运气......我试过调用javax.swing.SwingUtilities.invokeLater但它是仍然给我问题。 任何帮助将不胜感激,下面是代码(p.s.我仍在将命令行中的东西移动到GUI):

import java.util.ArrayList;
import java.util.Scanner;

public class HangmanTwo {
    private String[] wordList = {"apple", "orange"};
    private String chosenWord;
    private String playerGuess;
    private int numberOfIncorrectGuesses = 0;
    private boolean playerWon = false;
    private boolean playerPlaying = false;
    public static String uInput1;
    private boolean start = false;
    private ArrayList<String> lettersOfChosenWord;
    private ArrayList<String> incorrectGuessArrayList2 = new ArrayList<String>();
    private ArrayList<String> underScores;
    private boolean showHangman = false;
    HangmanGuiGui hh = new HangmanGuiGui();

//Print game instructions to player
void printGameInstructions() {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            hh.buildGui();
            hh.textFieldSouth.requestFocus();
            hh.textAreaCenter.append("Welcome to Hangman! \n");
            hh.textAreaCenter.append("To play, type in a letter as your guess, then press ENTER! \n");
            hh.textAreaCenter.append("If you think you know the word, type in the whole word and see if you got it right! \n");
            hh.textAreaCenter.append("But be careful! Guessing the word incorrectly will cost you a limb! \n");
            hh.textAreaCenter.append("To start playing, type 'start' and press ENTER. \n");
        }
    });

}

//Ask player if they want to start the game
void askToStart() {
    uInput1 = "waitingforinput";
    while (!start) {

        if(uInput1.equals("waitingforinput")) {

        } else if ((uInput1).equals("start")) {
            start = true;
            uInput1 = "waitingforInput";
        } else {
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    hh.textAreaCenter.append("Please type the word 'start' then press the ENTER key to begin playing. \n");

                }
            });


            uInput1 = "waitingforinput";
        }
    }
}

//Game picks random word from word list
void pickRandomWord() {
    int lengthOfWordList = wordList.length;
    int pickRandomWord = (int) (Math.random() * lengthOfWordList);
    chosenWord = wordList[pickRandomWord];
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            hh.textAreaCenter.append("The word is " + chosenWord.length() + " letters long\n");

        }
        });

}

//Make an arraylist to hold each letter of the chosen word at each index
void makeArrayListOfChosenWord(){
    lettersOfChosenWord = new ArrayList<String> ();
    for (int i = 0; i < chosenWord.length(); i++) {
        lettersOfChosenWord.add(chosenWord.substring(i, i+1));
    }
}

//Make an arraylist of underscores that holds as 
//many underscores as letters in the chosen word
void makeArrayListUnderScore(){
    underScores = new ArrayList<String>();
    for (int i = 0; i < chosenWord.length(); i++) {
        underScores.add("_");
    }
    for (int i = 0; i < underScores.size(); i++) {

        //hh.textAreaWest.append((underScores.get(i)).toString()); 
        //show the underscores in the text area

    }
}

//get a guess from the player
void getPlayerGuess() {
    boolean getGuess = true;
    uInput1 = "waitingforinput";
    while (getGuess) {
        if (uInput1.equals("")) {
            //javax.swing.SwingUtilities.invokeLater(new Runnable() {
                //public void run() {
                    hh.textAreaCenter.append("Please guess a letter\n");
                //}
                //});
            uInput1 = "waitingforinput";
        } else if (uInput1.equals("waitingforinput")) {

        } else {
            playerGuess = uInput1;
            //javax.swing.SwingUtilities.invokeLater(new Runnable() {
                //public void run() {
                    hh.textAreaCenter.append(playerGuess + "\n");
                //}
                //});


            getGuess = false;
        }
    }

}

//if the player wins, set the variable playerWon to true
void setPlayerWon(boolean a) {
    playerWon = a;
}

//start the game and play it
void playGame() {
    playerPlaying = true;
    while (playerPlaying && !playerWon) {
        getPlayerGuess();
        if (playerGuess.equals(chosenWord)) {
            playerPlaying = false;
            wordWasGuessed();
        }else if (numberOfIncorrectGuesses < 6) {
            checkPlayerGuess();
                if (playerWon) {
                    playerPlaying = false;
                    wordWasGuessed();
                } else if (numberOfIncorrectGuesses == 6) {
                    playerPlaying = false;
                    gameOver();
                }
        }
    }
}

//check the player's guess and see if its correct or not
void checkPlayerGuess(){
    //update number of incorrect guesses
    if (lettersOfChosenWord.contains(playerGuess)) {
        System.out.println("Correct guess!");
        if (!showHangman) {
            displayNoose();
        }
        displayHangman();
        replaceUnderScoreWithLetter();
        if (!underScores.contains("_")) {
            setPlayerWon(true);
        }
    } else if (!lettersOfChosenWord.contains(playerGuess)) {
        checkIncorrectGuessArrayList();
    }
}

//check the incorrectguess array list and add incorrect letters to it
void checkIncorrectGuessArrayList() {
    if (incorrectGuessArrayList2.contains(playerGuess)) {
        System.out.printf("You already guessed %s, try again!", playerGuess);
    } else if (!incorrectGuessArrayList2.contains(playerGuess)) {
        if (numberOfIncorrectGuesses < 6) {
            System.out.println("You guessed wrong, try again!");
            incorrectGuessArrayList2.add(playerGuess);
            ++numberOfIncorrectGuesses;
            displayHangman();
            printArrayListUnderScore();
        }
    }
}

//replace the underscores with a letter
void replaceUnderScoreWithLetter() {

    while (lettersOfChosenWord.contains(playerGuess)) {
        int indexOfPlayerGuess = lettersOfChosenWord.indexOf(playerGuess);
        underScores.set(indexOfPlayerGuess, playerGuess);
        lettersOfChosenWord.set(indexOfPlayerGuess, "_");
        incorrectGuessArrayList2.add(playerGuess);
    }
    printArrayListUnderScore();
}

//show the underscores to the player
void printArrayListUnderScore() {
    for (int j = 0; j < underScores.size(); j++) {
        System.out.print((underScores.get(j)).toString());
    }
}

void resetAllValues(int resetNumberIncorrectGuesses, boolean hangmanshow) {
    numberOfIncorrectGuesses = resetNumberIncorrectGuesses;
    lettersOfChosenWord.removeAll(lettersOfChosenWord);
    incorrectGuessArrayList2.removeAll(incorrectGuessArrayList2);
    underScores.removeAll(underScores);
    showHangman = hangmanshow;
}

void displayNoose(){
        System.out.println(" ___,");
        System.out.println(" l ");
        System.out.println(" l");
        System.out.println("_l_");
}


//Display a growing hangman with each incremental wrong guess
    void displayHangman(){
        switch (numberOfIncorrectGuesses) {
        case 1: firstWrongGuess();
        showHangman = true;
        break;
        case 2: secondWrongGuess();
        break;
        case 3: thirdWrongGuess();
        break;
        case 4: fourthWrongGuess();
        break;
        case 5: fifthWrongGuess();
        break;
        case 6: sixthWrongGuess();
        break;
    }
    }

    void firstWrongGuess(){
        System.out.println(" ___,");
        System.out.println(" l  o ");
        System.out.println(" l");
        System.out.println("_l_");
    }
    void secondWrongGuess(){
        System.out.println(" ___,");
        System.out.println(" l  o ");
        System.out.println(" l  l");
        System.out.println("_l_");
    }
    void thirdWrongGuess(){
        System.out.println(" ___,");
        System.out.println(" l  o ");
        System.out.println(" l /l");
        System.out.println("_l_");
    }
    void fourthWrongGuess(){
        System.out.println(" ___,");
        System.out.println(" l  o ");
        System.out.println(" l /l\\");
        System.out.println("_l_");
    }
    void fifthWrongGuess(){
        System.out.println(" ___,");
        System.out.println(" l  o ");
        System.out.println(" l /l\\");
        System.out.println("_l_/");
    }
    void sixthWrongGuess(){
        System.out.println(" ___,");
        System.out.println(" l  o ");
        System.out.println(" l /l\\");
        System.out.println("_l_/ \\");
    }

//what happens if the chosenWord was guessed
void wordWasGuessed() {
    hh.textAreaCenter.append("******\n");
    hh.textAreaCenter.append("GOOD JOB! YOU GUESSED THE WORD!\n");
    hh.textAreaCenter.append("You wanna play again? (y/n)\n"); 
    resetGame(0, false, false);
    boolean playAgain = false;
    while (!playAgain) {
        Scanner s = new Scanner(System.in);
        String userInput = s.next();
        if (userInput.equals("y")) {
            playAgain = true;
            resetAllValues(0, false);
            startGame();
        } else if (userInput.equals("n")) {
            playAgain = true;
            System.out.println("Ok...See you next time!");
        } else {
            System.out.println("please type y or n, then press enter!");
        }
    }
}

//what happens when the player loses and game is over
void gameOver() {
    System.out.println("Aww you lost... the word was " + chosenWord);
    System.out.println("You wanna play again? (y/n)");
    resetGame(0, false, false);
    boolean playAgain = false;
    while (!playAgain) {
        Scanner s = new Scanner(System.in);
        String userInput = s.next();
        if (userInput.equals("y")) {
            playAgain = true;
            resetAllValues(0, false);
            startGame();
        } else if (userInput.equals("n")) {
            playAgain = true;
            System.out.println("Ok...See you next time!");
        } else {
            System.out.println("please type y or n, then press enter!");
        }
    }
}

//reset the game
void resetGame(int resetNumberIG, boolean resetPlayerWon, boolean resetPlayerPlaying) {
    numberOfIncorrectGuesses = resetNumberIG;
    playerWon = resetPlayerWon;
    playerPlaying = resetPlayerPlaying;
}


void startGame() {
    pickRandomWord();
    makeArrayListOfChosenWord();
    makeArrayListUnderScore();
}

public static void main(String[] args) throws InterruptedException {
    HangmanTwo h = new HangmanTwo();
    h.printGameInstructions();
    h.askToStart();
    if (h.start == true) {
        h.startGame();
        h.playGame();
    }

}




}

和GUI

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class HangmanGuiGui {
    TextFieldSouthHandler tfsHandler = new TextFieldSouthHandler();
    ButtonEnterHandler beHandler = new ButtonEnterHandler();
    JFrame frame = new JFrame("Hangman");
    JLabel label = new JLabel("Welcome to Hangman");
    public JTextArea textAreaCenter = new JTextArea();
    JTextField textFieldSouth = new JTextField();
    JScrollPane scrollPane = new JScrollPane();
    JPanel panelWest = new JPanel(new BorderLayout());
    JPanel subPanelWest = new JPanel();
    JTextArea textAreaWest = new JTextArea();
    JPanel panelSouth = new JPanel(new BorderLayout());
    JButton buttonEnter = new JButton("Enter");
    //Icon aba = new ImageIcon(getClass().getResource("hangman1.jpg"));
    //JLabel picLabel = new JLabel(aba);
    JPanel panelEast = new JPanel();

    void buildGui() {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        textAreaCenter.setEditable(false);
        textFieldSouth.addKeyListener(tfsHandler);
        textAreaWest.setEditable(false);
        buttonEnter.addActionListener(beHandler);
        panelSouth.add(BorderLayout.CENTER, textFieldSouth);
        panelSouth.add(BorderLayout.EAST, buttonEnter);

        //subPanelWest.add(picLabel);
        JPanel panelwesteast = new JPanel();
        JPanel panelwestwest = new JPanel();
        JPanel panelwestsouth = new JPanel();
        panelWest.add(BorderLayout.SOUTH, panelwestsouth);
        panelWest.add(BorderLayout.EAST, panelwesteast);
        panelWest.add(BorderLayout.WEST, panelwestwest);
        panelWest.add(BorderLayout.NORTH, subPanelWest);
        panelWest.add(BorderLayout.CENTER, textAreaWest);

        scrollPane.getViewport().setView (textAreaCenter);
        frame.getContentPane().add(BorderLayout.NORTH, label);
        frame.getContentPane().add(BorderLayout.CENTER, scrollPane);
        frame.getContentPane().add(BorderLayout.SOUTH, panelSouth);
        frame.getContentPane().add(BorderLayout.WEST, panelWest);
        frame.getContentPane().add(BorderLayout.EAST, panelEast);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

private class TextFieldSouthHandler implements  KeyListener {

    public void keyPressed(KeyEvent event) {
            if (event.getKeyCode()==KeyEvent.VK_ENTER) {
                //boolean bee = javax.swing.SwingUtilities.isEventDispatchThread();
                javax.swing.SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        HangmanTwo.uInput1 = textFieldSouth.getText();
                        textFieldSouth.setText("");
                    }
                    });
            }
    }

    public void keyTyped(KeyEvent event) {
    }

    public void keyReleased(KeyEvent event) {
    }
}

private class ButtonEnterHandler implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                HangmanTwo.uInput1 = textFieldSouth.getText();
                textFieldSouth.setText("");
                textFieldSouth.requestFocus();
            }
            });
    }
} 

}
/*javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
}
}); */

2 个答案:

答案 0 :(得分:4)

为了避免重大问题,您应该重新设计应用程序的控制权。

如果没有GUI,您可以直接控制流程:等待输入,处理,显示结果,重复。

使用GUI,您将显示一个窗口,然后不执行任何操作。当用户输入内容时,GUI会调用您的一种回调方法,并根据您当前的状态做出反应。

所以:不要试图拥有一个控制线程,很容易遇到很多线程问题。设置一些变量,告诉你当前游戏状态是什么(等待“START”关键字,等待猜测,完成......),并在用户做某事时更新它们。

答案 1 :(得分:3)

你已经完全翻译了一个主循环结构,它非常适合于命令行应用程序。然后,您将自己沉浸在主线程中的无限循环中,寻找共享变量的变化。这与Swing管理事物的方式相冲突,应用程序的主线程对于Swing管理其重新绘制及其事件处理至关重要,并且您的代码正在与处理器竞争。我认为我们可以为Swing应用程序考虑更好的设计。

你有2个可能性:

  • 您可以使用原始命令行程序,只需将键盘上的任何读数替换为模态对话框,要求输入一个字母。这样您就可以尊重顺序设计并避免出现多线程问题。
  • 或者我最喜欢的:我建议您考虑将顺序设计完全改变为响应式设计。在这种情况下,您放弃到主循环,只需用您的UI在JFrame中显示JPanel,然后只需为每个按钮编写响应事件处理程序或更改输入。您应该将程序的状态存储到主类中,并且事件处理程序与它进行交互。

顺便说一句,无论你做出什么决定,我都强烈建议你删除所有invokeLater(new Runnable()...),这是不必要的,也许是危险的(你可以通过这样做来介绍你的事件处理程序之间的竞争条件)