Skip to content

Where to put another method in Swing UI thread

I’m making a 2-player Tic-Tac-Toe game in Java using Swing. The UI works as expected but I cannot get it to check for a winner.

I have made three classes Main, gui, and winnerDisplay. The gui class does is responsible for creating a 3×3 grid and buttons, etc. The winnerDisplay class is intended as a display prompt congratulating the winner. I’m assuming the first player chooses ‘X’ symbol. Also the 3×3 grid is numbered from 0 to 8 in a row major fashion. (The word grid here is used in a general sense and not in the GridLayout / 2D matrix sense).

I want to check after each turn of each player whether there is a winner (I will optimise it later because there can only be a winner after at least three moves). If there is a winner or a draw I want another window to pop up and display the name of the winner.

Now the problem : No matter where I place isWon() method, it doesn’t stop the game’s main UI thread and does not check it after every move. I know that UI runs on a different thread but how do I achieve my objective?

This is the Main class :

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package tictactoeDivyanshuVarma;

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

/**
 *
 * @author divyanshuvarma
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    static boolean playerOneTurn = true;
    static boolean isFilled0 = false, isFilled1 = false, isFilled2 = false;
    static boolean isFilled3 = false, isFilled4 = false, isFilled5 = false;
    static boolean isFilled6 = false, isFilled7 = false, isFilled8 = false;
    //static JButton button;
    static boolean gameWon = false;

    public static void main(String[] args) {
        // TODO code application logic here
        gui board = new gui();
        winnerDisplay winnerDisplayWindow = new winnerDisplay();
        setBoardProperties(board);
        initializeBoard(board);
        initializeGame(board);
       /* if (isWon(board)) {
            winnerDisplayWindow.setVisible(true);
            winnerDisplayWindow.setTitle("Congrats Winner !");
            winnerDisplayWindow.setResizable(false);
            winnerDisplayWindow.setAlwaysOnTop(true);
            JLabel winnerLabel = new JLabel("Winner is ");
            winnerDisplayWindow.setWinnerLabel(winnerLabel);
        }*/
        System.out.println("nThread count: "+Thread.activeCount());
    }

    public static void setBoardProperties(gui board) {
        board.setVisible(true);
        board.setTitle("Tic-Tac-Toe (2-player)");
        board.setResizable(false);
    }

    public static void initializeGame(gui board) {
        JButton button0, button1, button2, button3, button4, button5, button6, button7, button8;
        button0 = board.getButton0();
        button0.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled0) {
                    if (playerOneTurn) {
                        button0.setText("X");
                    } else {
                        button0.setText("O");
                    }
                    isFilled0 = true;
                    // I HAVE TRIED PLACING isWon() HERE   
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button1 = board.getButton1();
        button1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled1) {
                    if (playerOneTurn) {
                        button1.setText("X");
                    } else {
                        button1.setText("O");
                    }
                    isFilled1 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button2 = board.getButton2();
        button2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled2) {
                    if (playerOneTurn) {
                        button2.setText("X");
                    } else {
                        button2.setText("O");
                    }
                    isFilled2 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button3 = board.getButton3();
        button3.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled3) {
                    if (playerOneTurn) {
                        button3.setText("X");
                    } else {
                        button3.setText("O");
                    }
                    isFilled3 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button4 = board.getButton4();
        button4.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled4) {
                    if (playerOneTurn) {
                        button4.setText("X");
                    } else {
                        button4.setText("O");
                    }
                    isFilled4 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button5 = board.getButton5();
        button5.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled5) {
                    if (playerOneTurn) {
                        button5.setText("X");
                    } else {
                        button5.setText("O");
                    }
                    isFilled5 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button6 = board.getButton6();
        button6.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled6) {
                    if (playerOneTurn) {
                        button6.setText("X");
                    } else {
                        button6.setText("O");
                    }
                    isFilled6 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button7 = board.getButton7();
        button7.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled7) {
                    if (playerOneTurn) {
                        button7.setText("X");
                    } else {
                        button7.setText("O");
                    }
                    isFilled7 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });
        button8 = board.getButton8();
        button8.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isFilled8) {
                    if (playerOneTurn) {
                        button8.setText("X");
                    } else {
                        button8.setText("O");
                    }
                    isFilled8 = true;
                    // I HAVE TRIED PLACING isWon() HERE 
                    if (playerOneTurn) {
                        playerOneTurn = false;
                    } else {
                        playerOneTurn = true;
                    }
                }
            }
        });// I HAVE TRIED PLACING isWon() HERE TOO
    }

    public static boolean isWon(gui board) {
        String symbol0, symbol1, symbol2, symbol3, symbol4, symbol5, symbol6, symbol7, symbol8;
        symbol0 = board.getButton0().getText();
        symbol1 = board.getButton1().getText();
        symbol2 = board.getButton2().getText();
        symbol3 = board.getButton3().getText();
        symbol4 = board.getButton4().getText();
        symbol5 = board.getButton5().getText();
        symbol6 = board.getButton6().getText();
        symbol7 = board.getButton7().getText();
        symbol8 = board.getButton8().getText();
        if (symbol0.equals(symbol4) && symbol4.equals(symbol8)) //main diagonal
        {
            gameWon = true;
        }
        if (symbol2.equals(symbol4) && symbol4.equals(symbol6)) //other diagonal
        {
            gameWon = true;
        }
        if (symbol0.equals(symbol1) && symbol1.equals(symbol2)) //first row
        {
            gameWon = true;
        }
        if (symbol3.equals(symbol4) && symbol4.equals(symbol5)) //second row
        {
            gameWon = true;
        }
        if (symbol6.equals(symbol7) && symbol7.equals(symbol8)) //third row
        {
            gameWon = true;
        }
        if (symbol0.equals(symbol3) && symbol3.equals(symbol6)) //first column
        {
            gameWon = true;
        }
        if (symbol1.equals(symbol4) && symbol4.equals(symbol7)) //second column
        {
            gameWon = true;
        }
        if (symbol2.equals(symbol5) && symbol5.equals(symbol8)) //third column
        {
            gameWon = true;
        }
        if (gameWon) {
            return true;
        } else {
            return false;
        }
    }

    public static void initializeBoard(gui board) {
        JButton button;
        button = board.getButton0();
        button.setText("");
        button = board.getButton1();
        button.setText("");
        button = board.getButton2();
        button.setText("");
        button = board.getButton3();
        button.setText("");
        button = board.getButton4();
        button.setText("");
        button = board.getButton5();
        button.setText("");
        button = board.getButton6();
        button.setText("");
        button = board.getButton7();
        button.setText("");
        button = board.getButton8();
        button.setText("");
    }
}

This is the gui class :

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package tictactoeDivyanshuVarma;

import javax.swing.JButton;

/**
 *
 * @author divyanshuvarma
 */
public class gui extends javax.swing.JFrame {

    /**
     * Creates new form gui
     */
    public gui() {
        initComponents();
    }

    public void setButton0Text(String symbol) {
        this.button0.setText(symbol);
    }

    public void setButton1Text(String symbol) {
        this.button1.setText(symbol);
    }

    public void setButton2Text(String symbol) {
        this.button2.setText(symbol);
    }

    public void setButton3Text(String symbol) {
        this.button3.setText(symbol);
    }

    public void setButton4Text(String symbol) {
        this.button4.setText(symbol);
    }

    public void setButton5Text(String symbol) {
        this.button5.setText(symbol);
    }

    public void setButton6Text(String symbol) {
        this.button6.setText(symbol);
    }

    public void setButton7Text(String symbol) {
        this.button7.setText(symbol);
    }

    public void setButton8Text(String symbol) {
        this.button8.setText(symbol);
    }

    public JButton getButton0() {
        return button0;
    }

    public JButton getButton1() {
        return button1;
    }

    public JButton getButton2() {
        return button2;
    }

    public JButton getButton3() {
        return button3;
    }

    public JButton getButton4() {
        return button4;
    }

    public JButton getButton5() {
        return button5;
    }

    public JButton getButton6() {
        return button6;
    }

    public JButton getButton7() {
        return button7;
    }

    public JButton getButton8() {
        return button8;
    }

    
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        button1 = new javax.swing.JButton();
        button3 = new javax.swing.JButton();
        button5 = new javax.swing.JButton();
        button2 = new javax.swing.JButton();
        button6 = new javax.swing.JButton();
        button8 = new javax.swing.JButton();
        button4 = new javax.swing.JButton();
        button0 = new javax.swing.JButton();
        button7 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        button1.setText("jButton1");
        button1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button1ActionPerformed(evt);
            }
        });

        button3.setText("jButton1");

        button5.setText("jButton1");

        button2.setText("jButton1");

        button6.setText("jButton1");

        button8.setText("jButton1");

        button4.setText("jButton1");

        button7.setText("jButton1");

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(button0, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGap(72, 72, 72)
                        .addComponent(button1))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(button3)
                        .addGap(72, 72, 72)
                        .addComponent(button4))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(button6)
                        .addGap(72, 72, 72)
                        .addComponent(button7)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 79, Short.MAX_VALUE)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(button8, javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(button5, javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(button2, javax.swing.GroupLayout.Alignment.TRAILING))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(button0, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(button1, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(button2, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(18, 18, Short.MAX_VALUE)
                        .addComponent(button8, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(32, 32, 32)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(button3, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(button4, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(button5, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 55, Short.MAX_VALUE)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(button6, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(button7, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE))))
                .addContainerGap())
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        );

        pack();
    }// </editor-fold>                        

    private void button1ActionPerformed(java.awt.event.ActionEvent evt) {                                        
        // TODO add your handling code here:
    }                                       

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(gui.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new gui().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton button0;
    private javax.swing.JButton button1;
    private javax.swing.JButton button2;
    private javax.swing.JButton button3;
    private javax.swing.JButton button4;
    private javax.swing.JButton button5;
    private javax.swing.JButton button6;
    private javax.swing.JButton button7;
    private javax.swing.JButton button8;
    private javax.swing.JPanel jPanel1;
    // End of variables declaration                   
}

This is the winnerDisplay class :

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package tictactoeDivyanshuVarma;

import javax.swing.JLabel;

/**
 *
 * @author divyanshuvarma
 */
public class winnerDisplay extends javax.swing.JFrame {

    /**
     * Creates new form winnerDisplay
     */
    public winnerDisplay() {
        initComponents();
    }

    public JLabel getWinnerLabel() {
        return winnerLabel;
    }

    public void setWinnerLabel(JLabel winnerLabel) {
        this.winnerLabel = winnerLabel;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        winnerLabel = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        winnerLabel.setText("jLabel1");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(77, 77, 77)
                .addComponent(winnerLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(80, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(82, Short.MAX_VALUE)
                .addComponent(winnerLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 124, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(94, 94, 94))
        );

        pack();
    }// </editor-fold>                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(winnerDisplay.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(winnerDisplay.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(winnerDisplay.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(winnerDisplay.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new winnerDisplay().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JLabel winnerLabel;
    // End of variables declaration                   
}

Answer

The code construct looks good, dont see why the method isWon – is not called. Step through your code in debug – to understand more.

The anonymous action listener will have visibility to the static method defined in the class.

The winnerDisplay frame can be called from within isWon() method, and if you use a dialog instead of a JFrame for the alert – you would get the feedback from the user to terminate the program.