3.5.1.1.3. 界面事件

本节介绍可以在控制器中处理的界面生命周期事件。

参考 使用应用程序事件解耦业务逻辑 指南,了解如何在 UI 层使用事件。



InitEvent

InitEvent 在界面控制器及其所有以声明方式定义的组件创建后并完成依赖注入时发送的事件。此时,嵌套的界面 fragment 尚未初始化,某些可视化组件未完全初始化,例如按钮还未与操作关联起来。

@Subscribe
protected void onInit(InitEvent event) {
    Label<String> label = uiComponents.create(Label.TYPE_STRING);
    label.setValue("Hello World");
    getWindow().add(label);
}
AfterInitEvent

AfterInitEvent 在界面控制器及其所有以声明方式定义的组件被创建并完成依赖注入,并且所有组件都已完成其内部初始化过程时发送此事件。此时,嵌套的界面 fragment(如果有的话)已经发送了 InitEventAfterInitEvent 事件。在此事件监听器中,可以创建可视化组件或数据组件并且进行一些依赖于嵌套 fragment 的额外初始化过程。

InitEntityEvent

InitEntityEvent 继承自 StandardEditorMasterDetailScreen 的界面中,在新实体实例设置给被编辑实体的容器之前发送的事件。使用此事件监听器初始化新实体实例中的默认值,例如:

也可参考 初始化实体值 指南,了解如何使用 InitEntityEvent 监听器。

用该监听器可以为新实体实例设置初始化值,示例:

@Subscribe
protected void onInitEntity(InitEntityEvent<Foo> event) {
    event.getEntity().setStatus(Status.ACTIVE);
}
BeforeShowEvent

BeforeShowEvent 在界面将要展示之前发送的事件,此时,界面尚未被添加到应用程序 UI 中、UI 组件已经应用安全限制、保存的组件设置尚未应用到 UI 组件。对于使用 @LoadDataBeforeShow 注解的界面,尚未加载数据。在此事件监听器中,可以加载数据、检查权限和修改 UI 组件。例如:

@Subscribe
protected void onBeforeShow(BeforeShowEvent event) {
    customersDl.load();
}
AfterShowEvent

AfterShowEvent 在显示界面之后立即发送此事件,此时,界面已经被添加到应用程序 UI 中。保存的组件设置已应用到 UI 组件。在此事件监听器中,可以显示通知、对话框或其它界面。例如:

+

@Subscribe
protected void onAfterShow(AfterShowEvent event) {
    notifications.create().withCaption("Just opened").show();
}
BeforeCommitChangesEvent

BeforeCommitChangesEvent 在继承自 StandardEditorMasterDetailScreen 的界面中发送,在通过 commitChanges() 方法保存数据改动之前发送。在此事件监听器中,可以做一些检查、与用户交互然后通过事件对象的 preventCommit()resume() 方法退出操作或者继续操作。

我们看几个用例:

  1. 退出保存操作并弹出通知消息:

    @Subscribe
    public void onBeforeCommitChanges(BeforeCommitChangesEvent event) {
        if (getEditedEntity().getStatus() == null) {
            notifications.create().withCaption("Enter status!").show();
            event.preventCommit();
        }
    }
  2. 退出保存,显示一个对话框,如果用户选择继续,则继续保存操作:

    @Subscribe
    public void onBeforeCommitChanges(BeforeCommitChangesEvent event) {
        if (getEditedEntity().getStatus() == null) {
            dialogs.createOptionDialog()
                    .withCaption("Confirmation")
                    .withMessage("Status is empty. Do you really want to commit?")
                    .withActions(
                            new DialogAction(DialogAction.Type.OK).withHandler(e -> {
                                // resume with default behavior
                                event.resume();
                            }),
                            new DialogAction(DialogAction.Type.CANCEL)
                    )
                    .show();
            // abort
            event.preventCommit();
        }
    }
  3. 退出保存,显示对话框,用户确认之后重试 commitChanges()

    @Subscribe
    public void onBeforeCommitChanges(BeforeCommitChangesEvent event) {
        if (getEditedEntity().getStatus() == null) {
            dialogs.createOptionDialog()
                    .withCaption("Confirmation")
                    .withMessage("Status is empty. Do you want to use default?")
                    .withActions(
                            new DialogAction(DialogAction.Type.OK).withHandler(e -> {
                                getEditedEntity().setStatus(getDefaultStatus());
                                // retry commit and resume action
                                event.resume(commitChanges());
                            }),
                            new DialogAction(DialogAction.Type.CANCEL)
                    )
                    .show();
            // abort
            event.preventCommit();
        }
    }
AfterCommitChangesEvent

AfterCommitChangesEvent 在继承自 StandardEditorMasterDetailScreen 的界面中发送,在通过 commitChanges() 方法保存数据改动之后发送。示例:

@Subscribe
public void onAfterCommitChanges(AfterCommitChangesEvent event) {
    notifications.create()
            .withCaption("Saved!")
            .show();
}
BeforeCloseEvent

BeforeCloseEvent 在界面通过其 close(CloseAction) 方法关闭之前发送的事件。此刻界面仍然正常显示并且功能完整。组件设置尚未保存。在此事件监听器中,可以做任何条件检查并使用事件的 preventWindowClose() 方法阻止界面关闭,例如:

@Subscribe
protected void onBeforeClose(BeforeCloseEvent event) {
    if (Strings.isNullOrEmpty(textField.getValue())) {
        notifications.create().withCaption("Input required").show();
        event.preventWindowClose();
    }
}

还有一个同名的事件,它定义在 Window 接口内。此事件会在界面被外部(界面控制器之外)操作关闭之前发送,比如点击窗口标签页的关闭按钮或者按下 Esc 键。可以使用 getCloseOrigin() 方法获取窗口关闭的类型,此方法返回一个实现了 CloseOrigin 接口的对象。CloseOrigin 接口的默认实现是 CloseOriginType,有三个值:

  • BREADCRUMBS - 界面通过点击面包屑链接关闭。

  • CLOSE_BUTTON - 界面通过窗口顶部的关闭按钮关闭,或者通过窗口标签页的关闭按钮或右键菜单的操作:关闭、关闭全部、关闭其它。

  • SHORTCUT - 界面通过 cuba.gui.closeShortcut 应用程序属性定义的快捷键关闭。

可以通过在 @Subscribe 注解中指定 Target.FRAME 的方法来订阅 Window.BeforeCloseEvent

@Subscribe(target = Target.FRAME)
protected void onBeforeClose(Window.BeforeCloseEvent event) {
    if (event.getCloseOrigin() == CloseOriginType.BREADCRUMBS) {
        event.preventWindowClose();
    }
}
AfterCloseEvent

AfterCloseEvent 在界面通过 close(CloseAction) 方法关闭并且在 Screen.AfterDetachEvent 之后发送的事件。组件设置已保存。在此事件监听器中,可以在关闭界面后显示通知或对话框,例如:

@Subscribe
protected void onAfterClose(AfterCloseEvent event) {
    notifications.create().withCaption("Just closed").show();
}
AfterDetachEvent

AfterDetachEvent 在用户关闭界面或用户注销时从应用程序 UI 中移除界面后发送的事件。此事件监听器可用于释放界面持有的资源。请注意,在 HTTP 会话过期时不会发送此事件。

UrlParamsChangedEvent
  • UrlParamsChangedEvent 打开的界面对应的浏览器 URL 参数更改时发送的事件。事件在显示界面之前触发,以便能够进行一些准备工作。在此事件监听器中,可以根据新的参数加载一些数据或更改界面控件的状态:

@Subscribe
protected void onUrlParamsChanged(UrlParamsChangedEvent event) {
    Map<String, String> params = event.getParams();
    // handle new params
}