package SOS;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class BoardPanel {
private JFrame frame;
private void createAndDisplayGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTopPanel(), BorderLayout.PAGE_START);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void createBoard(ActionEvent event) {
Object source = event.getSource();
if (source instanceof JTextField) {
JTextField textField = (JTextField) source;
String text = textField.getText();
int dimension = Integer.parseInt(text);
JPanel board = new JPanel(new GridLayout(dimension, dimension));
for (int row = 0; row < dimension; row ) {
for (int col = 0; col < dimension; col ) {
JLabel square = new JLabel(" ");
square.setBackground(Color.white);
square.setOpaque(true);
square.setBorder(BorderFactory.createLineBorder(Color.black));
board.add(square);
}
}
frame.add(board, BorderLayout.CENTER);
frame.pack();
}
}
private JPanel createTopPanel() {
JRadioButton optionS = new JRadioButton("S");
JRadioButton optionO = new JRadioButton("O");
ButtonGroup group = new ButtonGroup();
group.add(optionS);
group.add(optionO);
JPanel topPanel = new JPanel();
JLabel label = new JLabel("Board size:");
topPanel.add(label);
JTextField boardSize = new JTextField(6);
boardSize.addActionListener(this::createBoard);
topPanel.add(boardSize);
topPanel.add(optionS, BorderLayout.NORTH);
topPanel.add(optionO, BorderLayout.CENTER);
return topPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new BoardPanel().createAndDisplayGui());
}
}
I know I am supposed to make an action listener for each radio button and that seems pretty straightforward, but I am confused on how I would do that and then translate that to placing an S or O on the game boards given cell depending on what is selected. I think the more confusing part is being able to draw in the given cell either the S or the O depending on what is selected. This is for an SOS game, sort of like tic tac toe. I tried following a simple tic tac toe example but got lost as there is no radio buttons like this and I am using a different createboard method.
CodePudding user response:
You can declare your radioButton globally so you can check the selected status. Then in a listener in your cells check that and place the appropriate letter:
package SOS;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class BoardPanel {
private JFrame frame;
private JRadioButton optionS;
private JRadioButton optionO;
private void createAndDisplayGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(createTopPanel(), BorderLayout.PAGE_START);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void createBoard(ActionEvent event) {
Object source = event.getSource();
if (source instanceof JTextField) {
JTextField textField = (JTextField) source;
String text = textField.getText();
int dimension = Integer.parseInt(text);
JPanel board = new JPanel(new GridLayout(dimension, dimension));
for (int row = 0; row < dimension; row ) {
for (int col = 0; col < dimension; col ) {
JLabel square = new JLabel(" ");
square.setBackground(Color.white);
square.setOpaque(true);
square.setBorder(BorderFactory.createLineBorder(Color.black));
board.add(square);
square.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
square.setText(optionS.isSelected() ? " S " : " O ");
}
});
}
}
frame.getContentPane().add(board, BorderLayout.CENTER);
frame.pack();
}
}
private JPanel createTopPanel() {
optionS = new JRadioButton("S");
optionO = new JRadioButton("O");
ButtonGroup group = new ButtonGroup();
group.add(optionS);
group.add(optionO);
JPanel topPanel = new JPanel();
JLabel label = new JLabel("Board size:");
topPanel.add(label);
JTextField boardSize = new JTextField(6);
boardSize.addActionListener(this::createBoard);
topPanel.add(boardSize);
topPanel.add(optionS, BorderLayout.NORTH);
topPanel.add(optionO, BorderLayout.CENTER);
return topPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new BoardPanel().createAndDisplayGui());
}
}
CodePudding user response:
There are few ways you might be able to do this, personally, I like to decouple the workflows and remove dependencies where I can.
For example, your createBoard
method is making an assumption about how the dimension
value is captured by the user. What happens if you want to change that workflow to use a JSpinner
or JCombobox
? You'd then have to modify this method as well.
Better to pass the method the information it needs to do its job. In fact, I'd make it return an instance of JPanel
, so as to remove all the dependencies, after all createBoard
should do just that, nothing else.
I've changed the workflow so there is now a dedicated "create" button, this will collect the information it needs in order to be able to create the board itself. Not as dynamic as the other approach, but it gives the user time to consider their inputs
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class BoardPanel {
private JFrame frame;
enum State {
S, O;
}
private JPanel board;
private void createAndDisplayGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTopPanel(), BorderLayout.PAGE_START);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createBoard(int dimension, State state) {
JPanel board = new JPanel(new GridLayout(dimension, dimension));
for (int row = 0; row < dimension; row ) {
for (int col = 0; col < dimension; col ) {
JLabel square = new JLabel(" " state.name() " ");
square.setBackground(Color.white);
square.setOpaque(true);
square.setBorder(BorderFactory.createLineBorder(Color.black));
board.add(square);
}
}
return board;
}
private JPanel createTopPanel() {
JRadioButton optionS = new JRadioButton("S");
JRadioButton optionO = new JRadioButton("O");
JTextField boardSize = new JTextField(6);
JPanel topPanel = new JPanel();
ButtonGroup group = new ButtonGroup();
group.add(optionS);
group.add(optionO);
// Default state
optionS.setSelected(true);
JButton createButton = new JButton("Make it so");
createButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
State state = State.O;
if (optionS.isSelected()) {
state = State.S;
}
try {
int dimension = Integer.parseInt(boardSize.getText());
if (board != null) {
frame.remove(board);
}
board = createBoard(dimension, state);
frame.add(board, BorderLayout.CENTER);
frame.pack();
} catch (NumberFormatException exp) {
JOptionPane.showMessageDialog(topPanel, "Invalid board size", "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
JLabel label = new JLabel("Board size:");
topPanel.add(label);
topPanel.add(boardSize);
topPanel.add(optionS);
topPanel.add(optionO);
topPanel.add(createButton);
return topPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new BoardPanel().createAndDisplayGui());
}
}
If you'd prefer something a little more dynamic, then you could add shared ActionListener
to the buttons and text field, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class BoardPanel {
private JFrame frame;
enum State {
S, O;
}
private JPanel board;
private void createAndDisplayGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTopPanel(), BorderLayout.PAGE_START);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createBoard(int dimension, State state) {
JPanel board = new JPanel(new GridLayout(dimension, dimension));
for (int row = 0; row < dimension; row ) {
for (int col = 0; col < dimension; col ) {
JLabel square = new JLabel(" " state.name() " ");
square.setBackground(Color.white);
square.setOpaque(true);
square.setBorder(BorderFactory.createLineBorder(Color.black));
board.add(square);
}
}
return board;
}
private JPanel createTopPanel() {
JRadioButton optionS = new JRadioButton("S");
JRadioButton optionO = new JRadioButton("O");
JTextField boardSize = new JTextField(6);
JPanel topPanel = new JPanel();
ButtonGroup group = new ButtonGroup();
group.add(optionS);
group.add(optionO);
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
State state = State.O;
if (optionS.isSelected()) {
state = State.S;
}
try {
int dimension = Integer.parseInt(boardSize.getText());
if (board != null) {
frame.remove(board);
}
board = createBoard(dimension, state);
frame.add(board, BorderLayout.CENTER);
frame.pack();
} catch (NumberFormatException exp) {
// Not yet ready
}
}
};
optionS.addActionListener(actionListener);
optionO.addActionListener(actionListener);
boardSize.addActionListener(actionListener);
// Default state
optionS.setSelected(true);
JLabel label = new JLabel("Board size:");
topPanel.add(label);
topPanel.add(boardSize);
topPanel.add(optionS);
topPanel.add(optionO);
return topPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new BoardPanel().createAndDisplayGui());
}
}