简体   繁体   English

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

[英]How to open an additional window in a JavaFX FXML app?

In my JavaFX FXML app, I want a secondary window to pop up when the user clicks a menu item somewhere in the primary window so that the user can enter some input into it, which will be then fed to the application upon clicking a button, and the secondary window will be closed. 在我的JavaFX FXML应用程序中,我希望用户单击主窗口中某处的菜单项时弹出一个辅助窗口,以便用户可以在其中输入一些输入,然后在单击按钮时将其输入到应用程序中,辅助窗口将关闭。

All the tutorials out there are slightly off the mark. 那里的所有教程都略有偏离。 They describe how to do it in pure JavaFX, which is apparently different from the way you'd use with FXML, or they explain how to switch Scenes, which closes the old Scene. 他们描述了如何在纯JavaFX中执行此操作,这显然与您在FXML中使用的方式不同,或者他们解释了如何切换场景,从而关闭了旧的场景。 I'd guess it would be simple enough, along the lines of defining the FXML layout and its Controller, creating a new Scene with them, and then calling something like 我想这很简单,按照定义FXML布局及其Controller,用它们创建新的Scene,然后调用类似

theStage.showScene(userInputWindow);

but a working solution seems much more complicated, and the reasoning behind it different from my assumptions. 但是有效的解决方案似乎要复杂得多,其背后的原因也与我的假设不同。 For example in this tutorial , I don't really understand why did they put that cast in there, what would the FXMLLoader() actually do, or indeed how would I adapt any of this to the task at hand. 例如,在本教程中 ,我并不真正理解他们为什么将其放入其中,FXMLLoader()的实际作用,或者实际上我将如何适应当前的任务。 Also, the resource states the "the stage can only show 1 scene at a time". 此外,资源指出“舞台一次只能显示1个场景”。 It seems extremely unlikely to me that a JavaFX app could lack such a trivial feature as showing a new window without closing the old one. 在我看来,JavaFX应用程序似乎缺乏像显示新窗口而不关闭旧窗口这样琐碎的功能。 Maybe I misunderstood something about what a Stage and a Scene are and what they can do. 也许我误解了舞台和场景是什么以及它们可以做什么。 So I need to know: 所以我需要知道:

  1. How to achieve the effect described above in code? 如何在代码中达到上述效果?

  2. What is the reasoning behind the solution; 解决方案背后的原因是什么? what do all the things involved do there? 那里涉及的所有事情是什么?

You can only show one scene in a Stage , but you can create multiple stages. 您只能在Stage显示一个场景,但是可以创建多个Stage If you want to use fxml for your secondary window, you should get your hands on the controller instance and design the controller in a way that allows you to access the user's input. 如果要在辅助窗口中使用fxml,则应使用控制器实例,并以允许访问用户输入的方式设计控制器。 You can use Stage.showAndWait to "wait for the user to complete the input". 您可以使用Stage.showAndWait来“等待用户完成输入”。

Example

Application start method 申请开始方法

Note that here it's just a button that opens the new window, but you could use similar logic in the onAction event handler of a menu item. 请注意,这里只是打开新窗口的按钮,但是您可以在菜单项的onAction事件处理程序中使用类似的逻辑。 (You need to use someNode.getScene().getWindow() to get access to the parent window for Stage.initOwner in this case; someNode is a arbitrary Node in the parent window; you could get the node from the event ( ((Node)event.getTarget()) ) or use a node that you know is in the scene; in InputController.submit mealField is used for this purpose) (在这种情况下,您需要使用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();
}

controller 调节器

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

In your first sentence you describe a scenario which looks like it is an ideal candidate for using Dialogs. 在第一句话中,您描述了一个场景,它看起来像是使用对话框的理想人选。 Did you have a look at the Dialog class? 您看过Dialog类吗? Of course it is possible to open as many windows (aka stages) in JavaFX as you like but for the scenario you describe Dialogs seem to be the easier and better fitting solution. 当然,可以根据需要在JavaFX中打开任意多个窗口(又称阶段),但是对于您所描述的情况,对话框似乎是更简单,更合适的解决方案。

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

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