JMAD2016
JMAD2016

Reputation: 121

Java-FX Receive Index of Shape-Array when clicked

I am trying to build a battle ship application. So far I managed to display both fields for the player and the enemy. A field consists of 10 x 10 Rectangles - 10 HBox'es in one VBox. This is the method that creates me a field:

private Rectangle[][] field;    
public VBox CreateField(){
        VBox vbox = new VBox(2);
        for(int i = 0; i < this.columns; ++i){
            HBox hbox = new HBox(2);
            for(int j = 0; j < this.rows; ++j){
                this.array[j][i] = 0;
                this.field[i][j] = new Rectangle(this.height*j, this.width*i, this.height, this.width);
                this.field[i][j].setStroke(Color.BLACK);
                this.field[i][j].setFill(Color.LIGHTGRAY);                
                hbox.getChildren().add(this.field[i][j]);
            }
            vbox.getChildren().add(hbox);
        } 
        return vbox;
    }

This is the result:

enter image description here

I need to receive the Index of a Rectangle when the user clicks one of it.

Can you guys give me an example / code snipped how to accomplish my problem?

Upvotes: 0

Views: 440

Answers (2)

fabian
fabian

Reputation: 82461

I recommend using a GridPane instead of HBoxes and a VBox. You could copy the loop indices to final local variables to access them from a anonymus EventHandler class/lambda expression created inside the loop body or you could use GridPane.getRowIndex/GridPane.getColumnIndex on the GridPane children:

public GridPane CreateField(){
    GridPane grid = new GridPane();
    grid.setVgap(2);
    grid.setHgap(2);
    EventHandler<MouseEvent> handler = evt -> {
        Node source = (Node) evt.getSource();
        int row = GridPane.getRowIndex(source);
        int column = GridPane.getColumnIndex(source);
        ...
    };
    for(int i = 0; i < this.columns; i++){
        for(int j = 0; j < this.rows; j++){
            Rectangle rect = new Rectangle(this.height*j, this.width*i, this.height, this.width);
            this.array[j][i] = 0;
            this.field[i][j] = rect;
            rect.setStroke(Color.BLACK);
            rect.setFill(Color.LIGHTGRAY);
            rect.setOnMouseClicked(handler);
            grid.add(rect, j, i);
        }
    } 
    return grid;
}

You could also use

final int finalI = i;
final int finalJ = j;
rect.setOnMouseClicked(evt -> {
    // TODO: use finalI and finalJ here 
});

in the inner loop instead.

Upvotes: 1

JMAD2016
JMAD2016

Reputation: 121

Lol, got it faster work than I thought. Here is my solution (How can I get the indexes of each button clicked for my program?)

private EventHandler<? super MouseEvent> 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));
}
public VBox CreateField(){
    VBox vbox = new VBox(2);
    for(int i = 0; i < this.columns; ++i){
        HBox hbox = new HBox(2);
        for(int j = 0; j < this.rows; ++j){
            this.array[j][i] = 0;
            this.field[i][j] = new Rectangle(this.height*j, this.width*i, this.height, this.width);
            this.field[i][j].setStroke(Color.BLACK);
            this.field[i][j].setFill(Color.LIGHTGRAY);      
            this.field[i][j].setOnMouseClicked(createTileHandler(i,j));
            hbox.getChildren().add(this.field[i][j]);
        }
        vbox.getChildren().add(hbox);
    } 
    return vbox;
}

This returns:

Clicked tile at (3,2)
Clicked tile at (3,2)
Clicked tile at (4,4)
Clicked tile at (3,0)
Clicked tile at (8,8)
Clicked tile at (9,9)
Clicked tile at (0,0)
Clicked tile at (0,1)
Clicked tile at (0,2)

When I click one Shape. Apologizing for this questions ..

Upvotes: 1

Related Questions