如何在JavaFX FXML应用程序中打开其他窗口?

Sar*_*on1 2 java javafx window scene fxml

在我的JavaFX FXML应用程序中,我希望用户单击主窗口中某个地方的菜单项时弹出一个辅助窗口,以便用户可以在其中输入一些输入,然后在单击按钮时将其输入到应用程序中,辅助窗口将关闭。

那里的所有教程都略有偏离。他们描述了如何在纯JavaFX中执行此操作,这显然与您在FXML中使用的方式不同,或者他们解释了如何切换场景,从而关闭了旧的场景。我想这很简单,按照定义FXML布局及其Controller,用它们创建一个新的Scene,然后调用类似

theStage.showScene(userInputWindow);
Run Code Online (Sandbox Code Playgroud)

但是有效的解决方案似乎要复杂得多,其背后的原因也与我的假设不同。例如,在本教程中,我并不真正理解他们为什么将这些转换放在那里,FXMLLoader()的实际作用,或者实际上我将如何适应当前的任务。此外,资源指出“舞台一次只能显示1个场景”。在我看来,JavaFX应用程序似乎缺乏像显示新窗口而不关闭旧窗口这样琐碎的功能。也许我误解了舞台和场景是什么以及它们可以做什么。所以我需要知道:

  1. 如何在代码中达到上述效果?

  2. 解决方案背后的原因是什么?那里涉及的所有事情是什么?

fab*_*ian 5

您只能在中显示一个场景Stage,但可以创建多个阶段。如果要在辅助窗口中使用fxml,则应使用控制器实例,并以允许访问用户输入的方式设计控制器。您可以使用Stage.showAndWait“等待用户完成输入”。

申请开始方法

请注意,这里只是打开新窗口的按钮,但是您可以在onAction菜单项的事件处理程序中使用类似的逻辑。(在这种情况下,您需要使用someNode.getScene().getWindow()来访问父窗口;Stage.initOwner在父窗口中someNode是任意Node的;您可以从事件(((Node)event.getTarget()))获取节点,也可以使用场景中已知的节点;在InputController.submit mealField中使用以此目的)

@Override
public void start(Stage primaryStage) {
    Button btn = new Button();
    btn.setText("Choose favorite meal");

    Label label = new Label("I don't know your favorite meal yet!");

    btn.setOnAction((ActionEvent event) -> {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("input.fxml"));
        Scene newScene;
        try {
            newScene = new Scene(loader.load());
        } catch (IOException ex) {
            // TODO: handle error
            return;
        }

        Stage inputStage = new Stage();
        inputStage.initOwner(primaryStage);
        inputStage.setScene(newScene);
        inputStage.showAndWait();

        String meal = loader.<InputController>getController().getMeal();

        label.setText(meal == null ? "C'mon, tell me your favourite meal already!" : "Your favourite meal is "+meal+". Interesting!");
    });

    VBox root = new VBox(label, btn);
    root.setSpacing(10);
    root.setPadding(new Insets(10));
    root.setPrefWidth(300);

    Scene scene = new Scene(root);

    primaryStage.setScene(scene);
    primaryStage.show();
}
Run Code Online (Sandbox Code Playgroud)

控制者

public class InputController {
    @FXML
    private TextField mealField;
    private boolean mealChosen;

    @FXML
    private void submit() {
        mealChosen = true;
        mealField.getScene().getWindow().hide();
    }

    public String getMeal() {
        return mealChosen ? mealField.getText() : null;
    }

}
Run Code Online (Sandbox Code Playgroud)

文件

@Override
public void start(Stage primaryStage) {
    Button btn = new Button();
    btn.setText("Choose favorite meal");

    Label label = new Label("I don't know your favorite meal yet!");

    btn.setOnAction((ActionEvent event) -> {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("input.fxml"));
        Scene newScene;
        try {
            newScene = new Scene(loader.load());
        } catch (IOException ex) {
            // TODO: handle error
            return;
        }

        Stage inputStage = new Stage();
        inputStage.initOwner(primaryStage);
        inputStage.setScene(newScene);
        inputStage.showAndWait();

        String meal = loader.<InputController>getController().getMeal();

        label.setText(meal == null ? "C'mon, tell me your favourite meal already!" : "Your favourite meal is "+meal+". Interesting!");
    });

    VBox root = new VBox(label, btn);
    root.setSpacing(10);
    root.setPadding(new Insets(10));
    root.setPrefWidth(300);

    Scene scene = new Scene(root);

    primaryStage.setScene(scene);
    primaryStage.show();
}
Run Code Online (Sandbox Code Playgroud)