Loop containing EventHandler isn't working as intended for javafx?

Will170393 :

I am new to JavaFX and am having trouble using the setOnMouseClicked method. In the below code I have tried to add an event Handler inside a nested loop to assign every rectangle created an eventHandler that, on a mouse click, turns the rectangle grey. It doesn't seem to be working at all and I cant work out why. Am I missing something that needs to be added?

public class Cinema extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {

            Screen screen1 = new Screen(8, 14);

            Pane root = FXMLLoader.load(getClass().getResource("Cinema.fxml"));

            Scene scene = new Scene(root, 400, 400);

            VBox seatHolder = new VBox(5);

            seatHolder.setPrefWidth(root.getWidth());
            seatHolder.setPrefHeight(root.getHeight());

            seatHolder.prefWidthProperty().bind(root.widthProperty());
            seatHolder.prefHeightProperty().bind(root.heightProperty());

            seatHolder.setAlignment(Pos.CENTER);

            for (int i = 0; i < screen1.getSeats().length; i++) {

                HBox hbox = new HBox();

                hbox.setSpacing(1);

                hbox.setAlignment(Pos.CENTER);

                for (int j = 0; j < screen1.getSeats()[i].length; j++) {

                    Rectangle r = new Rectangle(30, 40);

                    r.setOnMouseClicked(new EventHandler<MouseEvent>() {

                        @Override
                        public void handle(MouseEvent event) {

                            r.setFill(Color.GREEN);
                        }
                    });

                    hbox.getChildren().add(r);

                    r.widthProperty().bind(root.heightProperty().divide(15));
                    r.heightProperty().bind(root.widthProperty().divide(30));

                    if (screen1.getSeats()[i][j] != null) {

                        r.setFill(Color.RED);
                    }

                    else {

                        r.setFill(Color.BLUE);
                    }

                }

                seatHolder.getChildren().add(hbox);
            }

            root.getChildren().add(seatHolder);

            HBox screenHolder = new HBox();

            screenHolder.setPrefWidth(root.getWidth());
            screenHolder.setPrefHeight(root.getHeight());

            screenHolder.prefWidthProperty().bind(root.widthProperty());
            screenHolder.prefHeightProperty().bind(root.heightProperty());

            Rectangle screen = new Rectangle(350, 25);

            screen.widthProperty().bind(seatHolder.widthProperty());

            screen.setFill(Color.LIGHTSLATEGREY);

            screenHolder.getChildren().add(screen);

            screenHolder.setAlignment(Pos.BOTTOM_CENTER);

            root.getChildren().add(screenHolder);

            primaryStage.setScene(scene);
            primaryStage.show();

        }

        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Edit: This is the FXML content, the root node is just a blank pane

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.shape.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.Pane?>


<Pane maxHeight="-Infinity" maxWidth="-Infinity"
    minHeight="-Infinity" minWidth="-Infinity" prefHeight="558.0"
    prefWidth="714.0" xmlns="http://javafx.com/javafx/8"
    xmlns:fx="http://javafx.com/fxml/1" />

Also custom screen class defines the 2d seats array used in the loop

public class Screen {

    private String [][] seats;

    public Screen(int rows, int columns) {

        this.seats = new String [rows][columns];
    }

    public String[][] getSeats() {

        return seats;
    }
}
Samuel Philipp :

The problem is that the seatHolder pane is added before screenHolder pane. This causes the screenHolder to be above the seatHolder. You can easy see this by adding screenHolder.setStyle("-fx-background-color: #ffff00;");. In this case your EventHandler is never called. You can check this by printing something in the handler method.

You can fix this by changing the order the panes are added to the root pane (root.getChildren().addAll(screenHolder, seatHolder);). The first one is the lowest, the last one the highest. Alternatively you can also change your Layout.

I would suggest to change the Layout and use a BorderPane:

BorderPane root = new BorderPane();
Scene scene = new Scene(root, 400, 400);
VBox seatHolder = new VBox(5);
seatHolder.setAlignment(Pos.CENTER);

// setup seatHolder as before but use 

root.setCenter(seatHolder);

HBox screenHolder = new HBox();
Rectangle screen = new Rectangle(350, 25);
screen.widthProperty().bind(seatHolder.widthProperty());
screen.setFill(Color.LIGHTSLATEGREY);
screenHolder.getChildren().add(screen);
screenHolder.setAlignment(Pos.BOTTOM_CENTER);
root.setBottom(screenHolder);
primaryStage.setScene(scene);
primaryStage.show();

This should work for you. In this case you even don't need a fxml file.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=146355&siteId=1