简体   繁体   中英

Whats wrong with this Java code - JLabel doesn't show in JPanel (JFrames)?

The relevent parts of this code causing the problem are in between the ------------ dashes....

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JLabel;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.*;

public class Game3 extends JFrame implements ActionListener {

    private int[][] winCombinations = new int[][]{
            {0, 1, 2}, {3, 4, 5}, {6, 7, 8},  //horizontal wins
            {0, 3, 6}, {1, 4, 7}, {2, 5, 8},  //virticle wins
            {0, 4, 8}, {2, 4, 6}   //diagonal wins
    };

    private JFrame gameWindow = new JFrame("TIC-TAC-TOE");
    private JButton buttons[] = new JButton[9];
    private JPanel biggerPanel;
    private JPanel winnerPanel;
    private int count = 0;
    private String letter = ""; //The player X or O is initialized to empty string
    private boolean win = false;
    public static final int WIDTH = 400;
    public static final int HEIGHT = 300;
    private JLabel winnerLabel = new JLabel("");

    public Game3() {

        gameWindow.setSize(WIDTH, HEIGHT);
        gameWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        gameWindow.setLayout(new BorderLayout());
        JPanel winnerPanel = new JPanel();
        winnerPanel.setBackground(Color.MAGENTA);
        winnerPanel.setLayout(new FlowLayout());
// -----------------------------------------------------------
        win = winBool();
        if (win == true) {
            JLabel winnerLabel = new JLabel(letter + " WINS!");
            winnerPanel.add(winnerLabel);
            gameWindow.add(winnerPanel, BorderLayout.NORTH);
        } else if (count == 9 && win == false) {
            JLabel winnerLabel1 = new JLabel("Tie Game!");
            winnerPanel.add(winnerLabel1);
            gameWindow.add(winnerPanel, BorderLayout.NORTH);
        }
// -----------------------------------------------------------

        JPanel biggerPanel = new JPanel();
        biggerPanel.setLayout(new GridLayout(3, 3));
        gameWindow.add(biggerPanel, BorderLayout.CENTER);
        for (int i = 0; i <= 8; i++) {
            buttons[i] = new JButton();
            buttons[i].setBackground(Color.WHITE);
            biggerPanel.add(buttons[i]);
            buttons[i].addActionListener(this);
        }
        gameWindow.setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        count++;
        if (count == 1 || count == 3 || count == 5 || count == 7 || count == 9) {
            letter = "X";
        } else if (count == 2 || count == 4 || count == 6 || count == 8 || count == 10) {
            letter = "O";
        }

        JButton pressedButton = (JButton) e.getSource();
        pressedButton.setText(letter);
        pressedButton.setEnabled(false);

        for (int i = 0; i <= 7; i++) {
            if (buttons[winCombinations[i][0]].getText().equals(buttons[winCombinations[i][1]].getText())
                    && buttons[winCombinations[i][1]].getText().equals(buttons[winCombinations[i][2]].getText())
                    && buttons[winCombinations[i][0]].getText() != "") {
                win = true;
            }
        }
    }

    // -------------------------------------------------------------------------------------
    public boolean winBool() {
        return win;
    }

    // ----------------------------------------------------------------------------------------
    public static void main(String[] args) {
        Game3 game3 = new Game3();
    }
}

Looks like the code which adds the JLabel objects is in the constructor and will thus only be called once. The conditions which will cause it to add the labels aren't met when the constructor is called and thus no labels are added.

You probably want to extract adding the JLabel objects into a separate function and call it from actionPerformed each time there's an update.

Also, consider whether you need gameWindow given that the Game3 class extends JFrame

1- Why is Game3 extending JFrame when you already have gameWindow ?

2- Replace JLabel winnerLabel = new JLabel(letter + " WINS!"); with winnerLabel = new JLabel(letter + " WINS!"); and JLabel winnerLabel1 = new JLabel("Tie Game!"); with winnerLabel1 = new JLabel("Tie Game!"); as you don't want to create new local variables but assign new objects to the Game3 class's member variables. Also, for the same reason as above, replace JPanel winnerPanel = new JPanel(); with winnerPanel = new JPanel(); .

Apply these changes and let me know what happens next.

In the constructor, you have

if(win == true) {
    JLabel winnerLabel = new JLabel(letter + " WINS!");
    winnerPanel.add(winnerLabel);
    gameWindow.add(winnerPanel, BorderLayout.NORTH);
} else if(count == 9 && win == false){
        JLabel winnerLabel1 = new JLabel("Tie Game!");
        winnerPanel.add(winnerLabel1);
        gameWindow.add(winnerPanel, BorderLayout.NORTH);
}

but, win, is initialized to false, and count to 0. This code part is executed only once, at construction time, so it never change

I think in the constructor, you can have always

winnerPanel.add(winnerLabel);
gameWindow.add(winnerPanel, BorderLayout.NORTH);

and put your condition in the action listener (something like):

public void actionPerformed(ActionEvent e) {
    count++;
    ...//your code here
    if(win == true) {
        winnerLabel.setText(letter + " WINS!");
    } else if(count == 9 && win == false){
        winnerLabel.setText("TIE GAME");
    }
}
public class Test extends JFrame implements ActionListener {

private int[][] winCombinations = new int[][]{
        {0, 1, 2}, {3, 4, 5}, {6, 7, 8},  //horizontal wins
        {0, 3, 6}, {1, 4, 7}, {2, 5, 8},  //virticle wins
        {0, 4, 8}, {2, 4, 6}   //diagonal wins
};

private JFrame gameWindow = new JFrame("TIC-TAC-TOE");
private JButton buttons[] = new JButton[9];
private JPanel biggerPanel;
private JPanel winnerPanel;
private int count = 0;
private String letter = ""; //The player X or O is initialized to empty string
private boolean win = false;
public static final int WIDTH = 400;
public static final int HEIGHT = 300;
private JLabel winnerLabel = new JLabel("");

public Test() {

    gameWindow.setSize(WIDTH, HEIGHT);
    gameWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    gameWindow.setLayout(new BorderLayout());

    JPanel biggerPanel = new JPanel();
    biggerPanel.setLayout(new GridLayout(3, 3));
    gameWindow.add(biggerPanel, BorderLayout.CENTER);
    for (int i = 0; i <= 8; i++) {
        buttons[i] = new JButton();
        buttons[i].setBackground(Color.WHITE);
        biggerPanel.add(buttons[i]);
        buttons[i].addActionListener(this);
    }
    gameWindow.setVisible(true);
}

private void publishResult() {
    JPanel winnerPanel = new JPanel();
    winnerPanel.setBackground(Color.MAGENTA);
    winnerPanel.setLayout(new FlowLayout());

    win = winBool();
    if (win == true) {
        JLabel winnerLabel = new JLabel(letter + " WINS!");
        winnerPanel.add(winnerLabel);
        gameWindow.add(winnerPanel, BorderLayout.NORTH);
    } else if (count == 9 && win == false) {
        JLabel winnerLabel1 = new JLabel("Tie Game!");
        winnerPanel.add(winnerLabel1);
        gameWindow.add(winnerPanel, BorderLayout.NORTH);
    }
    gameWindow.repaint();
}

public void actionPerformed(ActionEvent e) {
    count++;
    if (count == 1 || count == 3 || count == 5 || count == 7 || count == 9) {
        letter = "X";
    } else if (count == 2 || count == 4 || count == 6 || count == 8 || count == 10) {
        letter = "O";
    }

    JButton pressedButton = (JButton) e.getSource();
    pressedButton.setText(letter);
    pressedButton.setEnabled(false);

    for (int i = 0; i <= 7; i++) {
        if (buttons[winCombinations[i][0]].getText().equals(buttons[winCombinations[i][1]].getText())
                && buttons[winCombinations[i][1]].getText().equals(buttons[winCombinations[i][2]].getText())
                && buttons[winCombinations[i][0]].getText() != "") {
            win = true;
            publishResult();
        }
    }
}

public boolean winBool() {
    return win;
}

public static void main(String[] args) {
    Test game3 = new Test();
}  }

Hope this helps!!

Wrong: Piece of code written for adding JLabel (with if/else-if logic) should not be in that place, since constructor will be called only once during the object(in our case, frame) initialization.

Solution: I suppose that JLabel should be added whenever any one wins & that scenario you have captured inside actionPerformed(where you set win=true). Hence I have extracted your JLabel adding logic to a separate method and calls it when win occurs.

Advice: You can debug the scenario to have a better understanding on what is going on! :)

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