对话框
Dialogs
接口用来展示标准对话框窗口。对话框窗口是覆盖于其他界面之上的小窗口,可以展示一些信息或 UI 元素。
其 createMessageDialog()
、createOptionDialog()
和 createInputDialog()
方法是流式 API 的入口点,可以用来创建和显示对话框。
Dialogs
的外观可以使用带 $jmix-window-modal-*
前缀的 SCSS 变量进行自定义。在创建了 自定义主题 之后,可以在可视化编辑器中修改这些变量。
消息对话框
消息对话框的最基本用法是为用户展示一些信息。
下面的例子中,当用户点击按钮时,会显示一个消息对话框:
@Autowired
private Dialogs dialogs;
@Subscribe("msgDialogBtn")
public void onMsgDialogBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("Success")
.withMessage("Your invitation successfully send")
.show();
}
使用 withMessage()
方法传递消息文本。
使用 withContentMode()
方法可以定义消息文本的展示方式。有三种预定义的内容模式:
-
ContentMode.TEXT
- 文本值作为纯文本展示。 -
ContentMode.PREFORMATTED
- 文本值作为预格式化文本展示。该模式下,会保留换行并在界面展示。 -
ContentMode.HTML
- 文本值作为 HTML 进行解析和展示。当使用 HTML 时,别忘了转义内容以防恶意代码注入。
可以在消息中使用 \n
字符来换行。如果要显示 HTML,可以用 withContentMode()
方法带 ContentMode.HTML
参数。
为 withHtmlSanitizer()
方法传参 true
可以启用对话框内容的 HTML 清理功能。此时,必须为 withContentMode()
方法传递 ContentMode.HTML
参数。
protected static final String UNSAFE_HTML = "<i>Jackdaws </i><u>love</u> " +
"<font size=\"javascript:alert(1)\" " +
"color=\"moccasin\">my</font> " +
"<font size=\"7\">big</font> <sup>sphinx</sup> " +
"<font face=\"Verdana\">of</font> <span style=\"background-color: " +
"red;\">quartz</span><svg/onload=alert(\"XSS\")>";
@Autowired
private Dialogs dialogs;
@Subscribe("msgDialogOnBtn")
public void onMsgDialogOnBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("MessageDialog with Sanitizer")
.withMessage(UNSAFE_HTML)
.withContentMode(ContentMode.HTML)
.withHtmlSanitizer(true)
.show();
}
@Subscribe("msgDialogOffBtn")
public void onMsgDialogOffBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("MessageDialog without Sanitizer")
.withMessage(UNSAFE_HTML)
.withContentMode(ContentMode.HTML)
.withHtmlSanitizer(false)
.show();
}
withHtmlSanitizer()
接收的参数会覆盖全局的 jmix.ui.component.html-sanitizer-enabled 配置。
使用下面的方法可以自定义消息对话框的外观和行为:
-
withModal()
- 如果为false
,对话框不以模态窗展示,此时用户可以与应用程序的其他部分交互。对话框默认以模态框展示。
-
withCloseOnClickOutside()
- 如果为true
,并且窗口是模态展示时,用户可以点击对话框之外的地方来关闭对话框。
-
withWindowMode()
- 设置对话框窗口的模式。有两种预定义模式:-
WindowMode.NORMAL
- 窗口大小和位置根据窗口状态确定。 -
WindowMode.MAXIMIZED
- 窗口最大化,左上角对齐后占满整个界面。
-
-
withStyleName()
可以为对话框设置自定义的 CSS 样式名称。参阅 创建新样式 了解详情。
-
withWidth()
、withHeight()
支持指定对话框大小。
示例:
@Autowired
private Dialogs dialogs;
@Subscribe("showDialogBtn")
public void onShowDialogBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("Information")
.withMessage("<i>Message<i/>")
.withContentMode(ContentMode.HTML)
.withCloseOnClickOutside(true)
.withWidth("100px")
.withHeight("300px")
.show();
}
选项对话框
选项对话框展示消息和一组用户交互的按钮。
使用 withActions()
方法可以为对话框提供 操作,每个操作在对话框中以按钮的形式展示。示例:
@Autowired
private Dialogs dialogs;
@Subscribe("optDialogBtn")
public void onOptDialogBtnClick(Button.ClickEvent event) {
dialogs.createOptionDialog()
.withCaption("Please confirm")
.withMessage("Do you really want to add a customer?")
.withActions(
new DialogAction(DialogAction.Type.YES, Action.Status.PRIMARY)
.withHandler(e -> doSomething()),
new DialogAction(DialogAction.Type.NO)
)
.show();
}
当按钮被点击时,对话框会关闭并且调用相应操作的 actionPerform()
方法。
DialogAction
基类可以用来创建带有标准名称和图标的操作。支持五种使用 DialogAction.Type
枚举定义的操作类型:OK
,CANCEL
,YES
,NO
,CLOSE
。对应的按钮名称通过主语言消息包获取。
DialogAction
构造器的第二个参数用来为操作的按钮设置特殊的可视化样式。jmix-primary-action
样式提供的 Status.PRIMARY
会高亮对应的按钮并默认选中。如果对话框中有多个操作使用了 Status.PRIMARY
,只有第一个操作的按钮能使用正确的样式并获得焦点。
输入对话框
输入对话框是一个多功能的工具,可以使用 API 构建输入表单,摆脱为琐碎的数据输入创建界面的麻烦。支持不同类型数据的输入、验证输入数据以及为用户提供不同的操作。
下面我们看几个例子。
标准参数
下面例子中,输入对话框带有标准类型的参数和标准的 OK
/ Cancel
操作:
@Autowired
private Dialogs dialogs;
@Subscribe("inputDialogBtn")
public void onInputDialogBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Get values")
.withParameters(
InputParameter.dateTimeParameter("deliveryTime")
.withCaption("Delivery Time")
.withRequired(true),(1)
InputParameter.doubleParameter("amount")
.withCaption("Amount")
.withDefaultValue(1.0),(2)
InputParameter.entityParameter("customer", Customer.class)
.withCaption("Customer"),(3)
InputParameter.enumParameter("status", Status.class)
.withCaption("Status")(4)
)
.withActions(DialogActions.OK_CANCEL)(5)
.withCloseListener(closeEvent -> {
if (closeEvent.closedWith(DialogOutcome.OK)) {(6)
String name = closeEvent.getValue("name");(7)
Double quantity = closeEvent.getValue("quantity");
Customer customer = closeEvent.getValue("customer");
Status status = closeEvent.getValue("status");
// process entered values...
}
})
.show();
}
1 | 指定一个必填的字符串参数。 |
2 | 指定一个带有默认值的双浮点参数。 |
3 | 指定一个实体参数。 |
4 | 指定一个枚举参数。 |
5 | 指定一组用按钮表示的操作,放置于对话框底部。 |
6 | 在关闭事件监听器中,我们可以检查用户使用了什么操作。 |
7 | 关闭事件包含了输入的值,可以通过参数标识符进行获取。 |
自定义参数
@Autowired
private Dialogs dialogs;
@Autowired
private UiComponents uiComponents;
@Subscribe("inpDlgParamsBtn")
public void onInpDlgParamsBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Enter some values")
.withParameters(
InputParameter.stringParameter("name").withCaption("Name"),
InputParameter.parameter("customer")(1)
.withField(() -> {
EntityComboBox<Customer> field = uiComponents.create(
EntityComboBox.of(Customer.class));
field.setOptionsList(dataManager.load(Customer.class).all().list());
field.setCaption("Customer");(2)
field.setWidthFull();
return field;
})
)
.withActions(DialogActions.OK_CANCEL)
.withCloseListener(closeEvent -> {
if (closeEvent.closedWith(DialogOutcome.OK)) {
String name = closeEvent.getValue("name");
Customer customer = closeEvent.getValue("customer");(3)
// process entered values...
}
})
.show();
}
1 | 指定一个自定义参数 |
2 | 在创建的组件中指定自定义参数的标题。 |
3 | 跟标准的参数一样的方法获取自定义参数的值。 |
自定义操作
@Autowired
private Dialogs dialogs;
@Subscribe("inpDlgActionsBtn")
public void onInpDlgActionsBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Enter some values")
.withParameters(
InputParameter.stringParameter("name").withCaption("Name")
)
.withActions((1)
InputDialogAction.action("confirm")
.withCaption("Confirm")
.withPrimary(true)
.withHandler(actionEvent -> {
InputDialog dialog = actionEvent.getInputDialog();
String name = dialog.getValue("name");(2)
dialog.closeWithDefaultAction();(3)
// process entered values...
}),
InputDialogAction.action("refuse")
.withCaption("Refuse")
.withValidationRequired(false)
.withHandler(actionEvent ->
actionEvent.getInputDialog().closeWithDefaultAction())
)
.show();
}
1 | withActions() 方法能接收一组用户自定义的操作。 |
2 | 在操作处理器中,可以从对话框获取参数值。 |
3 | 自定义操作不会关闭对话框本身,所以需要同时手动关闭。 |
自定义校验
@Autowired
private Dialogs dialogs;
@Subscribe("inpDlgValidBtn")
public void onInpDlgValidBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Enter some values")
.withParameters(
InputParameter.stringParameter("name").withCaption("Name"),
InputParameter.entityParameter("customer", Customer.class).withCaption("Customer")
)
.withValidator(context -> {(1)
String name = context.getValue("name");(2)
Customer customer = context.getValue("customer");
if (Strings.isNullOrEmpty(name) && customer == null) {
return ValidationErrors.of("Enter name or select a customer");
}
return ValidationErrors.none();
})
.withActions(DialogActions.OK_CANCEL)
.withCloseListener(closeEvent -> {
if (closeEvent.closedWith(DialogOutcome.OK)) {
String name = closeEvent.getValue("name");
Customer customer = closeEvent.getValue("customer");
// process entered values...
}
})
.show();
}
1 | 需要自定义 Validator 确保至少输入了一个参数。 |
2 | 在 Validator 中,参数值可以通过上下文对象获取。 |
捕获异常对话框
这是一个特殊的对话框,用于展示后台异常。对话框包含一个可折叠的区域,展示完整的异常堆栈信息。
此对话框用在默认的处理器中,但是也可以用于自己的异常。示例:
@Autowired
private Dialogs dialogs;
@Subscribe("expDlgBtn")
public void onExpDlgBtnClick(Button.ClickEvent event) {
try {
int d = 0;
int a = 42 / d;
}
catch (ArithmeticException e) {
dialogs.createExceptionDialog()
.withCaption("Alert")
.withMessage("Division by zero")
.withThrowable(e.fillInStackTrace())
.show();
}
}