How can I get the indexes of each button clicked f

2019-02-24 19:26发布

问题:

So I have a double array of buttons. Once I clicked a button I need to be able to get the index of it to use for further coding(This is a minesweeper like game). This is my code so far. I have a double for loop to create a Handle event for each button but i can't figure out how to get the indexes of each button. I've tried e.getSource() but it only returns the address which would be useless. I've tried give each button a Id but it only accepts strings. I'm lost on what to do next.

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;



public class main extends Application {


Button[][] tiles = new Button[8][8];
Integer[][] mine_field = new Integer[8][8];
Stage window;



public void start(Stage primaryStage){

    BorderPane Field = new BorderPane();
    HBox Start_Show = new HBox(50);
    Button Start = new Button("Start");
    Button Show = new Button ("Show");
    Start.setStyle("-fx-font-size: 15.5pt;");
    Show.setStyle("-fx-font-size: 15.5pt;");
    Start_Show.getChildren().addAll(Start, Show);
    Start_Show.setAlignment(Pos.CENTER);
    Start_Show.setPadding(new Insets(10,10,10,10));
    Field.setTop(Start_Show);



    tiles = create_tiles(tiles);

    int i;
    int j;

    VBox columns = new VBox();

    for(i=0; i<8; i++){
        HBox row = new HBox();
        for(j=0; j<8; j++){
            row.getChildren().add(tiles[i][j]);
        }
        columns.getChildren().add(row);
    }
    columns.setAlignment(Pos.CENTER);
    columns.setPadding(new Insets(0,0,0,100));

    Field.setCenter(columns);



    mine_field = set_mines(mine_field);

    Start.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
             start(primaryStage);               
        }

    });

    Show.setOnAction(new EventHandler<ActionEvent>() {
        @Override
            public void handle(ActionEvent e){

                int i = 0;
                int j = 0;

                for(i=0; i<8; i++){
                    for(j=0; j<8; j++){

                        if(mine_field[i][j] == 1) {
                            tiles[i][j].setStyle("-fx-font-size: 15.5pt;");
                            tiles[i][j].setTextFill(Color.RED);
                            tiles[i][j].setMaxHeight(150);
                            tiles[i][j].setMaxWidth(251);
                            tiles[i][j].setText("M");   
                            }
                        }
                    }
                }
            });



    for(i=0; i<8; i++){

        for(j=0; j<8; j++){
            Tile_Handler tile_handle = new Tile_Handler();
            tiles[i][j].setOnAction(tile_handle);
        }
    }





    Scene scene = new Scene(Field, 600, 600);
    primaryStage.setTitle("MineSweeper!");
    primaryStage.setScene(scene);
    primaryStage.show();


}


public Button[][] create_tiles(Button[][] array){

    int i;
    int j;

    for(i=0; i<8; i++){

        for(j=0; j<8; j++){
            Button my_butt = new Button("?");
            my_butt.setStyle("-fx-font-size: 20pt;");
            my_butt.prefWidthProperty();

            array[i][j] = my_butt;

        }
    }

    return array;

}

public Integer[][] set_mines(Integer[][] array){
    Random random = new Random();

    int i;
    int j;
    int k;

    for(i=0; i<8; i++){

            for(j=0; j<8; j++){
                array[i][j] = 0;

            }
        }

    for(i=0; i<10; i++){
        j = random.nextInt(8);
        k = random.nextInt(8);
        array[j][k] = 1;            
    }

    return array;
}


class Tile_Handler implements EventHandler<ActionEvent> {

    public void handle(ActionEvent e){




        System.out.println("yo clicked one button located at ");
    }
}



public static void main(String[] args){

        Application.launch(args);

}







}

回答1:

You can create tile handlers with the parameters on the fly, with a utility function and lambda expressions:

private EventHandler<ActionEvent> createTileHandler(int x, int y) {
    return event -> tileHandler(x, y);
}
private void tileHandler (int x, int y){
    System.out.println(String.format("Clicked tile at (%d,%d)", x, y));
}

Then apply to the different buttons like so:

 ... 

for (int i=0; i<8; i++){
    for (int j=0; j<8; j++) {
        tiles[i][j].setOnAction(createTileHandler(i, j));
    }
}

...

Alternatively, modifying your current solution, you can add two members to Tile_Handler, so when creating it you attach it to the specific coordinates:

class Tile_Handler implements EventHandler<ActionEvent> {

    private int x, y;

    public Tile_Handler(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void handle(ActionEvent e){

        System.out.println(String.format("yo clicked one button located at %d,%d",x,y));
    }
}

Then change the instantiation to

Tile_Handler tile_handle = new Tile_Handler(i, j);


回答2:

Sillyfly's answer is great, the info below is just presented as a different option.

Sillyfly's approach of storing data the co-ordinate data in the event handler is a good approach if you only ever need access to the coordinates in the event handler. If you need access from other locations, you can use the approach below.

Rather than storing the co-ordinates in an event handler, you could store the co-ordinates with the original object (the button). You could do this by extending button and adding additional properties or by making use of the generic userData property that is settable on any node.

for (int i = 0; i < N_ROWS; i++) {
    for (int j = 0; j < N_COLS; j++) {
        Button button = new Button();
        button.setUserData(new Coord(i,j));
        button.setOnAction(event -> takeActionForCoord((Coord) button.getUserData()));
        pane.getChildren().add(button);
    }
}

Where Coord is a holder class for the button co-ordinates.

class Coord {
    private int i;
    private int j;

    public Coord(int i, int j) {
        this.i = i;
        this.j = j;
    }

    public int getI() {
        return i;
    }

    public int getJ() {
        return j;
    }
}