JavaFX 将一个节点放在一个单独的 class 文件中

JavaFX Put a node in a separated class file

如何将名为“sellingPane”的 GridPane 放在单独的 class 文件中,但仍在此 class 中使用它?我希望能够更改场景中不同 GridPane 的 GridPane。我想了解如何将节点放在不同的 class 文件中并将它们放在一起以创建场景。 我试图将 sellingPane 放在不同的 class 中,并使用“return sellingPane”到 return,GridPane 到 MainWindowView.java,但我不知道如何制作按钮setOnAction 函数起作用。 一个小程序作为例子会很有帮助。

import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import nl.inholland.cinemamarkkea.controllers.MovieController;
import nl.inholland.cinemamarkkea.models.Movie;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

public class MainWindowView extends HBox {
    private ObservableList<Movie> room1Movies;
    private ObservableList<Movie> room2Movies;
    private Movie movie;

    public MainWindowView(MovieController movieController){
        Label title = new Label("Purchase tickets");
        title.setFont(new Font("Arial", 24));
        title.setTextFill(Color.web("#286DA3"));

        room1Movies = movieController.getRoom1Movies();
        room2Movies = movieController.getRoom2Movies();

        //Tableview for the room1Movies
        Label room1Label = new Label("Room 1");
        room1Label.setFont(new Font("Arial", 12));

        TableView<Movie> room1TableView = new TableView<>();
        room1TableView.setMinWidth(450);

        TableColumn<Movie, LocalDateTime> start1Column = new TableColumn<>("Start");
        start1Column.setCellValueFactory(Movie -> {
            SimpleObjectProperty startLabel= new SimpleObjectProperty();
            DateTimeFormatter format = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
            startLabel.setValue(Movie.getValue().getStartDateTime().format(format));
            return startLabel;
        });

        TableColumn<Movie, LocalDateTime> end1Column = new TableColumn<>("End");
        end1Column.setCellValueFactory(Movie -> {
            SimpleObjectProperty endLabel= new SimpleObjectProperty();
            DateTimeFormatter format = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
            endLabel.setValue(Movie.getValue().getEndDateTime().format(format));
            return endLabel;
        });

        TableColumn<Movie, String> title1Column = new TableColumn<>("Title");
        title1Column.setCellValueFactory(new PropertyValueFactory<>("title"));

        TableColumn<Movie, Integer> seats1Column = new TableColumn<>("Seats");
        seats1Column.setCellValueFactory(new PropertyValueFactory<>("seats"));

        TableColumn<Movie, Double> price1Column = new TableColumn<>("Price");
        price1Column.setCellValueFactory(new PropertyValueFactory<>("price"));

        room1TableView.getColumns().addAll(start1Column, end1Column, title1Column, seats1Column, price1Column);
        room1TableView.setItems(room1Movies);

        //Tableview for the room2Movies
        Label room2Label = new Label("Room 2");
        room2Label.setFont(new Font("Arial", 12));

        TableView<Movie> room2TableView = new TableView<>();
        room2TableView.setMinWidth(450);

        TableColumn<Movie, LocalDateTime> start2Column = new TableColumn<>("Start");
        start2Column.setCellValueFactory(Movie -> {
            SimpleObjectProperty startLabel= new SimpleObjectProperty();
            DateTimeFormatter format = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
            startLabel.setValue(Movie.getValue().getStartDateTime().format(format));
            return startLabel;
        });

        TableColumn<Movie, LocalDateTime> end2Column = new TableColumn<>("End");
        end2Column.setCellValueFactory(Movie -> {
            SimpleObjectProperty endLabel= new SimpleObjectProperty();
            DateTimeFormatter format = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
            endLabel.setValue(Movie.getValue().getEndDateTime().format(format));
            return endLabel;
        });

        TableColumn<Movie, String> title2Column = new TableColumn<>("Title");
        title2Column.setCellValueFactory(new PropertyValueFactory<>("title"));

        TableColumn<Movie, Integer> seats2Column = new TableColumn<>("Seats");
        seats2Column.setCellValueFactory(new PropertyValueFactory<>("seats"));

        TableColumn<Movie, Double> price2Column = new TableColumn<>("Price");
        price2Column.setCellValueFactory(new PropertyValueFactory<>("price"));

        room2TableView.getColumns().addAll(start2Column, end2Column, title2Column, seats2Column, price2Column);
        room2TableView.setItems(room2Movies);

        Label roomLabel = new Label("Room");
        Label roomNameLabel = new Label("");

        Label movieLabel = new Label("Movie title");
        Label movieNameLabel = new Label();

        Label startLabel = new Label("Start");
        Label startTimeLabel = new Label();

        Label seatsLabel = new Label("No. of seats");
        ComboBox<Integer> seatsBox = new ComboBox<Integer>();
        seatsBox.getItems().add(0);
        seatsBox.getItems().add(1);
        seatsBox.getItems().add(2);

        Button purchaseButton = new Button("Purchase");

        Label endLabel = new Label("End");
        Label endTimeLabel = new Label();

        Label nameLabel = new Label("Name");
        TextField nameInput = new TextField();
        nameInput.setMaxWidth(150);

        Button clearButton = new Button("Clear");

        //selling tickets pane
        GridPane sellingPane = new GridPane();

        sellingPane.add(roomLabel, 0, 0, 1, 1);
        sellingPane.add(roomNameLabel, 1, 0, 1, 1);

        sellingPane.add(movieLabel, 2, 0, 1, 1);
        sellingPane.add(movieNameLabel, 3, 0, 1, 1);

        sellingPane.add(startLabel, 0, 1, 1, 1);
        sellingPane.add(startTimeLabel, 1, 1, 1, 1);

        sellingPane.add(seatsLabel, 2, 1, 1, 1);
        sellingPane.add(seatsBox, 3, 1, 1, 1);

        sellingPane.add(purchaseButton, 4, 1, 1, 1);

        sellingPane.add(endLabel, 0, 2, 1, 1);
        sellingPane.add(endTimeLabel, 1, 2, 1, 1);

        sellingPane.add(nameLabel, 2, 2, 1, 1);
        sellingPane.add(nameInput, 3, 2, 1, 1);

        sellingPane.add(clearButton, 4,2,1,1);

        //hide pane when no movie is selected
        sellingPane.setVisible(false);

        sellingPane.setVgap(10);
        sellingPane.setHgap(40);
        sellingPane.setStyle("-fx-padding: 10;" + "-fx-border-width: 2;");
        

        room1TableView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) ->{
            movie = newSelection;
            if (newSelection != null){
                sellingPane.setVisible(true);
                roomNameLabel.setText("Room 1");
                movieNameLabel.setText(newSelection.getTitle());

                DateTimeFormatter format = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
                startTimeLabel.setText(newSelection.getStartDateTime().format(format));

                endTimeLabel.setText(newSelection.getEndDateTime().format(format));
            }
        });

        room2TableView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) ->{
            movie = newSelection;
            if (newSelection != null){
                sellingPane.setVisible(true);
                roomNameLabel.setText("Room 2");
                movieNameLabel.setText(newSelection.getTitle());

                DateTimeFormatter format = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
                startTimeLabel.setText(newSelection.getStartDateTime().format(format));

                endTimeLabel.setText(newSelection.getEndDateTime().format(format));
            }
        });


        Label errorLabel = new Label();

        clearButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                //hide form
                sellingPane.setVisible(false);
                //clear combobox
                seatsBox.valueProperty().set(null);
                //clear name input field
                nameInput.clear();
                //clear error message
                errorLabel.setText("");
                //unselect row in table
                room1TableView.getSelectionModel().select(null);
                room2TableView.getSelectionModel().select(null);
                //clear movie
                movie = null;
            }
        });

        purchaseButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                Integer selectedSeats = seatsBox.getValue();
                String name = nameInput.getText();
                if (selectedSeats == null || selectedSeats == 0){
                    errorLabel.setText("The minimum number of tickets you need to buy 1.");
                } else if (name == null) {
                    errorLabel.setText("Please fill in your name.");
                } else if (movie.getSeats() == 0) {
                    errorLabel.setText("There are no seats left for this movie, please try different room.");
                } else {
                    //clear error message from possible previous attempt
                    errorLabel.setText("");

                    Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
                    alert.setTitle("Confirm payment");
                    alert.setHeaderText("Please confirm payment");
                    alert.setContentText("Do you want to buy tickets for this movie?");
                    Optional<ButtonType> result = alert.showAndWait();
                    if (result.get() == ButtonType.OK){
                        movieController.purchaseTicket(movie, selectedSeats, name, roomNameLabel.getText());
                        room1TableView.refresh();
                        room2TableView.refresh();
                        //clear and hide form
                        clearButton.fire();
                    }
                }
            }
        });

        VBox mainPane = new VBox();
        //rooms together
        HBox roomsPane = new HBox();
        //rooms
        VBox room1Pane = new VBox();
        VBox room2Pane = new VBox();

        roomsPane.setStyle("-fx-padding: 10;" +
                "-fx-border-style: solid inside;" +
                "-fx-border-width: 2;" +
                "-fx-border-color: #8398AE;");
        roomsPane.setSpacing(10);


        room2Pane.getChildren().addAll(room2Label, room2TableView);
        room1Pane.getChildren().addAll(room1Label, room1TableView);
        roomsPane.getChildren().addAll(room1Pane, room2Pane);
        mainPane.getChildren().addAll(title, roomsPane, sellingPane, errorLabel);

        this.getChildren().addAll(mainPane);
    }
}

您需要努力将视图与控制器分开。本质上,您需要处理模型视图控制器 (MVC)。您的控制器应该处理事件等。例如,这里不使用匿名 class

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

在您的控制器中创建一个方法class。

public class SellingPaneController{
    Node sellingPane;
    Button purchaseButton;
    ComboBox<Integer> seatsBox;
    public SellingPaneController(){
        sellingPane = ...;
        purchaseButton = ...;
        purchaseButton.setOnAction(this::purchaseButtonAction);
    }
    public void purchaseButtonAction( ActionEvent actionEvent ){
        //All of you local GUI classes here should be part of the grid view.
    }

    public Node getSellingPane(){ return sellingPane;}
}

当您创建控制器时,它将构建 GUI 元素并附加侦听器。

注意:这是 FXML 的优势,它会为您构建 gui 组件并附加监听器。您只需声明所有字段并编写事件处理程序。

这是一项相当大的工作量,因为您已将所有内容捆绑在一起。例如 room1Movies 是 MovieController 的一部分。您可能会做一些事情,例如让您的 SellingPaneController 构造函数将 MovieController 作为参数,然后它可以保留引用。