我正在尝试创建一个允许用户玩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>
答案 0 :(得分:0)
我设法解决了我的问题,显然在我的GUI方法结束时调用revalidate()是必须的,否则屏幕不会更新,即使JFrame成功添加新组件。