Search code examples
buttonjavafxtimerwaittic-tac-toe

Wait until any button is pressed?


I am writing a TicTacToe game in JavaFX. I've decided to make a board as 9 (3x3) buttons with changing text: "" (if empty) or "X" or "O". Everything is going ok beside one thing... I got stuck here:

public void game() {

        while(keepPlaying) {
            if(computerTurn) {;
                computerMove();
            }else {
                while(waitForUser) {
                    //wait until any of 9 buttons is pushed!
                }
            }

            if (checkResult()) {
                keepPlaying = false;
            }
            computerTurn = !computerTurn;
        }
    }

How to wait for user pushing any of those 9 buttons and then continue with computer turn??

I need something like waiting for scanner input in console application, but this input must be one of 9 buttons...

I know that there are few "possible duplicates", but in fact those problems were solved using methods I can't use here, for example timer. Correct me if I am wrong.


Solution

  • Blocking the application thread in JavaFX should not be done since it freezes the UI. For this reason a loop like this is not well suited for a JavaFX application. Instead you should react to user input:

    public void game() {
        if (keepPlaying && computerTurn) {
            computerMove();
            if (checkResult()) {
                keepPlaying = false;
            }
            computerTurn = false;
        }
    }
    
    // button event handler
    private void button(ActionEvent event) {
        if (keepPlaying) {
            Button source = (Button) event.getSource();
    
            // probably the following 2 coordinates are computed from GridPane indices
            int x = getX(source);
            int y = getY(source);
    
            // TODO: update state according to button pressed
    
            if (checkResult()) {
                keepPlaying = false;
            } else {
                computerMove();
                if (checkResult()) {
                    keepPlaying = false;
                }
            }
        }
    
    }
    

    Starting with javafx 9 there is a public API for "pausing" on the application thread however:

    private static class GridCoordinates {
        int x,y;
        GridCoordinates (int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
    private final Object loopKey = new Object();
    
    public void game() {
        while(keepPlaying) {
            if(computerTurn) {
                computerMove();
            } else {
                // wait for call of Platform.exitNestedEventLoop​(loopKey, *)
                GridCoordinates coord = (GridCoordinates)  Platform.enterNestedEventLoop​(loopKey);
    
                // TODO: update state
            }
    
            if (checkResult()) {
                keepPlaying = false;
            }
            computerTurn = !computerTurn;
        }
    }
    
    private void button(ActionEvent event) {
        if (keepPlaying) {
            Button source = (Button) event.getSource();
    
            // probably the following 2 coordinates are computed from GridPane indices
            int x = getX(source);
            int y = getY(source);
    
            Platform.exitNestedEventLoop​(loopKey, new GridCoordinates(x, y));
        }
    }