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()メソッドも併せてオーバーライドすることを推奨します。