【问题标题】:How do I reset the GUI and the Game?如何重置 GUI 和游戏?
【发布时间】:2018-08-14 21:59:04
【问题描述】:

我正在制作一个游戏,并希望在游戏结束并单击“休息”按钮后重置棋盘。目前游戏首轮运行良好。

我认为问题在于重置方法“this.play()”。有人可以解释一下我打电话时发生了什么。

使用“this.play()”,GUI 不会重置,游戏也不会运行。如果没有“this.play()”,GUI 会重置,但游戏无法运行。

我还想在每次单击按钮而不是循环后运行检查方法。我不断收到无法从静态上下文引用非静态方法的错误。我一直把check方法放在buttons类的actionPerformed方法中

这是我的代码...

板级...

public class ticTacBoard extends JFrame implements ActionListener
{
Toebuttons toe[] = new Toebuttons[9];
JFrame over = new JFrame("Game Over");
JPanel panel = new JPanel();
JLabel winner = new JLabel("");
static boolean win = false;
public static void start()
{ 
    ticTacBoard b = new ticTacBoard();
    b.play();
}
public void play()
{
    //ticTacBoard one = new ticTacBoard();
    while(!win && Toebuttons.count < 9)
    {
        this.check();
    }
    endFrame();
}

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

public void check()
{
    checkRow();
    checkDiagonal();
    checkColumn();
}

public void checkRow()
{

    if((toe[0].getText().equals("X")||toe[0].getText().equals("O"))&&(toe[0].getText().equals(toe[1].getText()) && toe[1].getText().equals(toe[2].getText())))
    {
        winner.setText(toe[2].getText()+" WINS!!!\nROW");
        win = true;
    }
    if((toe[3].getText().equals("X")||toe[3].getText().equals("O"))&&(toe[3].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[5].getText())))
    {
        winner.setText(toe[3].getText()+" WINS!!!\nROW");
        win = true;
    }
    if((toe[6].getText().equals("X")||toe[6].getText().equals("O"))&&(toe[6].getText().equals(toe[7].getText()) && toe[7].getText().equals(toe[8].getText())))
    {
        winner.setText(toe[6].getText()+" WINS!!!\nROW");
        win = true;
    }
}

public void checkDiagonal()
{
    if((toe[0].getText().equals("X")||toe[0].getText().equals("O"))&&(toe[0].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[8].getText())))
    {
        winner.setText(toe[0].getText()+" WINS!!!\nDIAGONAL");
        win = true;
    }
    if((toe[2].getText().equals("X")||toe[2].getText().equals("O"))&&(toe[2].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[6].getText())))
    {
        winner.setText(toe[0].getText()+" WINS!!!\nDIAGONAL");
        win = true;
    }
}

public void checkColumn()
{
    if((toe[0].getText().equals("X")||toe[0].getText().equals("O"))&&(toe[0].getText().equals(toe[3].getText()) && toe[3].getText().equals(toe[6].getText())))
    {
        winner.setText(toe[0].getText()+" WINS!!!\nCOLUMN");
        win = true;
    }
    if((toe[1].getText().equals("X")||toe[1].getText().equals("O"))&&(toe[1].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[7].getText())))
    {
        winner.setText(toe[1].getText()+" WINS!!!\nCOLUMN");
        win = true;
    }
    if((toe[2].getText().equals("X")||toe[2].getText().equals("O"))&&(toe[2].getText().equals(toe[5].getText()) && toe[5].getText().equals(toe[8].getText())))
    {
        winner.setText(toe[2].getText()+" WINS!!!\nCOLUMN");
        win = true;
    }
}
public void endFrame()
{
    System.out.println("2222");
    over.setLocationRelativeTo(null);
    panel.setLayout(new FlowLayout());
    over.setLayout(new FlowLayout());
    panel.add(winner);
    panel.repaint();
    over.add(panel);
    over.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    over.setSize(500,100);
    JButton r = new JButton("Reset");
    JPanel p = new JPanel();
    p.add(r);
    over.add(p);
    r.addActionListener(this);
    over.repaint();
    over.setVisible(true);
}
public void reset()
{
    Toebuttons.x = true;
    for(int i = 0; i<toe.length;i++)
    { 
        toe[i].setText("blank");
    }
    win = false;
    Toebuttons.count = 0;
    this.play();
}
public void actionPerformed(ActionEvent e)
{
    over.hide();
    reset();
}
}

按钮类 ...

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

   }
   }

【问题讨论】:

    标签: java swing oop user-interface jbutton


    【解决方案1】:

    使用“this.play()”,GUI 不会重置,游戏也不会运行。如果没有“this.play()”,GUI 会重置,但游戏无法运行。

    问题是,你阻塞了事件调度线程...

    public void play()
    {
        //ticTacBoard one = new ticTacBoard();
        while(!win && Toebuttons.count < 9)
        {
            this.check();
        }
        endFrame();
    }
    

    这会创建一个无限循环,阻止事件调度线程处理事件队列。

    但为什么第一次就成功了?

    因为您实际上违反了 GUI 开发的基本规则之一。 main 被调用,通常称为“主线程”。这意味着您第一次调用play 时,您正在与事件调度线程不同的线程上运行。但是,第二次调用它时,会从 EDT 的上下文中调用 reset,然后导致 play 阻止它。

    GUI开发的一些基本规则:

    • 不要在 UI 线程中执行长时间运行或阻塞的操作
    • 不要从 UI 线程的上下文之外更新 UI 或 UI 所依赖的状态。大多数 UI API 都不是线程安全的。

    这是一个很大而且有些复杂的主题,但是,您可以先阅读Concurrency in Swing

    那么,解决办法是什么?

    UI 是事件驱动的,您应该使用此机制来监控按钮状态何时更改并执行更新检查。

    首先,摆脱play

    其次,将ActionListener 附加到板上的所有按钮。作为“操作”的一部分,您应该检查游戏的状态并决定应该做什么。

    而且,不,我不是说将检查添加到 Toebuttons#actionPerformed,我的意思是 ticTacBoard 应该在 Toebuttons 上注册它自己的 ActionListener,并且当触发时,检查游戏状态 - 请注意, ActionListeners 的顺序被称为我的影响你的决策过程,这就是为什么最好将 UI 状态与游戏状态分开 - 但这是另一个主题

    概念可运行示例...

    这是一个概念性的例子,它引入了将 UI 与游戏状态解耦的概念,让 UI 只负责显示游戏状态。

    见:

    挖掘它,放入一些System.out.println 语句,在代码上运行调试器。返回链接的教程并扩展您对所介绍概念的理解

    虽然有些人可能认为它“高级”,但从概念上讲,它介绍了您需要理解的核心概念,以便在一般情况下使用 Swing 和 GUI

    import java.awt.CardLayout;
    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.GridLayout;
    import java.awt.Insets;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class TicTac {
    
        public static void main(String[] args) {
            new TicTac();
        }
    
        public TicTac() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.add(new TicTacToePane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public enum Player {
            X, O, NONE;
        }
    
        public interface TicTacToeModelListener {
    
            public void ticTacToeGameWon(TicTacToeModel model);
        }
    
        public class TicTacToeModel {
    
            private Player[] board;
            private Player turn;
            private Player winner;
    
            private List<TicTacToeModelListener> listeners;
    
            public TicTacToeModel() {
                board = new Player[3 * 3];
                listeners = new ArrayList<>(25);
                reset();
            }
    
            public boolean isX() {
                return turn == Player.X;
            }
    
            public void nextTurn() {
                if (isX()) {
                    turn = Player.O;
                } else {
                    turn = Player.X;
                }
            }
    
            public Player getTurn() {
                return turn;
            }
    
            public Player getWinner() {
                return winner;
            }
    
            public void reset() {
                for (int index = 0; index < board.length; index++) {
                    board[index] = Player.NONE;
                }
                turn = Player.X;
                winner = Player.NONE;
            }
    
            public void set(int col, int row) {
                int index = (row * 3) + col;
                if (board[index] == Player.NONE) {
                    board[index] = turn;
                } else {
                    System.out.println("!! Spot already occupied");
                }
    
                check();
            }
    
            public void check() {
                checkRow();
                checkDiagonal();
                checkColumn();
    
                if (winner != Player.NONE) {
                    fireGameWon();
                }
            }
    
            public void addModelListener(TicTacToeModelListener listener) {
                listeners.add(listener);
            }
    
            public void removeModelListener(TicTacToeModelListener listener) {
                listeners.remove(listener);
            }
    
            protected void fireGameWon() {
                for (TicTacToeModelListener listener : listeners) {
                    listener.ticTacToeGameWon(this);
                }
            }
    
            public void checkRow() {
    
                if ((board[0] == Player.X || board[0] == Player.O) && (board[0] == board[1] && board[1] == board[2])) {
                    winner = turn;
                }
                if ((board[3] == Player.X || board[3] == Player.O) && (board[3] == board[4] && board[4] == board[5])) {
                    winner = turn;
                }
                if ((board[6] == Player.X || board[6] == Player.O) && (board[6] == board[7] && board[7] == board[8])) {
                    winner = turn;
                }
            }
    
            public void checkDiagonal() {
                if ((board[0] == Player.X || board[0] == Player.O) && (board[0] == (board[4]) && board[4] == (board[8]))) {
                    winner = turn;
                }
                if ((board[2] == Player.X || board[2] == Player.O) && (board[2] == (board[4]) && board[4] == (board[6]))) {
                    winner = turn;
                }
            }
    
            public void checkColumn() {
                if ((board[0] == Player.X || board[0] == Player.O) && (board[0] == (board[3]) && board[3] == (board[6]))) {
                    winner = turn;
                }
                if ((board[1] == Player.X || board[1] == Player.O) && (board[1] == (board[4]) && board[4] == (board[7]))) {
                    winner = turn;
                }
                if ((board[2] == Player.X || board[2] == Player.O) && (board[2] == (board[5]) && board[5] == (board[8]))) {
                    winner = turn;
                }
            }
        }
    
        public class TicTacToePane extends JPanel {
    
            private TicTacToeModel model;
            private GamePane gamePane;
            private WinPane winPane;
    
            public TicTacToePane() {
                CardLayout cardLayout = new CardLayout();
    
                model = new TicTacToeModel();
                model.addModelListener(new TicTacToeModelListener() {
                    @Override
                    public void ticTacToeGameWon(TicTacToeModel model) {
                        winPane.setWinner(model.getWinner());
                        cardLayout.show(TicTacToePane.this, "GameOverMan");
                    }
                });
    
                winPane = new WinPane();
                gamePane = new GamePane(model);
    
                winPane.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (e.getActionCommand().equals(GameActions.PLAY_AGAIN.getCommand())) {
                            gamePane.reset();
                            cardLayout.show(TicTacToePane.this, "ReadyPlayer");
                        } else if (e.getActionCommand().equals(GameActions.STOP_PLAYING.getCommand())) {
                            SwingUtilities.windowForComponent(TicTacToePane.this).dispose();
                        }
                    }
                });
    
                setLayout(cardLayout);
                add(winPane, "GameOverMan");
                add(gamePane, "ReadyPlayer");
    
                cardLayout.show(this, "ReadyPlayer");
                System.out.println("...");
            }
    
        }
    
        public class GamePane extends JPanel {
    
            private JButton board[];
            private TicTacToeModel model;
    
            public GamePane(TicTacToeModel model) {
                this.model = model;
                setLayout(new GridLayout(3, 3));
                board = new JButton[9];
                for (int row = 0; row < 3; row++) {
                    for (int col = 0; col < 3; col++) {
                        int index = (row * 3) + col;
                        System.out.println(index);
                        board[index] = new JButton("-"); // Icon might be better
                        board[index].addActionListener(new ButtonActionListener(col, row));
                        add(board[index]);
                    }
                }
                reset();
            }
    
            public void reset() {
                model.reset();
                for (int index = 0; index < board.length; index++) {
                    board[index].setText("-");
                }
            }
    
            protected class ButtonActionListener implements ActionListener {
    
                private int col;
                private int row;
    
                public ButtonActionListener(int col, int row) {
                    this.col = col;
                    this.row = row;
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    // Normally I'd use instanceof to check the source, but
                    // I've deliberly limited the possible scope.
                    JButton btn = (JButton) e.getSource();
                    btn.setText(model.isX() ? "X" : "0");
                    model.set(col, row);
                    model.nextTurn();
                }
    
            }
        }
    
        public enum GameActions {
            PLAY_AGAIN("playAgain"), STOP_PLAYING("stopPlaying");
    
            private String command;
    
            private GameActions(String command) {
                this.command = command;
            }
    
            public String getCommand() {
                return command;
            }
        }
    
        public class WinPane extends JPanel {
    
            private JLabel winner;
            private JButton playAgain;
            private JButton end;
    
            public WinPane() {
                setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                gbc.insets = new Insets(8, 8, 8, 8);
    
                winner = new JLabel("");
                playAgain = new JButton("Play Again");
                playAgain.setActionCommand(GameActions.PLAY_AGAIN.getCommand());
    
                end = new JButton("Stop Playing");
                end.setActionCommand(GameActions.STOP_PLAYING.getCommand());
    
                add(new JLabel("Game Over!"), gbc);
                add(new JLabel("Player"), gbc);
                add(winner, gbc);
                add(new JLabel("Wins!"), gbc);
    
                JPanel buttons = new JPanel(new GridLayout(1, 0));
                buttons.add(playAgain);
                buttons.add(end);
    
                add(buttons, gbc);
            }
    
            public void setWinner(Player player) {
                if (player == Player.X) {
                    winner.setText("X");
                } else if (player == Player.O) {
                    winner.setText("0");
                } else {
                    winner.setText("No boby knows");
                }
            }
    
            public void addActionListener(ActionListener listener) {
                playAgain.addActionListener(listener);
                end.addActionListener(listener);
            }
    
            public void removeActionListener(ActionListener listener) {
                playAgain.removeActionListener(listener);
                end.removeActionListener(listener);
            }
    
        }
    
    }
    

    【讨论】:

    • 我想通过调用静态方法来启动整个程序。这可能吗?
    • 为什么?你会得到什么好处?此外,一旦你摆脱了play,你可以继续调用static方法直到奶牛回家
    • play 不是静态的,start 是。但是由于您已经重置了当前板的状态,我看不出再次调用它的意义,您已经重置了 UI/游戏的状态,只需继续使用您拥有的当前实例 -否则reset 方法的整个概念毫无意义,只需创建一个新的板实例并处理当前的实例:/
    • 我将 play 方法中的代码复制并粘贴到静态方法 start() 中,并改为调用 start,但还是同样的错误。我将如何处理一个板实例并创建另一个?我喜欢这个主意
    • @HovercraftFullOfEels 看起来 OP 不喜欢听到“不要按你的方式做,你需要改变”:/ - 喝水,不能强迫他们喝。 .. 想淹死他们
    猜你喜欢
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2018-01-16
    相关资源
    最近更新 更多