Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I fire internal close request?

I have trouble when closing a window in JavaFX.

I define my setOnCloseRequest as I wanted and it works when I click the x in the window. However, I also need a button to close the window and this onCloseRequest has to work, the problem is it does not. The event does not fire at all.

I am using JavaFX 2.2 (Java 7) and I notice that the reference for setOnCloseRequest says close the window on external request

like image 960
caju Avatar asked Apr 17 '15 22:04

caju


Video Answer


1 Answers

Solution

Fire an event from your internal close request (on the button push), so that the application thinks it received an external close request. Then your close request logic can be identical whether the request came from an external event or an internal one.

private EventHandler<WindowEvent> confirmCloseEventHandler = event -> {
        // close event handling logic.
        // consume the event if you wish to cancel the close operation.
}

...

stage.setOnCloseRequest(confirmCloseEventHandler);

Button closeButton = new Button("Close Application");
closeButton.setOnAction(event ->
        stage.fireEvent(
                new WindowEvent(
                        stage,
                        WindowEvent.WINDOW_CLOSE_REQUEST
                )
        )
);

Note

This is a Java 8+ solution, for JavaFX 2, you will need to convert the lambda functions in anonymous inner classes and will be unable to use the Alert dialog box but will need to provide your own alert dialog system as JavaFX 2 does not feature an in-built one. I strongly recommend upgrading to Java 8+ rather than staying with JavaFX 2.

Sample UI

close app

close confirm

Sample Code

The sample code will show the user a close confirmation alert and cancel the close request if the user does not confirm the close.

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.*;
import javafx.stage.WindowEvent;

import java.util.Optional;

public class CloseConfirm extends Application {

    private Stage mainStage;

    @Override
    public void start(Stage stage) throws Exception {
        this.mainStage = stage;
        stage.setOnCloseRequest(confirmCloseEventHandler);

        Button closeButton = new Button("Close Application");
        closeButton.setOnAction(event ->
                stage.fireEvent(
                        new WindowEvent(
                                stage,
                                WindowEvent.WINDOW_CLOSE_REQUEST
                        )
                )
        );

        StackPane layout = new StackPane(closeButton);
        layout.setPadding(new Insets(10));

        stage.setScene(new Scene(layout));
        stage.show();
    }

    private EventHandler<WindowEvent> confirmCloseEventHandler = event -> {
        Alert closeConfirmation = new Alert(
                Alert.AlertType.CONFIRMATION,
                "Are you sure you want to exit?"
        );
        Button exitButton = (Button) closeConfirmation.getDialogPane().lookupButton(
                ButtonType.OK
        );
        exitButton.setText("Exit");
        closeConfirmation.setHeaderText("Confirm Exit");
        closeConfirmation.initModality(Modality.APPLICATION_MODAL);
        closeConfirmation.initOwner(mainStage);

        // normally, you would just use the default alert positioning,
        // but for this simple sample the main stage is small,
        // so explicitly position the alert so that the main window can still be seen.
        closeConfirmation.setX(mainStage.getX());
        closeConfirmation.setY(mainStage.getY() + mainStage.getHeight());

        Optional<ButtonType> closeResponse = closeConfirmation.showAndWait();
        if (!ButtonType.OK.equals(closeResponse.get())) {
            event.consume();
        }
    };

    public static void main(String[] args) {
        launch(args);
    }

}
like image 139
jewelsea Avatar answered Oct 01 '22 14:10

jewelsea