如何在JavaFX FXML应用程序中打开一个额外的窗口?

时间:2016-03-17 21:12:37

标签: java javafx window fxml scene

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

所有教程都略有偏差。他们描述了如何在纯JavaFX中执行此操作,这显然与您使用FXML的方式不同,或者他们解释了如何切换关闭旧场景的场景。我猜它很简单,沿着定义FXML布局及其控制器的方式,用它们创建一个新的场景,然后调用像

这样的东西
theStage.showScene(userInputWindow);

但是一个有效的解决方案似乎要复杂得多,其背后的推理与我的假设不同。例如在this tutorial中,我真的不明白为什么他们会把那些演员放在那里,FXMLLoader()实际上会做什么,或者我将如何将其中任何一个调整到手头的任务中。此外,资源声明"舞台一次只能显示1个场景"。对于我来说,JavaFX应用程序似乎不太可能缺少显示新窗口而不关闭旧窗口这样的微不足道的功能。也许我误解了舞台和场景是什么以及他们能做些什么。所以我需要知道:

  1. 如何在代码中实现上述效果?

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

2 个答案:

答案 0 :(得分:4)

您只能在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();
}

控制器

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

}

FXML

<GridPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mypackage.InputController" vgap="10" hgap="10"  >
  <columnConstraints>
    <ColumnConstraints prefWidth="150.0" />
    <ColumnConstraints prefWidth="150.0" />
  </columnConstraints>
   <children>
      <TextField GridPane.columnIndex="1" fx:id="mealField" onAction="#submit" />
      <Button mnemonicParsing="false" text="Ok" GridPane.columnIndex="1" GridPane.rowIndex="1" onAction="#submit" />
      <Label text="Your favourite meal" />
   </children>
   <padding>
      <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
   </padding>
</GridPane>

答案 1 :(得分:1)

在第一句话中,您描述了一个看起来像是使用Dialogs的理想候选人的场景。你看过Dialog课了吗?当然可以在JavaFX中打开尽可能多的窗口(也称为阶段),但是对于你所描述的场景,Dialog似乎是更容易和更合适的解决方案。