简体   繁体   English

包含EventHandler的循环无法按预期用于javafx的方式工作?

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

I am new to JavaFX and am having trouble using the setOnMouseClicked method. 我是JavaFX的新手,使用setOnMouseClicked方法时遇到麻烦。 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 编辑:这是FXML内容,根节点只是一个空白窗格

<?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. 问题在于,在seatHolder窗格之前添加了screenHolder窗格。 This causes the screenHolder to be above the seatHolder . 这导致screenHolder高于seatHolder You can easy see this by adding screenHolder.setStyle("-fx-background-color: #ffff00;"); 您可以通过添加screenHolder.setStyle("-fx-background-color: #ffff00;");轻松地看到这一点screenHolder.setStyle("-fx-background-color: #ffff00;"); . In this case your EventHandler is never called. 在这种情况下,永远不会调用您的EventHandler。 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); ). 您可以通过更改将窗格添加到根窗格的顺序来解决此问题( 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

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. 在这种情况下,您甚至不需要fxml文件。

I think this may be an issue with when the value of r is bound vs when it gets used within your handler function. 我认为这可能与何时绑定r的值与何时在处理函数中使用它有关。

Within your EventHandler, try the following 在您的EventHandler中,尝试以下操作

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

instead of referencing r within the handler. 而不是在处理程序中引用r

EDIT: Looks like the screenHolder covers all the seats, so your clicks never register. 编辑:看起来screenHolder涵盖了所有席位,因此您的点击永远不会注册。 Try setting the screenHolder dimensions to match the screen itself: 尝试设置screenHolder尺寸以匹配屏幕本身:

Rectangle screen = new Rectangle(350, 25);

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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