JavaFX:阶段关闭处理程序

Posted

技术标签:

【中文标题】JavaFX:阶段关闭处理程序【英文标题】:JavaFX: Stage close handler 【发布时间】:2014-12-24 12:29:54 【问题描述】:

我想在关闭我的 JavaFX 应用程序之前保存一个文件。

这就是我在Main::start 中设置处理程序的方式:

primaryStage.setOnCloseRequest(event -> 
    System.out.println("Stage is closing");
    // Save file
);

当按下按钮时控制器调用Stage::close

@FXML
public void exitApplication(ActionEvent event) 
    ((Stage)rootPane.getScene().getWindow()).close();

如果我单击窗口边框上的红色 X 关闭窗口(正常方式),则会收到输出消息“Stage is closing”,这是所需的行为。

但是,当调用 Controller::exitApplication 时,应用程序会在不调用处理程序的情况下关闭(没有输出)。

如何让控制器使用我添加到primaryStage 的处理程序?

【问题讨论】:

【参考方案1】:

如果您查看 Application 类的 life-cycle:

JavaFX 运行时按顺序执行以下操作,只要 应用程序启动:

    构造指定应用程序类的实例 调用init()方法 调用start(javafx.stage.Stage)方法 等待应用程序完成,当发生以下任一情况时会发生这种情况: 应用程序调用Platform.exit() 最后一个窗口已关闭,Platform 上的implicitExit 属性为true 调用stop()方法

这意味着您可以在控制器上调用Platform.exit()

@FXML
public void exitApplication(ActionEvent event) 
   Platform.exit();

只要重写主类上的stop() 方法即可保存文件。

@Override
public void stop()
    System.out.println("Stage is closing");
    // Save file

如您所见,通过使用stop(),您不再需要收听关闭请求来保存文件(但如果您想阻止窗口关闭,您可以这样做)。

【讨论】:

【参考方案2】:

假设您想询问用户是否要退出应用程序而不保存工作。如果用户选择 no,则无法避免应用程序在 stop 方法内关闭。在这种情况下,您应该为 WINDOW_CLOSE_REQUEST 事件将 EventFilter 添加到您的窗口

在你的 start 方法中添加这个代码来检测事件:

(请注意,调用 Platform.exit(); 不会触发 WindowEvent.WINDOW_CLOSE_REQUEST 事件,请参阅下文了解如何从自定义手动触发事件按钮)

// *** Only for Java >= 8 ****
// ==== This code detects when an user want to close the application either with
// ==== the default OS close button or with a custom close button ====

primaryStage.getScene().getWindow().addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, this::closeWindowEvent);

然后添加您的自定义逻辑。在我的示例中,我使用警报弹出窗口询问用户他/她是否要关闭应用程序而不保存。

private void closeWindowEvent(WindowEvent event) 
        System.out.println("Window close request ...");

        if(storageModel.dataSetChanged())   // if the dataset has changed, alert the user with a popup
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.getButtonTypes().remove(ButtonType.OK);
            alert.getButtonTypes().add(ButtonType.CANCEL);
            alert.getButtonTypes().add(ButtonType.YES);
            alert.setTitle("Quit application");
            alert.setContentText(String.format("Close without saving?"));
            alert.initOwner(primaryStage.getOwner());
            Optional<ButtonType> res = alert.showAndWait();

            if(res.isPresent()) 
                if(res.get().equals(ButtonType.CANCEL))
                    event.consume();
            
        
    

event.consume() 方法阻止应用程序关闭。显然,您应该至少添加一个允许用户关闭应用程序的按钮,以避免用户强制关闭应用程序,这在某些情况下会损坏数据。

最后,如果你必须从自定义关闭按钮触发事件,你可以使用这个:

Window window = Main.getPrimaryStage()  // Get the primary stage from your Application class
                .getScene()
                .getWindow();

window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));

【讨论】:

对我的用例非常有用,我有一个简单的对话框并且没有继承 Application 类。【参考方案3】:

啊,这是 JavaFX 中的一个已知错误,如果在关闭时存在模式对话框,舞台将不会关闭。我会将您链接到我今天刚刚看到的错误报告。我认为它已在最新版本中修复。

给你:

https://bugs.openjdk.java.net/browse/JDK-8093147?jql=text%20~%20%22javafx%20re-entrant%22

它说在 8.4 中解决。我想这就是你所描述的。

【讨论】:

【参考方案4】:
public Stage getParentStage() 
    return (Stage) getFxmlNode().getScene().getWindow();


btnCancel.setOnAction(e -> 
    getParentStage().close();
);

【讨论】:

很好,您试图提供帮助 - 但这并不能解决 OP 的问题:没有按钮 ;)

以上是关于JavaFX:阶段关闭处理程序的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX 2.0:关闭阶段(窗口)

如何在 JavaFX 中获得一个阶段的关闭事件?

如何在一定时间后关闭一个阶段JavaFX

JavaFX如何改变阶段

在普通 Java 应用程序中创建 JavaFX 初级阶段

在JavaFX中为TextField设置KeyPressed事件