4.5.6.1. Подключение аддона Vaadin

Рассмотрим пример использования компонента Stepper, доступного по адресу http://vaadin.com/addon/stepper. Данный компонент позволяет пошагово изменять значение текстового поля с помощью клавиатуры, колесика мыши и встроенных кнопок вверх/вниз.

Создайте новый проект в CUBA Studio и назовите его addon-demo.

Для подключения аддона Vaadin проект должен иметь модуль web-toolkit. Создайте его, нажав на ссылку Create web toolkit module секции Project properties навигатора.

Далее нажмите на ссылку New UI component. Откроется окно создания визуального компонента UI component generation. В секции Component type выберите значение Vaadin add-on.

studio vaadin addon wizard no gui

Заполните следующие поля:

  • Add-on Maven dependency - в этом поле необходимо указать Maven-координаты аддона Vaadin для подключения его как зависимости к текущему проекту. Указание координат возможно в двух форматах:

    1. XML, скопированный с сайта аддона (http://vaadin.com/addon/stepper):

      <dependency>
         <groupId>org.vaadin.addons</groupId>
         <artifactId>stepper</artifactId>
         <version>2.2.2</version>
      </dependency>
    2. Одной строкой в том виде, как вы добавляете зависимости в build.gradle: org.vaadin.addons:stepper:2.2.2

  • Inherited widgetset - в этом поле необходимо указать имя виджетсета подключаемого аддона:

    org.vaadin.risto.stepper.widgetset.StepperWidgetset
  • Integrate into generic UI - в данном примере флажок должен быть снят, т.к. мы не интегрируем компонент в универсальный интерфейс платформы.

Нажмите кнопку OK.

Если открыть проект в IDE, то можно увидеть, что Студия изменила два файла:

  1. build.gradle. В модуле web появилась новая зависимость от аддона, содержащего компонент:

    configure(webModule) {
        ...
        dependencies {
            ...
            compile("org.vaadin.addons:stepper:2.2.2")
        }
  2. В файл AppWidgetSet.gwt.xml модуля web-toolkit проекта подключен виджетсет аддона после виджетсета платформы:

    <module>
        <inherits name="com.haulmont.cuba.web.toolkit.ui.WidgetSet" />
    
        <inherits name="org.vaadin.risto.stepper.widgetset.StepperWidgetset" />
    
        <set-property name="user.agent" value="safari" />
    Tip

    Для более быстрой сборки виджетов на время разработки вы можете установить свойство user.agent. В данном примере набор виджетов будет собираться только для браузеров, основанных на WebKit: Chrome, Safari, и т.д.

Компонент из аддона Vaadin подключен. Далее мы покажем как использовать его в экранах проекта.

  • Создаем новую сущность Customer с двумя полями:

    • name типа String

    • score типа Integer

  • Сгенерируем для новой сущности стандартные экраны. В диалоге генерации стандартных экранов убедитесь что значение поля In module - Web Module. Экраны, использующие компоненты Vaadin напрямую, должны располагаться в модуле web.

    Tip

    На самом деле экран может располагаться и в модуле gui, но тогда код, работающий с Vaadin компонентом, должен быть вынесен в отдельный компаньон.

  • Далее добавим компонент stepper на экран. Вы можете поместить его как в FieldGroup, так и вне ее. Рассмотрим оба способа.

    1. В XML-дескрипторе экрана редактирования customer-edit.xml для поля score компонента fieldGroup добавим атрибут custom = "true":

      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
              caption="msg://editCaption"
              class="com.company.addondemo.web.customer.CustomerEdit"
              datasource="customerDs"
              focusComponent="fieldGroup"
              messagesPack="com.company.addondemo.web.customer">
          <dsContext>
              <datasource id="customerDs"
                          class="com.company.addondemo.entity.Customer"
                          view="_local"/>
          </dsContext>
          <layout expand="windowActions" spacing="true">
              <fieldGroup id="fieldGroup" datasource="customerDs">
                  <column width="250px">
                      <field property="name"/>
                      <field property="score" custom="true"/>
                  </column>
              </fieldGroup>
              <frame id="windowActions" screen="editWindowActions"/>
          </layout>
      </window>

      В контроллер экрана редактирования CustomerEdit.java добавим следующий код:

      package com.company.addondemo.web.customer;
      
      import com.haulmont.cuba.gui.components.AbstractEditor;
      import com.company.addondemo.entity.Customer;
      import com.haulmont.cuba.gui.components.Component;
      import com.haulmont.cuba.gui.components.FieldGroup;
      import com.haulmont.cuba.gui.components.VBoxLayout;
      import com.haulmont.cuba.gui.data.Datasource;
      import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
      import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
      import com.vaadin.ui.Layout;
      import org.vaadin.risto.stepper.IntStepper;
      
      import javax.inject.Inject;
      import java.util.Map;
      
      public class CustomerEdit extends AbstractEditor<Customer> {
      
          @Inject
          private ComponentsFactory componentsFactory;
      
          @Inject
          private FieldGroup fieldGroup;
      
          @Inject
          private Datasource<Customer> customerDs;
      
          private IntStepper stepper = new IntStepper();
      
          @Override
          public void init(Map<String, Object> params) {
              fieldGroup.createField("score");
              Component box = componentsFactory.createComponent(VBoxLayout.class);
              fieldGroup.getFieldNN("score").setComponent(box);
              Layout layout = (Layout) WebComponentsHelper.unwrap(box);
              layout.addComponent(stepper);
              stepper.setSizeFull();
              stepper.addValueChangeListener(event ->
                      customerDs.getItem().setValue("score", event.getProperty().getValue())
              );
          }
      
          @Override
          protected void initNewItem(Customer item) {
              item.setScore(0);
          }
      
          @Override
          protected void postInit() {
              stepper.setValue(getItem().getScore());
          }
      }

      Здесь в поле stepper создается экземпляр компонента, подключенного из аддона. В методе init() производится инициализация кастомного поля score. Через ComponentsFactory создается экземпляр BoxLayout, затем из него с помощью WebComponentsHelper извлекается ссылка на Vaadin-контейнер, и в этот контейнер добавляется наш новый компонент. BoxLayout возвращается для отображения в кастомном поле.

      Для связи компонента с данными, во-первых, в методе postInit() ему устанавливается текущее значение из редактируемого Customer, а во-вторых, добавляется слушатель на изменение значения, который обновляет соответствующий атрибут сущности при изменении значения пользователем.

    2. Чтобы использовать новый компонент вне FieldGroup в произвольном месте экрана в XML-дескрипторе объявим контейнер scoreBox и удалим поле score из fieldGroup:

      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
              caption="msg://editCaption"
              class="com.company.addondemo.web.customer.CustomerEdit"
              datasource="customerDs"
              focusComponent="fieldGroup"
              messagesPack="com.company.addondemo.web.customer">
          <dsContext>
              <datasource id="customerDs"
                          class="com.company.addondemo.entity.Customer"
                          view="_local"/>
          </dsContext>
          <layout expand="windowActions" spacing="true">
              <fieldGroup id="fieldGroup" datasource="customerDs">
                  <column width="250px">
                      <field property="name"/>
                  </column>
              </fieldGroup>
      
              <hbox id="scoreBox" spacing="true">
                  <label value="Score" align="MIDDLE_LEFT"/>
              </hbox>
      
              <frame id="windowActions" screen="editWindowActions"/>
          </layout>
      </window>

      В контроллере инжектируем контейнер, извлекаем ссылку на Vaadin-контейнер и добавляем в него компонент:

      package com.company.addondemo.web.customer;
      
      import com.haulmont.cuba.gui.components.*;
      import com.company.addondemo.entity.Customer;
      import com.haulmont.cuba.gui.data.Datasource;
      import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
      import com.vaadin.ui.Layout;
      import org.vaadin.risto.stepper.IntStepper;
      
      import javax.inject.Inject;
      import java.util.Map;
      
      public class CustomerEdit extends AbstractEditor<Customer> {
      
          @Inject
          private FieldGroup fieldGroup;
      
          @Inject
          private Datasource<Customer> customerDs;
      
          @Inject
          private BoxLayout scoreBox;
      
          private IntStepper stepper = new IntStepper();
      
          @Override
          public void init(Map<String, Object> params) {
      
              Layout box = (Layout) WebComponentsHelper.unwrap(scoreBox);
              box.addComponent(stepper);
      
              fieldGroup.addField(fieldGroup.createField("score"));
      
              stepper.setSizeFull();
              stepper.addValueChangeListener(event ->
                      customerDs.getItem().setValue("score", event.getProperty().getValue())
              );
          }
      
          @Override
          protected void initNewItem(Customer item) {
              item.setScore(0);
          }
      
          @Override
          protected void postInit() {
              stepper.setValue(getItem().getScore());
          }
      }

      Связь с данными выполняется здесь аналогично примеру с FieldGroup.

  • Для адаптации внешнего вида компонента создадим в проекте расширение темы. Для этого в Studio выполним команду Create theme extension секции Project properties навигатора. В списке тем для расширения выберем halo и нажмем кнопку Create. Затем откроем файл themes/halo/com.company.application/halo-ext.scss модуля web, и добавим в него следующий код:

    /* Define your theme modifications inside next mixin */
    @mixin com_company_application-halo-ext {
        @include halo;
    
        /* Basic styles for stepper inner text box */
        .stepper input[type="text"] {
           @include box-defaults;
           @include valo-textfield-style;
           &:focus {
             @include valo-textfield-focus-style;
           }
        }
    }
  • Запускаем сервер приложения. Экран редактирования должен выглядеть следующим образом:

customer edit result