JavaFXでウィンドウの閉じるボタンを無効化する方法

JavaFXアプリケーションを開発する際、ユーザーが誤ってウィンドウを閉じてしまうのを防ぐために、タイトルバーの閉じるボタン(×ボタン)を無効化したい場合があります。ここでは、その実現方法を解説します。

方法1: JavaコードでWindowEventを処理する

最も一般的なアプローチは、Stageオブジェクトに対してsetOnCloseRequestメソッドを使用し、イベントを消費することです。

public class AppLauncher extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/view/MainView.fxml"));
        Scene scene = new Scene(root);
        
        primaryStage.setTitle("Application");
        primaryStage.setScene(scene);
        
        // 閉じるボタンを無効化
        primaryStage.setOnCloseRequest(event -> {
            event.consume();
        });
        
        primaryStage.show();
    }
}

event.consume()を呼び出すことで、デフォルトのクローズ動作がキャンセルされます。

方法2: FXMLとコントローラーを組み合わせる

FXMLを使用している場合、コントローラーでWindowEventをハンドリングすることも可能です。

MainView.fxml:

<VBox xmlns:fx="http://javafx.com/fxml" 
      fx:controller="controller.MainController">
    
    <children>
        <Label text="Sample Application" />
    </children>
    
</VBox>

MainController.java:

public class MainController implements Initializable {

    @FXML
    private VBox rootContainer;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // ルートノードからWindowを取得してイベントを設定
        rootContainer.sceneProperty().addListener((obs, oldScene, newScene) -> {
            if (newScene != null) {
                newScene.windowProperty().addListener((obsW, oldWindow, newWindow) -> {
                    if (newWindow != null) {
                        ((Stage) newWindow).setOnCloseRequest(this::handleCloseRequest);
                    }
                });
            }
        });
    }

    @FXML
    private void handleCloseRequest(WindowEvent event) {
        // 条件付きで閉じるのを防ぐ
        boolean canClose = checkUnsavedWork();
        if (!canClose) {
            event.consume();
            showWarningAlert();
        }
    }

    private boolean checkUnsavedWork() {
        // 保存チェックロジック
        return false;
    }

    private void showWarningAlert() {
        Alert alert = new Alert(Alert.AlertType.WARNING);
        alert.setTitle("確認");
        alert.setHeaderText("終了できません");
        alert.setContentText("未保存のデータがあります。");
        alert.showAndWait();
    }
}

方法3: 閉じるボタンを完全に非表示にする

ボタン自体を見えなくしたい場合は、Stageの初期化時にステージスタイルを変更します。

Stage stage = new Stage();
stage.initStyle(StageStyle.UTILITY);
stage.initStyle(StageStyle.UNDECORATED);

ただし、UNDECORATEDを指定するとタイトルバー全体が非表示になるため、用途に応じて使い分ける必要があります。

注意点

event.consume()でクローズをブロックした場合でも、Platform.exit()System.exit()による終了は防げません。アプリケーションの終了処理を完全に制御したい場合は、Applicationクラスのstop()メソッドも併せてオーバーライドすることを推奨します。

タグ: JavaFX FXML Stage WindowEvent

7月11日 19:44 投稿