【问题标题】:How to open an additional window in a JavaFX FXML app?如何在 JavaFX FXML 应用程序中打开一个附加窗口?
【发布时间】:2016-07-04 11:08:01
【问题描述】:

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

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

theStage.showScene(userInputWindow);

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

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

  2. 解决方案背后的原因是什么;所有相关的东西都在那里做什么?

【问题讨论】:

  • 你能展示你目前拥有的东西吗?您的菜单和菜单项是否在 FXML 中定义?你有控制器类吗?你有相关菜单项的处理方法吗?这里和你说你已经看到的东西没有什么不同,所以如果不显示你已经走了多远的基本结构,任何人都很难知道你错过了哪一部分。
  • 哦,顺便说一句,您链接的教程充满了错误和根本不正确的陈述:我的建议是忽略它(我已经向作者指出了这些,但他忽略了它们,所以...)。
  • “舞台一次只能显示一个场景”虽然是一个真实的说法,但我不明白为什么你认为这意味着你不能打开第二个窗口。在 JavaFX 中,Stage 是一个窗口。每个人只有一个场景。但显然,您可以根据需要创建和展示任意数量的阶段。

标签: java javafx window fxml scene


【解决方案1】:

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>

【讨论】:

  • 您能否澄清一下“someNode.getScene().getWindow()”部分?我确实试图在单击菜单项时显示这个新窗口,但是如果我只是将您的 btn.setOnAction 代码复制到我的处理程序并重构以适应,我会收到 InvocationTarget 异常。
  • @Sargon1: someNode 只是打开窗口供用户输入的窗口场景图中的任意节点。
  • 好的,现在好像可以了。有一些问题,但结果是我忘记在辅助窗口控制器中对一些方法进行@FXML 注释,并且无法从神秘的错误消息中找出答案。但是,我的应用程序仅适用于“inputStage.initOwner(theStage);”(和“import javafx.stage.Stage;”)这一行,而不是你建议的,在这种情况下它会抛出一个 NullPointer。为什么会这样,我的做法难道不是一种不好的做法吗?
  • @Sargon1:我不知道您使用的确切代码,但是如果您在将节点层次结构添加到 @ 之前尝试获取 Scene/Window,可能会导致 NPE 987654338@/Window。您需要在事件处理程序中获取场景/舞台。如果 NPE 是由其他原因引起的,那么……如果没有代码,就不可能说出任何关于 if 的信息。
【解决方案2】:

在您的第一句话中,您描述了一个看起来是使用对话框的理想候选者的场景。你看过 Dialog 类吗?当然,您可以在 JavaFX 中打开任意数量的窗口(也称为阶段),但对于您描述的场景,对话框似乎是更简单、更合适的解决方案。

【讨论】:

    猜你喜欢
    • 2015-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-13
    • 2017-05-15
    • 1970-01-01
    • 2019-06-25
    • 2021-06-30
    相关资源
    最近更新 更多