简体   繁体   中英

How to implement the wait(); statement properly?

I'm getting an issue when I'm trying to make a tic tac toe game. The Issue that I'm coming across is presented when I'm trying to use a wait(); statement in order to pause the game so the player is able to look at who won the game and what the winning squares are, however when I try to run this little chunk of code right here:

            wait(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

It gives me this error code right here:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at GameCode.restart(GameCode.java:264)
    at GameCode.xWins(GameCode.java:245)
    at GameCode.check(GameCode.java:171)
    at GameCode.actionPerformed(GameCode.java:70)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

It describes it to be an IllegalMonitorStateException , however I tried using throw to resolve this problem but it still continues to give me this error. Any solutions out there? For reference here is my code if you need to see any other info:

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

public class GameCode implements ActionListener {
    
    Random random = new Random();
    JFrame frame = new JFrame();
    JPanel title_panel = new JPanel();
    JPanel button_panel = new JPanel();
    JLabel textfield = new JLabel();
    JButton[] buttons = new JButton[9];
    boolean player1_turn;
    
    
    
    
    GameCode() {
        
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,500);
        frame.getContentPane().setBackground(new Color(0,0,0));
        frame.setLayout(new BorderLayout());
        frame.setVisible(true);
        
        textfield.setBackground(new Color(25,25,25));
        textfield.setForeground(new Color(25,255,0));
        textfield.setFont(new Font("TimesRoman", Font.BOLD,75));
        textfield.setHorizontalAlignment(JLabel.CENTER);
        textfield.setText("Tic Tac Toe");
        textfield.setOpaque(true);
        title_panel.setLayout(new BorderLayout());
        title_panel.setBounds(0,0,800,100);
        
        button_panel.setLayout(new GridLayout(3,3));
        button_panel.setBackground(new Color(150,25,25));
        
        for(int j = 0; j < 9; j++ ) {
            
            buttons[j] = new JButton();
            button_panel.add(buttons[j]);
            buttons[j].setFont(new Font("Ink Free", Font.BOLD,120));
            buttons[j].setFocusable(false);
            buttons[j].addActionListener(this);
            
        }
        
        
        title_panel.add(textfield);
        frame.add(title_panel, BorderLayout.NORTH);
        frame.add(button_panel);
        
        Turnone();
        
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        
        for (int i = 0; i < 9; i++) {
            
            if(arg0.getSource()==buttons[i]) {
                if(player1_turn) {
                    if(buttons[i].getText()=="") {
                        buttons[i].setForeground(new Color(255,0,0));
                        buttons[i].setText("X");
                        player1_turn=false;
                        textfield.setText("O turn");
                        check();
                    }
                } else {
                    if(buttons[i].getText()=="") {
                        buttons[i].setForeground(new Color(0,0,255));
                        buttons[i].setText("O");
                        player1_turn=true;
                        textfield.setText("X turn");
                        check();
                    }
                }
            }
        }
    }//Creating the Buttons the player will interact with
    
    public void Turnone() {
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(false);
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(true);
        }
        
        if(random.nextInt(2)==0) {
            
            player1_turn = true;
            textfield.setText("X turn");
            
        } else {
            
            player1_turn = false;
            textfield.setText("O Turn");
            
        }
        
    }//Using a random int to decide which player will go first
    
    public void check() {
        //X Wins
        
        if(
                (buttons[0].getText()=="X") &&
                (buttons[1].getText()=="X") &&
                (buttons[2].getText()=="X") 
                ) {
            xWins(0,1,2);
        }
        if(
                (buttons[3].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[5].getText()=="X") 
                ) {
            xWins(3,4,5);
        }
        if(
                (buttons[6].getText()=="X") &&
                (buttons[7].getText()=="X") &&
                (buttons[8].getText()=="X") 
                ) {
            xWins(6,7,8);
        }
        if(
                (buttons[0].getText()=="X") &&
                (buttons[3].getText()=="X") &&
                (buttons[6].getText()=="X") 
                ) {
            xWins(0,3,6);
        }
        if(
                (buttons[1].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[7].getText()=="X") 
                ) {
            xWins(1,4,7);
        }
        if(
                (buttons[2].getText()=="X") &&
                (buttons[5].getText()=="X") &&
                (buttons[8].getText()=="X") 
                ) {
            xWins(2,5,8);
        }
        if(
                (buttons[0].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[8].getText()=="X") 
                ) {
            xWins(0,4,8);
        }
        if(
                (buttons[2].getText()=="X") &&
                (buttons[4].getText()=="X") &&
                (buttons[6].getText()=="X") 
                ) {
            xWins(2,4,6);
        }
        //O Wins
        
        if(
                (buttons[0].getText()=="O") &&
                (buttons[1].getText()=="O") &&
                (buttons[2].getText()=="O") 
                ) {
            oWins(0,1,2);
        }
        if(
                (buttons[3].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[5].getText()=="O") 
                ) {
            oWins(3,4,5);
        }
        if(
                (buttons[6].getText()=="O") &&
                (buttons[7].getText()=="O") &&
                (buttons[8].getText()=="O") 
                ) {
            oWins(6,7,8);
        }
        if(
                (buttons[0].getText()=="O") &&
                (buttons[3].getText()=="O") &&
                (buttons[6].getText()=="O") 
                ) {
            oWins(0,3,6);
        }
        if(
                (buttons[1].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[7].getText()=="O") 
                ) {
            oWins(1,4,7);
        }
        if(
                (buttons[2].getText()=="O") &&
                (buttons[5].getText()=="O") &&
                (buttons[8].getText()=="O") 
                ) {
            oWins(2,5,8);
        }
        if(
                (buttons[0].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[8].getText()=="O") 
                ) {
            oWins(0,4,8);
        }
        if(
                (buttons[2].getText()=="O") &&
                (buttons[4].getText()=="O") &&
                (buttons[6].getText()=="O") 
                ) {
            oWins(2,4,6);
        }
    
    }//Stating all the win conditions for the game
    
    public void xWins(int a, int b, int c) {
        buttons[a].setBackground(Color.GREEN);
        buttons[b].setBackground(Color.GREEN);
        buttons[c].setBackground(Color.GREEN);
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(false);
        }
        
        textfield.setText("X Wins!");
        
        restart();
    }//When Player X wins
    
    public void oWins(int a, int b, int c) {
        buttons[a].setBackground(Color.GREEN);
        buttons[b].setBackground(Color.GREEN);
        buttons[c].setBackground(Color.GREEN);
        
        for(int i=0; i<9;i++) {
            buttons[i].setEnabled(false);
        }
        textfield.setText("O Wins!");
        
        restart();
    }//When Player O wins 
    
    public void restart() { 
        
        try {
            wait(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        
    }
    
    
    
}//GameCode

Here is a simple example using a swing Timer.

public void restart() { 
    Timer t = new Timer( 1000, evt->{
        //reset and enable the board.
        for(int i=0; i<9;i++) {
            buttons[i].setText("_");
            buttons[i].setEnabled(true);
        }
    }
    t.setRepeats(false);
    t.start();
}

This creates a new timer each time and doesn't keep track of it. So there are definite improvements to managing the code. It hopefully illustrates a way to schedule events in swing.

The error you are getting with the wait code is because you have to be synchronized on an object to call wait on it. You could replace your wait call to a wait + synchronize to remove the error, but it is not good practice and will make your gui non-responsive while the EDT is waiting.

synchronize(this){
    wait(1000); 
}

You are doing too much on the event thread including checking for wins and waiting. So the following changes will work in a pinch.

First, put the entire body of the actionPerformed method in a separate thread.

    @Override
    public void actionPerformed(ActionEvent arg0) {
        new Thread(()-> {
        for (int i = 0; i < 9; i++) {
            
            if(arg0.getSource()==buttons[i]) {
                if(player1_turn) {
                    if(buttons[i].getText().equals("")) {
                        buttons[i].setForeground(new Color(255,0,0));
                        buttons[i].setText("X");
                        player1_turn=false;
                        textfield.setText("O turn");
                        check();
                    }
                } else {
                    if(buttons[i].getText().equals("")) {
                        buttons[i].setForeground(new Color(0,0,255));
                        buttons[i].setText("O");
                        player1_turn=true;
                        textfield.setText("X turn");
                        check();
                    }
                }
            }
        }
        }).start();
    }

Then it will be safe to use sleep in your restart method. You could also use a Swing Timer but it is still important to not do too much processing on the event thread.

public void restart() {
   try {
       Thread.sleep(2000);
   } catch (InterruptedException ie) {
   }
   System.out.println("Waking up");
  
}

But your overall approach has some issues when it comes to painting and handling events. You should check out the Java Tutorials for more on painting and event processing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM