Search code examples
javajavafxlambdascopeminesweeper

Lambda Expression Local variable text defined in an enclosing scope JavaFx


I am using JavaFX to create a minesweeper game. I have a lambda expression where (for now) when I press a button from the grid of buttons, it sets the text of the button to be the location in the 2D array. I am getting the error "Local variable text defined in an enclosing scope must be final or effectively final."

I understand that the variables I am using in the lambda expression cant be done because they have to be final outside the expression. but I cant figure out how to get around that.

static Stage stage;
Button[][] buttonGrid;

public void start(Stage primaryStage) throws Exception {
    SetSettings.readSettings();
    GridPane gridpane = new GridPane();

    int gridSize = Minesweeper.gridSize;
    buttonGrid = new Button[gridSize][gridSize];
    for (int i = 0; i < gridSize; i++) {
        for (int j = 0; j < gridSize; j++) {
            buttonGrid[i][j] = new Button();
            GridPane.setConstraints(buttonGrid[i][j], j, i);

        }
    }
    String text = "";
    for (int i = 0; i < gridSize; i++) {
        for (int j = 0; j < gridSize; j++) {
            text += i + "" + j;
            buttonGrid[i][j].setOnAction(e -> {
                buttonGrid[i][j].setText(text);
                text = "";

            });
            gridpane.getChildren().add(buttonGrid[i][j]);
        }
    }

    stage = primaryStage;
    primaryStage.setOnCloseRequest(e -> {
        e.consume();
        ConfirmExit.display("Exit", "Are you sure you want to quit this game?");
    });
    primaryStage.setTitle("Minesweeper");
    stage.getIcons().add(new Image("/Logo.jpg"));
    Scene scene = new Scene(gridpane, 600, 500);
    primaryStage.setScene(scene);
    primaryStage.show();
}


public static void main(String[] args) {
    launch(args);
}

It is flagging i, j, and text in the same error.

gridSize is the size of my grid for minesweeper. buttonGrid is the grid of buttons I am placing in the gridPane.

I saw a solution on stackoverflow to set these variables as global, but that did not work.


Solution

  • Just move the definition of text inside the loop (so you define a new, effectively final, variable on each iteration of the loop). You can also define a Button variable in the same way, to avoid referencing i and j:

    for (int i = 0; i < gridSize; i++) {
        for (int j = 0; j < gridSize; j++) {
            String text = i + "" + j;
            Button button = buttonGrid[i][j] ;
            button.setOnAction(e -> {
                button.setText(text);    
            });
            gridpane.getChildren().add(buttonGrid[i][j]);
        }
    }