I'm creating a tic tac toe game, and I have created 2 buttons "Quit" and "Replay". When I click on any other buttons, those 2 buttons disappear. I'd be happy if you tell what I can do to have them visible when I click on any other buttons.
As you can see in both screenshots, before I click on any buttons, both are visible, but when I click on any button, both disappear, and I have to hover my mouse over them for them appear again.
Below is all of code
public static void main(String[] args) {
TickTacToe tik = new TickTacToe();
}
Random random = new Random();
JFrame frame = new JFrame();
JPanel title_panel = new JPanel();
JPanel button_panel = new JPanel();
JLabel textfield = new JLabel();
JButton[] buttons_array = new JButton[9];
int i =0;
JPanel panel;
JButton Replaybutton,Quitbutton;
boolean player1_turn;
TickTacToe(){
JButton Replay,Quit;
Replay = new JButton();
Replay.setText("Replay?");
Replay.setForeground(Color.cyan);
Replay.setFont(new Font("Courgette",Font.BOLD,17));
Replay.setBackground(new Color(25,60,80));
Replay.setBounds(70,10, 100,45);
Quit = new JButton();
Quit.setText("Quit!");
Quit.setForeground(Color.black);
Quit.setFont(new Font("Courgette",Font.BOLD,19));
Quit.setBackground(new Color(145,80,120));
Quit.setBounds(620, 10, 100, 45);
////////////////////////////////////////////////////////
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,800);
frame.getContentPane().setBackground(new Color(50,50,50));
frame.setLayout(new BorderLayout());
frame.setVisible(true);
//Below line is for centring our frame in the middle.
frame.setLocationRelativeTo(null);
textfield.setBackground(Color.black);
textfield.setForeground(new Color(80,170,20));
textfield.setFont(new Font("Courgette",Font.PLAIN,50));
//The below method is for centering our text in the center.
textfield.setHorizontalAlignment(JLabel.CENTER);
textfield.setText("Tik-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,150,150));
for(int i = 0; i <9;i ) {
buttons_array[i] = new JButton();
button_panel.add(buttons_array[i]);
buttons_array[i].setFont(new Font("InkFree",Font.BOLD,120));
buttons_array[i].setFocusable(false);
buttons_array[i].addActionListener(this);
}
frame.add(Replay);
frame.add(Quit);
frame.setResizable(false);
title_panel.add(textfield);
frame.add(title_panel,BorderLayout.NORTH);
frame.add(button_panel);
firstTurn();
}
@Override
public void actionPerformed(ActionEvent e) {
for(int i=0;i<9;i ) {
if(e.getSource()==buttons_array[i]) {
if(player1_turn) {
if(buttons_array[i].getText()=="") {
buttons_array[i].setForeground(Color.red);
buttons_array[i].setText("X");
player1_turn =false;
textfield.setText("O Turn");
check();
}
}
else {
if(buttons_array[i].getText()=="") {
buttons_array[i].setForeground(Color.blue);
buttons_array[i].setText("O");
player1_turn =true;
textfield.setText("X Turn");
check();
}
}
}
}
}
public void firstTurn() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(random.nextInt(2)==0) {
player1_turn = true;
textfield.setText("X Turn");
}else if(random.nextInt(2) == 1) {
player1_turn = false;
textfield.setText("O Turn");
}
}
public void check() {
// Checking for x win Conditiotns.
if(
(buttons_array[0].getText() == "X") &&
buttons_array[1].getText() == "X" &&
buttons_array[2].getText() == "X"
) {
xWins(0,1,2);
}
if(
(buttons_array[3].getText() == "X") &&
buttons_array[4].getText() == "X" &&
buttons_array[5].getText() == "X"
) {
xWins(3,4,5);
}
if(
(buttons_array[6].getText() == "X") &&
buttons_array[7].getText() == "X" &&
buttons_array[8].getText() == "X"
) {
xWins(6,7,8);
}
if(
(buttons_array[0].getText() == "X") &&
buttons_array[3].getText() == "X" &&
buttons_array[6].getText() == "X"
) {
xWins(0,3,6);
}
if(
(buttons_array[1].getText() == "X") &&
buttons_array[4].getText() == "X" &&
buttons_array[7].getText() == "X"
) {
xWins(1,4,7);
}
if(
(buttons_array[2].getText() == "X") &&
buttons_array[5].getText() == "X" &&
buttons_array[8].getText() == "X"
) {
xWins(2,5,8);
}
if(
(buttons_array[0].getText() == "X") &&
buttons_array[4].getText() == "X" &&
buttons_array[8].getText() == "X"
) {
xWins(0,4,8);
}
if(
(buttons_array[2].getText() == "X") &&
buttons_array[4].getText() == "X" &&
buttons_array[6].getText() == "X"
) {
xWins(2,4,6);
}
if(
(buttons_array[0].getText() == "O") &&
buttons_array[1].getText() == "O" &&
buttons_array[2].getText() == "O"
) {
oWins(0,1,2);
}
if(
(buttons_array[3].getText() == "O") &&
buttons_array[4].getText() == "O" &&
buttons_array[5].getText() == "O"
) {
oWins(3,4,5);
}
if(
(buttons_array[6].getText() == "O") &&
buttons_array[7].getText() == "O" &&
buttons_array[8].getText() == "O"
) {
oWins(6,7,8);
}
if(
(buttons_array[0].getText() == "O") &&
buttons_array[3].getText() == "O" &&
buttons_array[6].getText() == "O"
) {
oWins(0,3,6);
}
if(
(buttons_array[1].getText() == "O") &&
buttons_array[4].getText() == "O" &&
buttons_array[7].getText() == "O"
) {
oWins(1,4,7);
}
if(
(buttons_array[2].getText() == "O") &&
buttons_array[5].getText() == "O" &&
buttons_array[8].getText() == "O"
) {
oWins(2,5,8);
}
if(
(buttons_array[0].getText() == "O") &&
buttons_array[4].getText() == "O" &&
buttons_array[8].getText() == "O"
) {
oWins(0,4,8);
}
if(
(buttons_array[2].getText() == "O") &&
buttons_array[4].getText() == "O" &&
buttons_array[6].getText() == "O"
) {
oWins(2,4,6);
}
}
//////////////////////////////////////////////////////////////////////////////////
public void xWins(int a, int b, int c) {
buttons_array[a].setBackground(new Color(50,15,80));
buttons_array[b].setBackground(new Color(150,15,80));
buttons_array[c].setBackground(Color.BLACK);
for(int i=0;i<9;i ) {
buttons_array[i].setEnabled(false);
}
CodePudding user response:
Introduction
Oracle has a helpful tutorial,
I used Swing layout managers to create a button JPanel
and a tic-tac-toe grid JPanel
. You can press any button you want, and all the buttons remain visible on the JFrame
.
I left all the coloring and fonts for you to add.
Explanation
When I create a Swing GUI, I use the model-view-controller (MVC) pattern. This pattern allows me to separate my concerns and focus on one small part of the application at a time.
For a Swing GUI, the MVC pattern is defined as:
- The view reads information from the model.
- The view does not update the model.
- The controller updates the model and repaints / revalidates the view.
A Swing GUI can have many controller classes. I created three controller classes for this tic-tac-toe game. Two of the three controller classes are expressed as lambda expressions because they are simple.
I created 5 different classes. One class makes up the application model, one class defines the view, and three controller classes manage the application.
Model
The GameModel
class is a plain Java getter/setter class that creates a logical tic-tac-toe board and keeps track of whose turn it is.
View
Every Swing application must start with a call to the SwingUtilities
invokeLater
method. This method ensures that the Swing components are created and updated on the Event Dispatch Thread.
I use a JFrame
and create a button JPanel
and a grid JPanel
. The JFrame has a default BorderLayout
. I put the button JPanel
at NORTH and the grid JPanel
in the CENTER.
The button JPanel
uses a FlowLayout
and the grid JPanel
uses, you guessed it, a GridLayout
. I added an empty border around both JPanels
to add some whitespace to the GUI.
I used a Box
createHorizontalStrut
method to add some whitespace to the button JPanel
.
Controller
The reset button and quit button controllers are simple lambda expressions.
I made nine instances of the MoveListener
class, one for each button in the tic-tac-toe grid. This makes the actionPerformed
code rather simple. The only logic is to check to make sure the square is empty before making the move.
For some reason, checking for spaces didn't work, so I check for the absence of an 'X' or an 'O'.
Code
Here's the complete runnable code. I made the additional classes inner classes so I could post this code as one block.
I tested this code and it works. Save it somewhere safe before you make lots of changes and then gripe that it doesn't work.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SimpleTicTacToeGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimpleTicTacToeGUI());
}
private final GameModel model;
private JButton[] gridButtons;
private JFrame frame;
private JLabel turnLabel;
public SimpleTicTacToeGUI() {
this.model = new GameModel();
}
@Override
public void run() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createButtonPanel(), BorderLayout.NORTH);
frame.add(createGrid(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
Font font = panel.getFont().deriveFont(16f);
JButton resetButton = new JButton("Replay?");
resetButton.setFont(font);
resetButton.addActionListener(event -> {
model.resetModel();
updateGUI();
enableButtons();
});
panel.add(resetButton);
panel.add(Box.createHorizontalStrut(30));
turnLabel = new JLabel(model.getTurn() "'s turn");
turnLabel.setFont(font);
panel.add(turnLabel);
panel.add(Box.createHorizontalStrut(30));
JButton quitButton = new JButton("Quit!");
quitButton.setFont(font);
quitButton.addActionListener(event -> {
frame.dispose();
System.exit(0);
});
panel.add(quitButton);
return panel;
}
private JPanel createGrid() {
JPanel panel = new JPanel(new GridLayout(0, 3));
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
Font font = panel.getFont().deriveFont(Font.BOLD, 72f);
gridButtons = new JButton[model.getBoard().length];
for (int index = 0; index < gridButtons.length; index ) {
gridButtons[index] = new JButton(" ");
MoveListener listener = new MoveListener(this, model, index);
gridButtons[index].addActionListener(listener);
gridButtons[index].setFont(font);
gridButtons[index].setPreferredSize(new Dimension(96, 96));
panel.add(gridButtons[index]);
}
return panel;
}
public void updateGUI() {
char[] board = model.getBoard();
for (int index = 0; index < gridButtons.length; index ) {
String s = Character.toString(board[index]);
gridButtons[index].setText(s);
}
turnLabel.setText(model.getTurn() "'s turn");
}
public void disableButtons() {
for (int index = 0; index < gridButtons.length; index ) {
gridButtons[index].setEnabled(false);
}
}
private void enableButtons() {
for (int index = 0; index < gridButtons.length; index ) {
gridButtons[index].setEnabled(true);
}
}
public JButton getButton(int index) {
return gridButtons[index];
}
public class MoveListener implements ActionListener {
private final int index;
private final SimpleTicTacToeGUI view;
private final GameModel model;
public MoveListener(SimpleTicTacToeGUI view, GameModel model,
int index) {
this.view = view;
this.model = model;
this.index = index;
}
@Override
public void actionPerformed(ActionEvent event) {
String s = view.getButton(index).getText();
if (!(s.equals("X") || s.equals("O"))) {
model.makeMove(index);
view.updateGUI();
if (model.isGameOver()) {
view.disableButtons();
}
}
}
}
public class GameModel {
private char[] board;
private char turn;
public GameModel() {
resetModel();
}
public void resetModel() {
this.board = new char[9];
this.turn = 'X';
}
public void makeMove(int index) {
board[index] = turn;
turn = (turn == 'X') ? 'O' : 'X';
}
public boolean isGameOver() {
int[][] indexes = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 },
{ 0, 3, 6 }, { 1, 4, 7 }, { 2, 5, 8 }, { 0, 4, 8 },
{ 2, 4, 6 } };
for (int index = 0; index < indexes.length; index ) {
if (checkRow('X', indexes[index])
|| checkRow('O', indexes[index])) {
return true;
}
}
return false;
}
private boolean checkRow(char player, int[] indexes) {
for (int index = 0; index < indexes.length; index ) {
if (board[indexes[index]] != player) {
return false;
}
}
return true;
}
public char getTurn() {
return turn;
}
public char[] getBoard() {
return board;
}
}
}