简体   繁体   中英

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

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;
    }
}

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.

I think this may be an issue with when the value of r is bound vs when it gets used within your handler function.

Within your EventHandler, try the following

@Override
public void handle(MouseEvent event) {
  Rectangle clicked = (Rectangle) event.getSource();
  clicked.setFill(Color.GREEN);
}

instead of referencing r within the handler.

EDIT: Looks like the screenHolder covers all the seats, so your clicks never register. Try setting the screenHolder dimensions to match the screen itself:

Rectangle screen = new Rectangle(350, 25);

screenHolder.setPrefWidth(screen.getWidth());
screenHolder.setPrefHeight(screen.getHeight());
screenHolder.prefWidthProperty().bind(screen.heightProperty());
screenHolder.prefHeightProperty().bind(screen.heightProperty());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM