3.5.17.4.2. 集成 Vaadin 组件到通用 UI 中

前一节中,我们在项目中包含了第三方 Stepper 组件。在本节中,我们将它集成到 CUBA 通用 UI 中。这样就允许开发人员在界面 XML 描述中以声明方式使用组件,并通过数据组件将其绑定到数据模型实体。

为了在 CUBA 通用 UI 中集成 Stepper,需要创建以下文件:

  • Stepper - 在 web 模块 gui 子文件夹的该组件接口。

  • WebStepper - 在 web 模块 gui 子文件夹的该组件实现。

  • StepperLoader - 在 web 模块 gui 子文件夹的组件 XML 加载器。

  • ui-component.xsd - 一个新的组件 XML 结构定义。如果这个文件已经存在,在文件中添加关于此新组件的信息。

  • cuba-ui-component.xml - 在 web 模块中注册新组件加载器的文件。如果该文件已存在,在文件中添加关于此新组件的信息。

在 IDE 中打开项目。

创建相应的文件,并添加必要的更改。

  • web 模块的 gui 子文件夹创建 Stepper 接口。用以下代码替换其内容:

    1. package com.company.demo.web.gui.components;
    2. import com.haulmont.cuba.gui.components.Field;
    3. // note that Stepper should extend Field
    4. public interface Stepper extends Field<Integer> {
    5. String NAME = "stepper";
    6. boolean isManualInputAllowed();
    7. void setManualInputAllowed(boolean value);
    8. boolean isMouseWheelEnabled();
    9. void setMouseWheelEnabled(boolean value);
    10. int getStepAmount();
    11. void setStepAmount(int amount);
    12. int getMaxValue();
    13. void setMaxValue(int maxValue);
    14. int getMinValue();
    15. void setMinValue(int minValue);
    16. }

    组件的基础接口是 Field,用于显示和编辑实体属性。

  • 创建 WebStepper 类 - web 模块的 gui 子文件夹中的组件实现。用以下代码替换其内容:

    1. package com.company.demo.web.gui.components;
    2. import com.haulmont.cuba.web.gui.components.WebV8AbstractField;
    3. import org.vaadin.risto.stepper.IntStepper;
    4. // note that WebStepper should extend WebV8AbstractField
    5. public class WebStepper extends WebV8AbstractField<IntStepper, Integer, Integer> implements Stepper {
    6. public WebStepper() {
    7. this.component = createComponent();
    8. attachValueChangeListener(component);
    9. }
    10. private IntStepper createComponent() {
    11. return new IntStepper();
    12. }
    13. @Override
    14. public boolean isManualInputAllowed() {
    15. return component.isManualInputAllowed();
    16. }
    17. @Override
    18. public void setManualInputAllowed(boolean value) {
    19. component.setManualInputAllowed(value);
    20. }
    21. @Override
    22. public boolean isMouseWheelEnabled() {
    23. return component.isMouseWheelEnabled();
    24. }
    25. @Override
    26. public void setMouseWheelEnabled(boolean value) {
    27. component.setMouseWheelEnabled(value);
    28. }
    29. @Override
    30. public int getStepAmount() {
    31. return component.getStepAmount();
    32. }
    33. @Override
    34. public void setStepAmount(int amount) {
    35. component.setStepAmount(amount);
    36. }
    37. @Override
    38. public int getMaxValue() {
    39. return component.getMaxValue();
    40. }
    41. @Override
    42. public void setMaxValue(int maxValue) {
    43. component.setMaxValue(maxValue);
    44. }
    45. @Override
    46. public int getMinValue() {
    47. return component.getMinValue();
    48. }
    49. @Override
    50. public void setMinValue(int minValue) {
    51. component.setMinValue(minValue);
    52. }
    53. }

    所选择的基类是 WebV8AbstractField,其实现了 Field 接口的方法。

  • web 模块的 gui 子文件夹中的 StepperLoader 类从 XML 描述中加载组件。

    1. package com.company.demo.web.gui.xml.layout.loaders;
    2. import com.company.demo.web.gui.components.Stepper;
    3. import com.haulmont.cuba.gui.xml.layout.loaders.AbstractFieldLoader;
    4. public class StepperLoader extends AbstractFieldLoader<Stepper> {
    5. @Override
    6. public void createComponent() {
    7. resultComponent = factory.create(Stepper.class);
    8. loadId(resultComponent, element);
    9. }
    10. @Override
    11. public void loadComponent() {
    12. super.loadComponent();
    13. String manualInput = element.attributeValue("manualInput");
    14. if (manualInput != null) {
    15. resultComponent.setManualInputAllowed(Boolean.parseBoolean(manualInput));
    16. }
    17. String mouseWheel = element.attributeValue("mouseWheel");
    18. if (mouseWheel != null) {
    19. resultComponent.setMouseWheelEnabled(Boolean.parseBoolean(mouseWheel));
    20. }
    21. String stepAmount = element.attributeValue("stepAmount");
    22. if (stepAmount != null) {
    23. resultComponent.setStepAmount(Integer.parseInt(stepAmount));
    24. }
    25. String maxValue = element.attributeValue("maxValue");
    26. if (maxValue != null) {
    27. resultComponent.setMaxValue(Integer.parseInt(maxValue));
    28. }
    29. String minValue = element.attributeValue("minValue");
    30. if (minValue != null) {
    31. resultComponent.setMinValue(Integer.parseInt(minValue));
    32. }
    33. }
    34. }

    AbstractFieldLoader 类包含用于加载 Field 组件的基本属性的代码。所以 StepperLoader 只加载特定于 Stepper 组件的属性。

  • web 模块中的 cuba-ui-component.xml 文件注册新组件及其加载器。用以下代码替换其内容:

    1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    2. <components xmlns="http://schemas.haulmont.com/cuba/components.xsd">
    3. <component>
    4. <name>stepper</name>
    5. <componentLoader>com.company.demo.web.gui.xml.layout.loaders.StepperLoader</componentLoader>
    6. <class>com.company.demo.web.gui.components.WebStepper</class>
    7. </component>
    8. </components>
  • web 模块中的 ui-component.xsd 文件包含自定义可视化组件的 XSD。添加 stepper 元素及其属性定义。

    1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    2. <xs:schema xmlns="http://schemas.company.com/agd/0.1/ui-component.xsd"
    3. elementFormDefault="qualified"
    4. targetNamespace="http://schemas.company.com/agd/0.1/ui-component.xsd"
    5. xmlns:xs="http://www.w3.org/2001/XMLSchema">
    6. <xs:element name="stepper">
    7. <xs:complexType>
    8. <xs:attribute name="id" type="xs:string"/>
    9. <xs:attribute name="caption" type="xs:string"/>
    10. <xs:attribute name="height" type="xs:string"/>
    11. <xs:attribute name="width" type="xs:string"/>
    12. <xs:attribute name="dataContainer" type="xs:string"/>
    13. <xs:attribute name="property" type="xs:string"/>
    14. <xs:attribute name="manualInput" type="xs:boolean"/>
    15. <xs:attribute name="mouseWheel" type="xs:boolean"/>
    16. <xs:attribute name="stepAmount" type="xs:int"/>
    17. <xs:attribute name="maxValue" type="xs:int"/>
    18. <xs:attribute name="minValue" type="xs:int"/>
    19. </xs:complexType>
    20. </xs:element>
    21. </xs:schema>

我们来看一下如何将新组件添加到界面。

  • 可以删除前一章节的改动或者为实体生成编辑界面。

  • stepper 组件添加到编辑界面。可以使用声明式的方式或者编程的方式进行添加。我们分别看看这两种方法。

    1. 在 XML 描述中声明式的使用该组件。

      • 打开 customer-edit.xml 文件。

      • 定义新的命名空间 xmlns:app="http://schemas.company.com/agd/0.1/ui-component.xsd"

      • form 中删除 score 字段。

      • stepper 组件添加到界面上。

  1. 这时,界面 XML 描述应如下所示:
  2. ```
  3. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  4. <window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
  5. xmlns:app="http://schemas.company.com/agd/0.1/ui-component.xsd"
  6. caption="msg://editorCaption"
  7. focusComponent="form"
  8. messagesPack="com.company.demo.web.customer">
  9. <data>
  10. <instance id="customerDc"
  11. class="com.company.demo.entity.Customer"
  12. view="_local">
  13. <loader/>
  14. </instance>
  15. </data>
  16. <dialogMode height="600"
  17. width="800"/>
  18. <layout expand="editActions" spacing="true">
  19. <form id="form" dataContainer="customerDc">
  20. <column width="250px">
  21. <textField id="nameField" property="name"/>
  22. <app:stepper id="stepper"
  23. dataContainer="customerDc" property="score"
  24. minValue="0" maxValue="20"/>
  25. </column>
  26. </form>
  27. <hbox id="editActions" spacing="true">
  28. <button action="windowCommitAndClose"/>
  29. <button action="windowClose"/>
  30. </hbox>
  31. </layout>
  32. </window>
  33. ```
  34. 在上面的例子中,`stepper` 组件与 `Customer` 实体的 `score` 属性相关联。该实体的实例由 `customerDc` 实例容器管理。
  35. 2. Java 控制器中以编程的方式创建组件。
  36. ```
  37. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  38. <window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
  39. caption="msg://editorCaption"
  40. focusComponent="form"
  41. messagesPack="com.company.demo.web.customer">
  42. <data>
  43. <instance id="customerDc"
  44. class="com.company.demo.entity.Customer"
  45. view="_local">
  46. <loader/>
  47. </instance>
  48. </data>
  49. <dialogMode height="600"
  50. width="800"/>
  51. <layout expand="editActions" spacing="true">
  52. <form id="form" dataContainer="customerDc">
  53. <column width="250px">
  54. <textField id="nameField" property="name"/>
  55. </column>
  56. </form>
  57. <hbox id="editActions" spacing="true">
  58. <button action="windowCommitAndClose"/>
  59. <button action="windowClose"/>
  60. </hbox>
  61. </layout>
  62. </window>
  63. ```
  64. ```
  65. package com.company.demo.web.customer;
  66. import com.company.demo.entity.Customer;
  67. import com.company.demo.web.gui.components.Stepper;
  68. import com.haulmont.cuba.gui.UiComponents;
  69. import com.haulmont.cuba.gui.components.Form;
  70. import com.haulmont.cuba.gui.components.data.value.ContainerValueSource;
  71. import com.haulmont.cuba.gui.model.InstanceContainer;
  72. import com.haulmont.cuba.gui.screen.*;
  73. import javax.inject.Inject;
  74. @UiController("demo_Customer.edit")
  75. @UiDescriptor("customer-edit.xml")
  76. @EditedEntityContainer("customerDc")
  77. @LoadDataBeforeShow
  78. public class CustomerEdit extends StandardEditor<Customer> {
  79. @Inject
  80. private Form form;
  81. @Inject
  82. private InstanceContainer<Customer> customerDc;
  83. @Inject
  84. private UiComponents uiComponents;
  85. @Subscribe
  86. protected void onInit(InitEvent event) {
  87. Stepper stepper = uiComponents.create(Stepper.NAME);
  88. stepper.setValueSource(new ContainerValueSource<>(customerDc, "score"));
  89. stepper.setCaption("Score");
  90. stepper.setWidthFull();
  91. stepper.setMinValue(0);
  92. stepper.setMaxValue(20);
  93. form.add(stepper);
  94. }
  95. @Subscribe
  96. protected void onInitEntity(InitEntityEvent<Customer> event) {
  97. event.getEntity().setScore(0);
  98. }
  99. }
  100. ```
  • 启动应用程序服务。将生成如下所示的编辑界面:

customer edit result