每当我回到游戏的介绍屏幕时,Java applet都会冻结

时间:2015-03-30 06:46:46

标签: java swing applet freeze

我正在尝试创建一个允许用户玩20个问题游戏的java小程序,但是当游戏结束并且我点击重放游戏时,它会在它应该返回到介绍屏幕时冻结。我在下面提供了我的代码:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

import java.util.ArrayList;




//json classes
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;




//google classes
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;

public class Interface extends JPanel implements ActionListener, PropertyChangeListener{
    //removes serialization warning
    private static final long serialVersionUID = 1L;
    /**Instances for the Buttons**/
    private JButton noButton;
    private JButton yesButton;
    private JButton unsureButton;
    private JButton replayButton;
    private JButton newGame;
    private JButton addQuestion; 
    /**Instances for the text used**/
    private JLabel questionLabel;
    /**Instances for the dialog boxes**/
    private JDialog addQuestionDialog;
    private JOptionPane addQuestionPane;
    private JDialog nameDialog;
    private JOptionPane namePane;
    /**Instances for the textfields**/
    private TextField questionTextField;
    private TextField mqlYesTextField;
    private TextField mqlNoTextField;
    private TextField nameTextField;
    /**Instance for keeping track of game state**/
    private boolean isGameOver = false;
    /**keeps track of the current and previous questions**/
    private int currentQuestionId = 1, previousQuestionId = 1;
    /**Instances of Arraylist**/
    private ArrayList<Integer> alreadyAskedQuestions;
    private ArrayList<Integer> columnValues;
    /**number of questions asked to the user so far**/;
    private int questionsAsked = 1;
    private JSONArray mqlResults = null;

    private Model sqlModel;
    private String mqlQuery = "[{\"name\":null, \"limit\":5";

    /**Constructor**/
    public Interface(){
        super();
        sqlModel = new Model();

        questionTextField = new TextField(50);
        mqlYesTextField = new TextField(100);
        mqlNoTextField = new TextField(100);

        alreadyAskedQuestions = new ArrayList<Integer>(21);
        columnValues = new ArrayList<Integer>(21);
        initGUI();
    }

    public void initGUI() {
        setLayout(new GridBagLayout());
        removeAll();

        JLabel introLabel = createIntroLabel();
        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.BOTH;
        add(introLabel,c);
        GridBagConstraints d = new GridBagConstraints();
        d.fill = GridBagConstraints.BOTH;
        d.ipady = 200;
        d.gridx = 0;
        d.gridy = 1;
        d.weighty = 0.5;
        add(createMainPanel(),d);
    }

    public JPanel createMainPanel() {
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new GridLayout(1,3));

        JPanel recentSearchesPanel = new JPanel();
        recentSearchesPanel.setLayout(new GridLayout(6,1));
        recentSearchesPanel.setBackground(Color.BLACK);
        //create Recent searches text
        JLabel recentSearchText = new JLabel("Recent searches:");
        recentSearchText.setForeground(Color.WHITE);
        recentSearchText.setFont(new Font("Gabriola",Font.BOLD,30));
        //add text into Panel
        recentSearchesPanel.add(recentSearchText);
        ArrayList<String> recentSearches = sqlModel.getRecentSearches();
        for(int i=0; i<recentSearches.size(); i++) {
            JLabel label = new JLabel(recentSearches.get(i));
            label.setForeground(Color.WHITE);
            label.setFont(new Font("Gabriola",Font.BOLD,30));
            label.setHorizontalAlignment(SwingConstants.CENTER);
            recentSearchesPanel.add(label);
        }
        //add recent searches in the leftmost column of the main panel
        mainPanel.add(recentSearchesPanel);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridBagLayout());
        buttonPanel.setBackground(Color.BLACK);
        newGame = new JButton(new ImageIcon("src\\Icons\\icon_play_en.png"));
        newGame.setBackground(Color.BLACK);
        newGame.setOpaque(true);
        newGame.addActionListener(this);
        buttonPanel.add(newGame);
        GridBagConstraints d = new GridBagConstraints();
        d.fill = GridBagConstraints.HORIZONTAL;
        d.gridy = 1;
        addQuestion = new JButton(new ImageIcon("src\\Icons\\icon_addQuestion.png"));
        addQuestion.setBackground(Color.BLACK);
        addQuestion.setOpaque(true);
        addQuestion.addActionListener(this);
        buttonPanel.add(addQuestion,d);
        mainPanel.add(buttonPanel);

        JPanel popularSearchesPanel = new JPanel();
        popularSearchesPanel.setLayout(new GridLayout(6,1));
        popularSearchesPanel.setBackground(Color.BLACK);
        JLabel popularSeachText = new JLabel("Popular searches:");
        popularSeachText.setFont(new Font("Gabriola",Font.BOLD,30));
        popularSeachText.setForeground(Color.WHITE);
        popularSearchesPanel.add(popularSeachText);

        ArrayList<String> popularSearches = sqlModel.getPopularSearches();
        for(int i=0; i<popularSearches.size(); i++) {
            JLabel label = new JLabel(popularSearches.get(i));
            label.setForeground(Color.WHITE);
            label.setFont(new Font("Gabriola",Font.BOLD,30));
            label.setHorizontalAlignment(SwingConstants.CENTER);
            recentSearchesPanel.add(label);
        }
        mainPanel.add(popularSearchesPanel);

        return mainPanel;
    }

    /**The initGUI method will create the GUI and hold all its components**/
    public void gameGUI(){
        //the layout is a new BorderLayout
        setLayout(new GridLayout(4,1));

        //clear all components currently in panel
        removeAll();

        add(createIntroLabel());
        mqlResults = getMQLData(mqlQuery + "}]");
        //are we in game over state
        isGameOver = ((mqlResults != null) && ( (mqlResults.size() <= 1) || (questionsAsked == 20) ));

        add(createQuestionsPanel(isGameOver));
        add(createGuessedPanel());
        add(createAnswerButtonPanel());
        //calling revalidate, avoids an error of the programme freezing
        revalidate();
    }

    /**Create a panel which holds the labels and the button that will change the labels color **/
    private JLabel createIntroLabel()
    {   
        JLabel introLabel = new JLabel("Twenty Questions");
        introLabel.setBackground(Color.BLACK);
        introLabel.setForeground(Color.WHITE);
        introLabel.setFont(new Font("Forte",Font.BOLD,108));
        introLabel.setOpaque(true);
        return introLabel;
    }

    /**The createQuestions method will display the current question at the time**/
    private JPanel createQuestionsPanel(boolean gameOver){
        //Create a new panel
        JPanel questionPanel = new JPanel();
        questionPanel.setBackground(Color.BLACK);
        questionPanel.setLayout(new BorderLayout());

        if(gameOver) {
            if(mqlResults.size() > 0)
                questionLabel = new JLabel("is your Character: "+((JSONObject)mqlResults.get(0)).get("name") );
            else //noone was found
                questionLabel = new JLabel("couldn't find any matches :(");

            //addQuestion();
        }
        else
            questionLabel = new JLabel("Q"+questionsAsked+": "+sqlModel.getData("questionid","questionid = "+currentQuestionId, 2));

        //make the label centred
        questionLabel.setHorizontalAlignment(SwingConstants.CENTER);
        //the Foreground is white
        questionLabel.setForeground(Color.WHITE);
        questionLabel.setFont(new Font("Comic Sans MS",Font.PLAIN,30));
        //add Label to the panel
        questionPanel.add(questionLabel);

        //return questionPanel
        return questionPanel;
    }

    private JPanel createGuessedPanel() {
        JPanel guessedPanel = new JPanel();
        guessedPanel.setLayout(new GridLayout(5,1));
        guessedPanel.setBackground(Color.BLACK);
        System.out.println(mqlQuery);

        if((questionsAsked > 1) && (mqlResults.size() > 0)) {
            for (Object result : mqlResults) {
                JLabel resultLabel = new JLabel((String)((JSONObject)result).get("name"));
                resultLabel.setHorizontalAlignment(SwingConstants.CENTER);
                resultLabel.setForeground(Color.WHITE);
                resultLabel.setFont(new Font("Comic Sans MS",Font.PLAIN,30));
                guessedPanel.add(resultLabel);
            }
        }
        return guessedPanel;
    }

    private JPanel createAnswerButtonPanel()
    {
        JPanel answerPanel = new JPanel();
        answerPanel.setLayout(new GridLayout(1,3));

        //MQL query couldn't find any results
        if ( (mqlResults != null) && (mqlResults.size() == 0) ) {
            replayButton = new JButton(new ImageIcon(getClass().getResource("/Icons/replay_icon.png")));
            replayButton.setBackground(Color.ORANGE);
            replayButton.setOpaque(true);
            replayButton.addActionListener(this);
            answerPanel.add(replayButton);
        }

        else {
            //the no button will be added to the panel
            noButton = new JButton("NO");
            noButton.setBackground(Color.RED);
            noButton.setOpaque(true);
            Font noFont = new Font("Bauhaus 93",Font.BOLD,30);
            noButton.setFont(noFont);
            noButton.addActionListener(this);
            answerPanel.add(noButton);

            //if the initial question has already been asked, create an unsure button
            if( (questionsAsked > 1) && !isGameOver )
            {
                unsureButton = new JButton("UNSURE");
                unsureButton.setBackground(Color.ORANGE);
                unsureButton.setOpaque(true);
                Font maybeFont = new Font("Bauhaus 93",Font.BOLD,30);
                unsureButton.setFont(maybeFont);
                unsureButton.addActionListener(this);
                answerPanel.add(unsureButton);
            }

            //the yes button will be added to the panel             
            yesButton = new JButton("YES");
            Font yesFont = new Font("Bauhaus 93",Font.BOLD,30);
            yesButton.setFont(yesFont);
            yesButton.setBackground(Color.GREEN);
            yesButton.setOpaque(true);
            yesButton.addActionListener(this);
            answerPanel.add(yesButton);
            //return answerPanel
        }
        return answerPanel; 
    }

    private int getNextQuestionId(int previousQuestionId) {
        int result;
        while(true) {
            double random = Math.random();
            result = sqlModel.chooseQuestion(previousQuestionId, random);
            //if question selected has already been asked in this game session
            System.out.println(alreadyAskedQuestions);

            if(alreadyAskedQuestions.contains(result)) {
                /*int value = Integer.parseInt(sqlModel.getData("questionvalues", "questionid = "+result, previousQuestionId + 1));
                if(value>=5) {
                    value = value - 5;
                    //change value in (result, previousQuestionId) cell
                    sqlModel.updateEntry("questionvalues", "`"+previousQuestionId+"` = "+value, "questionid = "+result);
                    int previousTotal = Integer.parseInt(sqlModel.getData("questionvalues", "questionid = 5000", previousQuestionId+1));
                    int newTotal = previousTotal - 5;
                    //decrement total value by 5, in the previousQuestionId column
                    sqlModel.updateEntry("questionvalues", "`"+previousQuestionId+"` = "+newTotal, "questionid = 5000");
                }*/
            }
            else
                return result;
        }
    }

    private JSONArray getMQLData(String query) {
        JSONArray results = null;
        try {
              HttpTransport httpTransport = new NetHttpTransport();
              HttpRequestFactory requestFactory = httpTransport.createRequestFactory();
              JSONParser parser = new JSONParser();
              GenericUrl url = new GenericUrl("https://www.googleapis.com/freebase/v1/mqlread");
              url.put("query", query);
              url.put("key", "AIzaSyAA0uodQOasgTIaGRHUeoKwnfS-FVoDxJc");
              HttpRequest request = requestFactory.buildGetRequest(url);
              HttpResponse httpResponse = request.execute();
              JSONObject response = (JSONObject)parser.parse(httpResponse.parseAsString());
              results = (JSONArray)response.get("result");
        } catch (Exception ex) {
          ex.printStackTrace();
        }
        return results;
    }

    private void addQuestion() {
        questionTextField = new TextField(50);

        Object[] componentsArray = {"Question:", questionTextField, "MQLYes:", mqlYesTextField, "MQLNo:", mqlNoTextField};
        Object[] options = {"Enter", "Cancel"};
        addQuestionDialog = new JDialog(new JFrame(),"Add question");
        addQuestionPane = new JOptionPane(componentsArray, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null, options, options[0]);

        int x = getX() + getWidth()/2, y = getY() + getHeight()/2;

        addQuestionDialog.setContentPane(addQuestionPane);
        addQuestionDialog.setResizable(false);
        addQuestionDialog.setSize(300,210);
        addQuestionDialog.setVisible(true);
        addQuestionDialog.setLocation(x, y);
        addQuestionDialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);

        addQuestionPane.addPropertyChangeListener(this);
    }

    /** This method reacts to state changes in the option pane. */
    public void propertyChange(PropertyChangeEvent e) {
        String prop = e.getPropertyName();

        if (addQuestionDialog.isVisible() && (e.getSource() == addQuestionPane) && (JOptionPane.VALUE_PROPERTY.equals(prop) || JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
            Object value = addQuestionPane.getValue();

            if (value == JOptionPane.UNINITIALIZED_VALUE) {
                //ignore reset
                return;
            }

            //Reset the JOptionPane's value.
            //If you don't do this, then if the user
            //presses the same button next time, no
            //property change event will be fired.
            addQuestionPane.setValue(
                JOptionPane.UNINITIALIZED_VALUE);

            if (value.equals("Enter")) {
                String questionTypedText = questionTextField.getText();
                String mqlYesTypedText = mqlYesTextField.getText();
                String mqlNoTypedText = mqlNoTextField.getText();

                sqlModel.addQuestion(questionTypedText, mqlYesTypedText, mqlNoTypedText);
                questionTextField.setText("");
                mqlYesTextField.setText("");
                mqlNoTextField.setText("");
            } else { //user closed dialog or clicked cancel
                addQuestionDialog.setVisible(false);
            }
        }

        else if (nameDialog.isVisible() && (e.getSource() == namePane) && (JOptionPane.VALUE_PROPERTY.equals(prop) || JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
            Object value = namePane.getValue();

            if (value == JOptionPane.UNINITIALIZED_VALUE) {
                //ignore reset
                return;
            }

            namePane.setValue(
                JOptionPane.UNINITIALIZED_VALUE);

            if (value.equals("Enter")) {
                sqlModel.addCelebrity(alreadyAskedQuestions, columnValues, nameTextField.getText());
            }
            //else, user clicked cancel, in either case, close the Dialog box
            nameDialog.setVisible(false);
            mqlQuery = "[{\"name\":null, \"limit\":5";
            isGameOver = false;
            initGUI();
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource().equals(newGame)) {
            gameGUI();
        }

        else if(e.getSource().equals(addQuestion)) {
            addQuestion();
        }

        //if you press the no button
        else if (e.getSource().equals(noButton)) {
            if(!isGameOver) {
                //don't update questionvalues for this case
                alreadyAskedQuestions.add(currentQuestionId);
                columnValues.add(-1);

                //update MQLQuery
                String s = sqlModel.getData("questionid", "questionid = "+currentQuestionId, 4);
                if( (questionsAsked > 1) && !s.equals("") )
                    mqlQuery = mqlQuery + ", \"ms"+questionsAsked+":"+s;
                else
                    mqlQuery = mqlQuery + s;

                currentQuestionId = getNextQuestionId(previousQuestionId);
                questionsAsked++;
                gameGUI();
            }
            else {
                //create new JOptionPane asking for celebrity name
                nameTextField = new TextField(50);

                Object[] componentsArray = {"Please enter your characters name:", questionTextField};
                Object[] options = {"Enter", "Cancel"};
                nameDialog = new JDialog();
                namePane = new JOptionPane(componentsArray, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null, options, options[0]);

                int x = getX() + getWidth()/2, y = getY() + getHeight()/2;

                nameDialog.setContentPane(namePane);
                nameDialog.setResizable(false);
                nameDialog.setSize(300,210);
                nameDialog.setVisible(true);
                nameDialog.setLocation(x, y);
                nameDialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);

                addQuestionPane.addPropertyChangeListener(this);
            }
        }

        //if you pressed the yes button
        else if (e.getSource().equals(yesButton)) {
            if(isGameOver) {
                String name = ""+((JSONObject)mqlResults.get(0)).get("name");
                sqlModel.addCelebrity(alreadyAskedQuestions, columnValues, name);
                mqlQuery = "[{\"name\":null, \"limit\":5";
                isGameOver = false;
                initGUI();
            }
            else {
                //update the value in the questionValues table
                if(previousQuestionId != currentQuestionId) {
                    int value = Integer.parseInt(sqlModel.getData("questionvalues", "questionid = "+currentQuestionId, previousQuestionId + 1));
                    value += 5;
                    //back ticks around previousQuestionId, so SQL compiler knows it's a column name
                    //change value in (currentQuestionId, previousQuestionId) cell
                    sqlModel.updateEntry("questionvalues", "`"+previousQuestionId+"` = "+value, "questionid = "+currentQuestionId);
                    int previousTotal = Integer.parseInt(sqlModel.getData("questionvalues", "questionid = 5000", previousQuestionId+1));
                    int newTotal = previousTotal + 5;
                    //decrement total value by 5, in the previousQuestionId column
                    sqlModel.updateEntry("questionvalues", "`"+previousQuestionId+"` = "+newTotal, "questionid = 5000");
                }
                alreadyAskedQuestions.add(currentQuestionId);
                columnValues.add(1);
                //update MQLQuery
                String s = sqlModel.getData("questionid", "questionid = "+currentQuestionId, 3);
                if(questionsAsked > 1)
                    mqlQuery = mqlQuery + ", \"ms"+questionsAsked+":"+s;
                else
                    mqlQuery = mqlQuery + s;

                if (questionsAsked > 1)
                    previousQuestionId = currentQuestionId;
                currentQuestionId = getNextQuestionId(previousQuestionId);

                questionsAsked++;
                gameGUI();
            }
        }

        //if you pressed the unsure button
        else if (e.getSource().equals(unsureButton)) {
            //update the value in the questionValues table
            if(previousQuestionId != currentQuestionId) {
                int value = Integer.parseInt(sqlModel.getData("questionvalues", "questionid = "+currentQuestionId, previousQuestionId + 1));
                if(value >= 5) {
                    value -= 5;
                    //back ticks around previousQuestionId, so SQL compiler knows it's a column name
                    sqlModel.updateEntry("questionvalues", "`"+previousQuestionId+"` = "+value, "questionid = "+currentQuestionId);
                    //change value in (result, previousQuestionId) cell
                    sqlModel.updateEntry("questionvalues", "`"+previousQuestionId+"` = "+value, "questionid = "+currentQuestionId);
                    int previousTotal = Integer.parseInt(sqlModel.getData("questionvalues", "questionid = 5000", previousQuestionId+1));
                    int newTotal = previousTotal - 5;
                    //decrement total value by 5, in the previousQuestionId column
                    sqlModel.updateEntry("questionvalues", "`"+previousQuestionId+"` = "+newTotal, "questionid = 5000");
                }
            }
            alreadyAskedQuestions.add(currentQuestionId);
            columnValues.add(0);

            if (questionsAsked > 1)
                previousQuestionId = currentQuestionId;
            currentQuestionId = getNextQuestionId(previousQuestionId);
            questionsAsked++;
            gameGUI();
        }

        else if(e.getSource().equals(replayButton)) {
            mqlQuery = "[{\"name\":null, \"limit\":5";
            isGameOver = false;
            initGUI();
        }
    }
}

当游戏结束时,会向用户显示以下屏幕,但点击重播会冻结小程序,当它真正做的就是调用initGUI方法,当applet首次启动时,该方法运行得非常好。我在initGUI方法的末尾添加了一个print语句,当我点击重放时它会显示在我的控制台中,因此代码成功通过initGUI方法,但它不会改变applet的外观。 / p>

1 个答案:

答案 0 :(得分:0)

我设法解决了我的问题,显然在我的GUI方法结束时调用revalidate()是必须的,否则屏幕不会更新,即使JFrame成功添加新组件。