【问题标题】:Why is the global variable resetting or different for each button?为什么每个按钮的全局变量重置或不同?
【发布时间】:2018-08-12 18:43:00
【问题描述】:

我正在制作井字游戏,我希望能够在单击时让按钮交替 x 和 o。现在它们在第一次点击时都是 x,在第二次点击时都是 o。我也尝试使用和不使用关键字 this。

这里是按钮类

public class Toebuttons extends JButton implements ActionListener
{
boolean x = true; // if true x's turn if false o's turn
int count = 0;
public Toebuttons()
{
   super("blank");
   this.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
   if(this.x == true)
   {
       count++;
       System.out.println(count);
       setText("X");
       this.x = false;
   }
   else if(this.x == false)
   {
       count++;
       System.out.println(count);
       setText("O");
       this.x = true;
   }
  }
}

这是棋盘类

public class ticTacBoard extends JFrame
{
Toebuttons toe[] = new Toebuttons[9];
public ticTacBoard()
{
    super("Tic tac board");
    setSize(500,500);
    setLayout(new GridLayout(3,3));
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    toFront();
    for(int i = 0; i<toe.length; i++)
    {
        toe[i] = new Toebuttons();
        add(toe[i]);
    }
    setVisible(true);
 }
}

【问题讨论】:

    标签: java variables global-variables field jbutton


    【解决方案1】:

    您的问题是无效的对象设计之一:每个按钮都有自己的布尔 x 状态,该状态独立于所有其他按钮,您不应该这样做。实际上,您应该有一个 Game 对象,它包含按钮,并且与按钮分开,它保存此状态并根据此状态控制按钮对按下的响应。

    旁注:我不会扩展 JButton,而是使用 JButton。

    例如,您可以为所有 JButton 赋予 相同 ActionListener:

    import java.awt.BorderLayout;
    import java.awt.Font;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;    
    import javax.swing.*;
    
    public class TicTacFoo extends JPanel {
        private static final long serialVersionUID = 1L;
        private static final int ROWS = 3;
        private static final Font BTN_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 80);
        private JButton[][] buttons = new JButton[ROWS][ROWS];
        private boolean xTurn = true;
        private int count = 0;
    
        public TicTacFoo() {
    
            JPanel buttonPanel = new JPanel(new GridLayout(ROWS, ROWS));
            setLayout(new GridLayout(ROWS, ROWS));
    
            // single ActionListener for all buttons
            ButtonListener buttonListener = new ButtonListener();
    
            // create buttons in nested for loop
            for (int row = 0; row < buttons.length; row++) {
                for (int col = 0; col < buttons[row].length; col++) {
                    buttons[row][col] = new JButton("   ");
                    buttons[row][col].setFont(BTN_FONT);
                    buttons[row][col].addActionListener(buttonListener);
                    buttonPanel.add(buttons[row][col]);
                }
            }
    
            setLayout(new BorderLayout());
            add(buttonPanel);
            add(new JButton(new ResetAction()), BorderLayout.PAGE_END);
        }
    
        private class ButtonListener implements ActionListener {
            @Override
            public void actionPerformed(ActionEvent e) {
    
                // get the button that was pressed
                JButton buttonPressed = (JButton) e.getSource();
                String text = buttonPressed.getText().trim();
                if (!text.isEmpty()) {
                    // button already has been pressed
                    // so exit from the listener
                    return;
                }
    
                if (xTurn) {
                    buttonPressed.setText("X");
                } else {
                    buttonPressed.setText("O");
                }
    
                int rowPressed = -1;
                int colPressed = -1;
                // which button pressed?
                for (int row = 0; row < buttons.length; row++) {
                    for (int col = 0; col < buttons[row].length; col++) {
                        if (buttons[row][col] == buttonPressed) {
                            rowPressed = row;
                            colPressed = col;
                            break;
                        }
                    }
                }
    
                // TODO: here code where you would test for win
                // ......
    
                // swap turn
                xTurn = !xTurn;
                // increment count:
                count++;
                System.out.printf("count: %d, [row, col]: [%d, %d]%n", count, rowPressed, colPressed);
            }
        }
    
        // resets program back to initial state
        @SuppressWarnings("serial")
        class ResetAction extends AbstractAction {
            public ResetAction() {
                super("Reset");
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                // loop through all buttons, resetting state back to initial
                for (JButton[] buttonRow : buttons) {
                    for (JButton button : buttonRow) {
                        button.setText("   ");
                    }
                }
                xTurn = true;
                count = 0;
            }
        }
    
        private static void createAndShowGui() {
            TicTacFoo mainPanel = new TicTacFoo();
    
            JFrame frame = new JFrame("TicTacFoo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    

    【讨论】:

    • JPanel 可以是游戏对象吗?它将如何保持按钮的状态?当布尔 x 是全局变量时,为什么按钮会有自己的布尔 x 状态?
    • @Ben:是的,但不要考虑组件,而是考虑逻辑对象。
    • @Ben:请查看解释事情的代码中的 cmets
    • 当我尝试使用“ButtonListener name = new ButtonListener();”创建单个按钮侦听器时出现错误我已经导入了 java.awt.*; javax.swing.*; java.awt.event.*; java.awt.event.ActionListener;
    • @Ben:问题的关键在于完整的错误消息,你没有向我们展示的东西——你没有告诉我们错误到底是什么,再说一次,那就是解决问题的关键。在该关键消息上搜索此站点以了解如何解决它。
    【解决方案2】:

    这不是 C++ 和这个

    boolean x = true;
    

    在 Java 中不是 global。要在 Java 中模拟可以理解为“全局”(所有类实例通用)的变量,您需要将其声明为 static 类似

    static boolean x = true;
    

    【讨论】:

    • 我强烈反对这种解决方案,因为这也不是 C,而且您正在将 OOP 婴儿与洗澡水一起扔出去。让我们避免在不需要也不推荐的情况下告诉新手使用静态。另一个对象应该保持布尔状态。
    • @HovercraftFullOfEels 我完全同意你的观点,但是教 OP 并解释 OOP 的整个范围以及为什么 Java 支持这种方法以及为什么应该遵循它远远超出了这个问题。因为我们不知道整个应用程序的外观以及上下文和要求是什么,所以我提供了解决 OP 问题的答案
    • 我真的很喜欢在变量之前使用静态。@HovercraftFullOfEels 我不明白对象如何保持布尔状态或计数如何继续增加?
    • @Ben:查看编辑示例。不,不要出于不好的原因使用静态,比如这个
    • @HovercraftFullOfEels 我没有达到你在 java 中的水平,而且还不了解你的所有代码。我明白为什么静态现在可以在我的代码中工作,但不明白为什么使用它不好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 2014-01-25
    • 2017-09-20
    相关资源
    最近更新 更多