我将如何使用 jswing 中的单选按钮使侦听器能够根据所选内容在给定单元格中放置 S 或 O?

How would I use the radio button in jswing to make a listener capable of placing an S or O in the given cell depending on what is selected?

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());
    }
}

我知道我应该为每个单选按钮创建一个动作侦听器,这看起来很简单,但我对如何做到这一点感到困惑,然后将其转换为在给定的游戏板上放置一个 S 或 O单元格取决于所选择的内容。我认为更令人困惑的部分是能够根据所选内容在给定的单元格中绘制 S 或 O。这是 SOS 游戏,有点像井字游戏。我尝试按照一个简单的井字游戏示例进行操作,但由于没有像这样的单选按钮而迷路了,而且我使用的是不同的创建板方法。

您可以全局声明您的 radioButton,这样您就可以检查选中的状态。然后在您的单元格中的侦听器中检查并放置适当的字母:

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());
    }
}

有几种方法可以做到这一点,就我个人而言,我喜欢尽可能地分离工作流并删除依赖项。

例如,您的 createBoard 方法假设用户如何捕获 dimension 值。如果您想将该工作流程更改为使用 JSpinnerJCombobox 会怎样?然后您还必须修改此方法。

最好向方法传递完成其工作所需的信息。事实上,我会让它 return 成为 JPanel 的实例,以便删除所有依赖项,毕竟 createBoard 应该这样做,没有别的。

我已经更改了工作流程,所以现在有一个专用的“创建”按钮,这将收集它需要的信息,以便能够自行创建看板。不像其他方法那样动态,但它让用户有时间考虑他们的输入

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());
    }
}

如果您想要更动态的内容,则可以将共享 ActionListener 添加到按钮和文本字段,例如...

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());
    }
}