stage.hide() 没有关闭 window

stage.hide() doesn't close window

我有一个 JavaFX 应用程序,我创建了一个切换按钮,可以将图表弹出到新的(非模态)window。该按钮旨在将图表弹出回主应用程序 window 的 VBox。如果手动关闭新图表window,图表也会returns到原来的VBox。

下面的代码是一个通用的 setOnAction 函数 (setToggleButton),我在初始化时为与其自己的图表关联的多个按钮调用该函数。

例如:


@Component
public class SummaryView {

    private GraphService graphService;
    @FXML
    private VBox powerChartVBox;
    @FXML
    private LineChart<Number, Number> powerChart;
    @FXML
    private Button openPowerChart;
    @FXML
    private NumberAxis powerAxis;

    public void setButtonToggle(Button button, LineChart<Number, Number> chart, VBox homeBox) {
        var ref = new Object() {
            Boolean popIn = false; // changes to allow toggle
        };

        button.setOnAction(actionEvent -> {
            VBox windowBox = new VBox();
            Stage stage = new Stage();
            Scene scene = new Scene(windowBox);
            stage.setOnCloseRequest(event -> {
                homeBox.getChildren().add(chart);
                ref.popIn = false;
                button.setText("Pop Out");
            });

            if (!ref.popIn){
                windowBox.getChildren().add(chart);
                stage.setScene(scene);
                stage.show();
                ref.popIn = true;
                button.setText("Pop In");
            } else {
                stage.hide(); // how to get this line to work?
                homeBox.getChildren().add(chart);
                ref.popIn = false;
                button.setText("Pop Out");
            }
        });
    }

    @FXML
    public void initialize() {
        graphService = SpringContext.getBean(GraphService.class);

        Platform.runLater(() -> {
            setButtonToggle(openPowerChart, powerChartStage, powerChart, powerChartVBox); 
        // in my application I call this function a few more times on other nodes as well
        });
    }

    @Scheduled(fixedRate = 300000)
    private void updateCharts() {
        Platform.runLater(() -> {
            XYChart.Series<Number, Number> outputKWSeries = graphService.updateKWOutputSeries();
            XYChart.Series<Number, Number> outputKVSeries = graphService.updateKVOutputSeries();
            XYChart.Series<Number, Number> outputKASeries = graphService.updateKAOutputSeries();
            powerAxis.setUpperBound(graphService.getUpperBound());
            powerAxis.setLowerBound(graphService.getLowerBound(40));
            powerChart.getData().clear();
            powerChart.getData().addAll(outputKWSeries, outputKVSeries, outputKASeries);
    })

}

但是,我使用“弹出”操作处理程序创建的新 window 不会从切换按钮关闭(在第一次单击后变为“弹出”,然后使用if/else 语句的第二个分支)。我尝试了各种方法,但没有找到解决方案。如果我尝试 scene.getWindow().hide() 它将导致空指针异常。我目前在下面的内容实际上不会隐藏window,只是将图表移回原来的位置。

这是屏幕截图 - 在顶部,您可以看到当我点击“弹出”按钮时留下的空白 window。

所以此刻,一切都按预期进行,但是当我按下按钮“弹出”window 时,图表 returns 回到了它的主页,但是 window保持空白打开 window。然而,使用它自己的 X 按钮手动关闭 window 会导致所需的行为,只要它还没有被切换按钮变成空白 window,在这种情况下,异常将是:

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Children: duplicate children added: parent = VBox[id=powerChartVBox]

这个异常对我来说很有意义,因为我在舞台上调用的 setOnCloseRequest 正试图将 VBox 添加回主应用程序的 VBox,但它已经存在于那里。

所以总而言之,如何让我的 else 分支的第一行中的 stage.hide() 在我最初创建的阶段执行,并关闭 window?

正如评论中所述,您的问题是因为您在 setOnAction 中创建了舞台。
当您切换按钮时,它会创建一个 Stage 的新实例并且不会影响已经实例化的舞台。

要解决此问题,您应该在 EventHandler.

之外实例化 Stage

有几种方法:

public class YourController{

  // Option 1
  private Stage newStage = new Stage();

  // Options 2 & 3
  private Stage newStage;

  // Option 2
  public YourController(){
    newStage = new Stage();
  }

  @FXML
  public void initialize() {
    // Option 3
    newStage = new Stage(); 
    // Option 4
    Stage newStage = new Stage();
  }

}

请注意,操作 GUI 必须在 JavaFX Application Thread 上进行,因此如果您尝试从另一个线程执行此操作,platform.runLater(); 可能会派上用场。