JavaFX FXML 对话框 - 无法使用 X 按钮关闭它

mar*_*trz 2 java javafx fxml

我预计将完成一个 JavaFX 对话框。我将控制器类添加到准备好的 FXML 中

<?xml version="1.0" encoding="UTF-8"?>

<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.image.Image?>


<Dialog fx:id="dialog"
    fx:controller="myapp.AddDialogController"
    xmlns:fx="http://javafx.com/fxml">
    <dialogPane>
        <DialogPane prefWidth="400.0" prefHeight="300.0">
            <stylesheets>
                <URL value="@/css/styles.css" />
            </stylesheets>
            <content>
                <VBox>
                    <Label text="Add some content here..."></Label>
                </VBox>
            </content>
        </DialogPane>
    </dialogPane>
</Dialog>
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试使用桌面环境提供的 X 按钮关闭对话框时,没有任何反应。我究竟做错了什么?

jew*_*sea 5

解决方案 - 将按钮添加到对话框中

请参阅以下问题的答案:

我还建议在 JavaFX 警报中至少设置一个 CANCEL_CLOSE 按钮或 OK_DONE 按钮,否则用户可能很难真正关闭警报,因为对话框可能不会像用户期望的那样响应按键。

尝试使用窗口框架中操作系统的 X 按钮来关闭舞台可能也是如此。

背景信息

要进一步了解该行为,请阅读对话框 javadoc中的对话框关闭规则:

了解关闭对话框时会发生什么以及如何关闭对话框非常重要,特别是在异常关闭情况下(例如,单击对话框标题栏中的“X”按钮时,或者当操作系统特定键盘时)输入快捷方式(例如 Windows 上的 alt-F4)。幸运的是,这些情况下的结果是明确定义的,并且可以最好地总结为以下要点:

  • JavaFX 对话框只能在两种情况下“异常”关闭(如上所述):
    1. 当对话框只有一个按钮时,或者
    2. 当对话框有多个按钮时,只要其中之一满足以下要求之一:
      1. 该按钮有一个ButtonTypewhoButtonBar.ButtonData的类型ButtonBar.ButtonData.CANCEL_CLOSE
      2. 该按钮有一个在被调用时返回 true 的ButtonType函数。ButtonBar.ButtonDataButtonBar.ButtonData.isCancelButton()
  • 在所有其他情况下,对话框将拒绝响应所有关闭请求,并保持打开状态,直到用户单击对话框的 DialogPane 区域中的可用按钮之一。
  • 如果对话框异常关闭,并且该对话框包含满足上述两个条件之一的按钮,则该对话框将尝试将结果属性设置为使用第一个匹配的 ButtonType 调用结果转换器所返回的任何值。
  • 如果由于任何原因结果转换器返回 null,或者如果对话框在仅存在一个非取消按钮时关闭,则 result 属性将为 null,并且该showAndWait()方法将返回 Optional.empty()。后面这一点意味着,如果您使用选项 2 或选项 3(如本类文档前面所述),则Optional.ifPresent(java.util.function.Consumer) lambda 将永远不会被调用,并且代码将继续执行,就好像对话框根本没有返回任何值一样。

所以,如果对话框中没有按钮,它就无法关闭......

回答后续问题

我可以从 FXML 设置按钮类型吗?

也许吧,我不知道,我从来没有尝试过。无论如何我不会建议它,相反我建议只从代码中设置按钮类型。老实说,我可能只会在 FXML 中定义对话框的内容窗格(例如,仅 FXML 的 VBox 部分及其子元素),而将其余的封闭对话框定义保留在 Java 代码中。我很惊讶在 FXML 中定义对话框甚至可以工作,但它确实有效:-) 但是,您无法使用对话框作为 SceneBuilder 中的根 XML 元素打开 FXML(并且使用 SceneBuilder 定义 UI 的能力是 IMO 之一)首先是使用 FXML 的最佳理由)。

示例解决方案

以下是对话框的对话框定义示例,可以通过对话框中的按钮或组合键或单击操作系统提供的对话框框架中的关闭图标来关闭该对话框:

添加对话框控制器.java

package myapp.ui;

public class AddDialogController {}
Run Code Online (Sandbox Code Playgroud)

DialogDisplayApp.java

package myapp.ui;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;

public class DialogDisplayApp extends Application {

    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader loader = new FXMLLoader(
                getClass().getResource(
                        "add-dialog.fxml"
                )
        );

        stage.setScene(new Scene(new VBox(new Label("Main Window")), 600, 400));
        stage.show();

        Dialog dialog = loader.load();
        dialog.getDialogPane().getButtonTypes().addAll(
                ButtonType.CLOSE
        );

        dialog.initOwner(stage);
        dialog.showAndWait();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Run Code Online (Sandbox Code Playgroud)

myapp/ui/add-dialog.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Dialog?>
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<Dialog fx:id="dialog"
        fx:controller="myapp.ui.AddDialogController"
        xmlns:fx="http://javafx.com/fxml">
  <dialogPane>
    <DialogPane prefWidth="400.0" prefHeight="300.0">
      <content>
        <VBox>
          <Label text="Add some content here..."></Label>
        </VBox>
      </content>
    </DialogPane>
  </dialogPane>
</Dialog>
Run Code Online (Sandbox Code Playgroud)