3.5.2.1.45. Table

В этом разделе:

Компонент Table позволяет выводить информацию в табличном виде, сортировать данные, управлять колонками и заголовками таблицы, вызывать действия для выбранных строк.

gui table

XML-имя компонента: table

Пример описания таблицы в XML-дескрипторе экрана:

<data readOnly="true">
    <collection id="ordersDc" class="com.company.sales.entity.Order" view="order-with-customer">
        <loader id="ordersDl">
            <query>
                <![CDATA[select e from sales_Order e]]>
            </query>
        </loader>
    </collection>
</data>
<layout>
<table id="ordersTable" dataContainer="ordersDc" width="100%">
    <columns>
        <column id="date"/>
        <column id="amount"/>
        <column id="customer"/>
    </columns>
    <rowsCount/>
</table>
</layout>

Здесь в элементе data определен контейнер данных, который выбирает сущности Order с помощью JPQL запроса select o from sales_Order o order by o.date. Для компонента table указывается используемый контейнер данных, а в элементе columns - какие атрибуты сущности, содержащейся в контейнере, использовать в качестве колонок.

Если вы хотите указать источник данных для таблицы программно в контроллере экрана, используйте атрибут metaClass вместо декларативного указания значения dataContainer в XML.

Элементы table

  • rows - обязательный элемент в случае, если для привязывания таблицы к данным используется атрибут datasource.

    Для строк можно настроить отображение заголовков - задать каждой строке свой значок в дополнительной колонке слева. Для этого в контроллере экрана необходимо реализовать интерфейс ListComponent.IconProvider и установить его таблице:

    @Inject
    private Table<Customer> table;
    
    @Subscribe
    protected void onInit(InitEvent event) {
        table.setIconProvider(new ListComponent.IconProvider<Customer>() {
            @Nullable
            @Override
            public String getItemIcon(Customer entity) {
                CustomerGrade grade = entity.getGrade();
                switch (grade) {
                    case PREMIUM: return "icons/premium_grade.png";
                    case HIGH: return "icons/high_grade.png";
                    case MEDIUM: return "icons/medium_grade.png";
                    default: return null;
                }
            }
        });
    }
  • columns - элемент, определяющий набор колонок таблицы. Если не задан, то столбцы таблицы будут автоматически определены из атрибутов представления, используемого при загрузке данных из контейнера данных. Элемент columns имеет следующие атрибуты:

    • includeAll – загружает все атрибуты представления, используемого при загрузке данных из контейнера данных.

      В приведенном ниже примере мы покажем все атрибуты из представления, используемого в customersDc. Если представление содержит системные свойства, они также будут показаны.

      <table id="table"
             width="100%"
             height="100%"
             dataContainer="customersDc">
          <columns includeAll="true"/>
      </table>

      Если представление сущности содержит ссылочный атрибут, этот атрибут выводится в соответствии с его шаблоном @NamePattern. Если вы хотите показать какой-то конкретный атрибут, он должен быть определен в представлении, а также в элементе column:

      <columns includeAll="true">
          <column id="address.street"/>
      </columns>

      Если представление не указано, атрибут includeAll загрузит все атрибуты из данной сущности и ее предков.

    • exclude – разделенный запятыми список атрибутов, которые не должны быть загружены в таблицу.

      В приведенном ниже примере мы покажем все атрибуты, за исключением атрибутов name и order:

      <table id="table"
             width="100%"
             height="100%"
             dataContainer="customersDc">
          <columns includeAll="true"
                   exclude="name, order"/>
      </table>

    Каждая колонка описывается во вложенном элементе column со следующими атрибутами:

    • id − обязательный атрибут, содержит название атрибута сущности, выводимого в колонке. Может быть как непосредственным атрибутом сущности, находящейся в контейнере, так и атрибутом связанной сущности - переход по графу объектов обозначается точкой. Например:

      <columns>
          <column id="date"/>
          <column id="customer"/>
          <column id="customer.name"/>
          <column id="customer.address.country"/>
      </columns>
    • captionAsHtml − необязательный атрибут, определяющий возможность использовать HTML-теги в заголовке колонки. По умолчанию false.

      <column id="name"
              caption="msg://role.name"
              captionAsHtml="true"/>
      role.name=<em>Name</em>
    • collapsed − необязательный атрибут, при указании true колонка будет изначально скрыта. Пользователь может управлять отображением колонок с помощью меню, доступного по кнопке gui_table_columnControl в правой верхней части таблицы, если атрибут columnControlVisible таблицы не false. По умолчанию collapsed имеет значение false.

    • expandRatio − необязательный атрибут, определяющий относительную длину для каждой колонки. Принимает значение большее или равное 0. Если хотя бы одной колонке установлено значение атрибута expandRatio, все неявные значения игнорируются и учитываются только явно присвоенные значения. Если вы одновременно установите атрибуты width и expandRatio, это вызовет ошибку в приложении.

    • width − необязательный атрибут, отвечает за изначальную ширину колонки. Может принимать только числовые значения в пикселах.

    • align - необязательный атрибут, устанавливает выравнивание текста в ячейках данной колонки. Возможные значения: LEFT, RIGHT, CENTER. По умолчанию LEFT.

    • editable − необязательный атрибут, разрешает/запрещает редактирование данной колонки в редактируемой таблице. Чтобы колонка была редактируемой, атрибут editable всей таблицы также должен быть установлен в true. Динамическое изменение значения этого атрибута не поддерживается.

    • sortable − необязательный атрибут, позволяющий запретить сортировку колонки. Вступает в действие, если атрибут sortable всей таблицы установлен в true (что имеет место по умолчанию).

    • sort − необязательный атрибут, позволяющий задать начальную сортировку таблицы по указанной колонке в соответствии с направлением сортировки. Возможные значения:

      • ASCENDING – сортировка по возрастанию (например, A-Z, 1..9).

      • DESCENDING – сортировка по убыванию (например, Z-A, 9..1).

      <columns>
          <column property="name" sort="DESCENDING"/>
      </columns>

    Обратите внимание: если значение атрибута settingsEnabled установлено в true, таблица сортируется в соответствии с настройками пользователя.

    В одно и то же время таблица может быть сортирована только по одной колонке. Таким образом, приведенный ниже пример:

    <columns>
        <column property="name" sort="DESCENDING"/>
        <column property="parent" sort="ASCENDING"/>
    </columns>

    вызовет исключение.

    Если одновременно для колонки установить атрибуты sort и sortable="false", это также вызовет исключение.

    • maxTextLength - необязательный атрибут, позволяет ограничивать количество символов в ячейке. При этом если разница между фактическим и допустимым количеством символов не превышает порог в 10 символов, "лишние" символы не скрываются. Для просмотра полной записи надо кликнуть на ее видимую часть. Пример колонки с ограничением в 10 символов:

      gui table column maxTextLength
    • linkScreen - позволяет указать идентификатор экрана, который будет открыт по нажатию на ссылку, включенную свойством link.

    • linkScreenOpenType - задает режим открытия экрана (THIS_TAB, NEW_TAB или DIALOG).

    • linkInvoke - позволяет заменить открытие окна на вызов метода контроллера.

      @Inject
      private Notifications notifications;
      
      public void linkedMethod(Entity item, String columnId) {
          Customer customer = (Customer) item;
          notifications.create()
                  .withCaption(customer.getName())
                  .show();
      }
    • captionProperty - имя атрибута сущности, который должен быть отображен в колонке вместо указанного в id. Например, если имеется связанная сущность Priority с атрибутами name и orderNo, можно определить следующую колонку:

      <column id="priority.orderNo" captionProperty="priority.name" caption="msg://priority" />

      В этом случае в колонке будет отображаться название приоритета, а сортировка колонки будет осуществляться по атрибуту orderNo.

    • необязательный атрибут generator содержит ссылку на метод в контроллере экрана, который создает визуальный компонент для отображения содержимого ячейки:

      <columns>
          <column id="name"/>
          <column id="imageFile"
                  generator="generateImageFileCell"/>
      </columns>
      public Component generateImageFileCell(Employee entity){
          Image image = uiComponents.create(Image.NAME);
          image.setSource(FileDescriptorResource.class).setFileDescriptor(entity.getImageFile());
          return image;
      }

      Он может быть использован вместо передачи реализации Table.ColumnGenerator в метод addGeneratedColumn().

    • Элемент column может содержать вложенный элемент formatter для представления значения атрибута в виде, отличном от стандартного для данного Datatype:

      <column id="date">
          <formatter class="com.haulmont.cuba.gui.components.formatters.DateFormatter"
                     format="yyyy-MM-dd HH:mm:ss"
                     useUserTimezone="true"/>
      </column>
  • rowsCount − необязательный элемент, создающий для таблицы компонент RowsCount, который позволяет загружать в таблицу данные постранично. Размер страницы задается путем ограничения количества записей в контейнере методом setMaxResults() loader'а. Как правило, это делает связанный с загрузчиком данных таблицы компонент Filter, однако при отсутствии универсального фильтра можно вызвать этот метод и напрямую из контроллера экрана.

    Компонент RowsCount может также отобразить общее число записей, возвращаемых текущим запросом в контейнере данных, без извлечения этих записей. По клику пользователя на знак "?" вызывается com.haulmont.cuba.core.global.DataManager#getCount, что приводит к выполнению в БД запроса с такими же, как у текущего запроса условиями, но с агрегатной функцией COUNT(*) вместо результатов. Полученное число отображается вместо знака "?".

    Атрибут autoLoad компонента RowsCount, установленный в значение true, позволяет автоматически загружать общее число записей. Его можно установить в XML-дескрипторе:

    <rowsCount autoLoad="true"/>

    Также включить или отключить автоматическую загрузку количества записей можно с помощью API в контроллере экрана:

    boolean autoLoadEnabled = rowsCount.getAutoLoad();
    rowsCount.setAutoLoad(false);
  • actions − необязательный элемент для описания действий, связанных с таблицей. Кроме описания произвольных действий, поддерживаются следующие стандартные действия, определенные в пакете com.haulmont.cuba.gui.actions.list: create, edit, remove, refresh, add, exclude, excel.

  • buttonsPanel - необязательный элемент, создающий над таблицей контейнер ButtonsPanel для отображения кнопок действий.

Атрибуты table

  • Атрибут emptyStateMessage позволяет задать сообщение в тех случаях, когда нет загруженных данных, установлены нулевые значения или контейнер данных пуст. Данный атрибут часто используется совместно с атрибутом emptyStateLinkMessage. Сообщение может содержать информацию о том, какие данные должна содержать таблица. Например:

    <table id="table"
           emptyStateMessage="No data added to the table"
           ...
           width="100%">

    Атрибут emptyStateMessage поддерживает загрузку сообщений из пакета сообщений. Если вы не хотите отображать сообщение, просто не указывайте этот атрибут.

  • Атрибут emptyStateLinkMessage позволяет задать сообщение в виде гиперссылки в тех случаях, когда нет загруженных данных, установлены нулевые значения или контейнер данных пуст. Данный атрибут часто используется совместно с атрибутом emptyStateMessage. Сообщение должно описывать действие, которое необходимо выполнить для заполнения таблицы. Например:

    <table id="table"
           emptyStateMessage="No data added to the table"
           emptyStateLinkMessage="Add data (Ctrl+\)"
           ...
           width="100%">
    gui table emptyState

    Атрибут emptyStateLinkMessage поддерживает загрузку сообщений из пакета сообщений. Если вы не хотите отображать сообщение, просто не указывайте этот атрибут.

    Чтобы обработать событие перехода по ссылке, используйте метод setEmptyStateLinkClickHandler или подпишитесь на соответствующее событие в контроллере экрана:

    @Install(to = "customersTable", subject = "emptyStateLinkClickHandler")
    private void customersTableEmptyStateLinkClickHandler(Table.EmptyStateClickEvent<Customer> emptyStateClickEvent) {
        screenBuilders.editor(emptyStateClickEvent.getSource())
                .newEntity()
                .show();
    }
  • Атрибут multiselect позволяет задать режим множественного выделения строк в таблице. Если multiselect равен true, то пользователь может выделить несколько строк с помощью клавиатуры или мыши, удерживая клавиши Ctrl или Shift. По умолчанию режим множественного выделения отключен.

  • Атрибут sortable разрешает или запрещает сортировку в таблице. По умолчанию имеет значение true. Если сортировка разрешена, то при нажатии на название колонки справа от названия появляется значок gui_sortable_down/gui_sortable_up. Сортировку некоторой отдельной колонки можно запретить с помощью атрибута sortable этой колонки.

    При включенной с помощью элемента rowsCount (см. выше) страничной загрузке таблицы сортировка производится разными способами в зависимости от того, умещаются ли все записи на одной странице. Если умещаются, то сортировка производится в памяти, без обращений к БД. Если же страниц больше одной, то сортировка производится на базе данных путем отправки нового запроса с соответствующим ORDER BY.

    Колонка таблицы может ссылаться на локальный атрибут или на связанную сущность. Например:

    <table id="ordersTable"
           dataContainer="ordersDc">
        <columns>
            <column id="customer.name"/> <!-- the 'name' attribute of the 'Customer' entity -->
            <column id="contract"/>      <!-- the 'Contract' entity -->
        </columns>
    </table>

    В последнем случае, сортировка на базе данных производится по атрибутам, указанным в аннотации @NamePattern связанной сущности. Если у связанной сущности нет такой аннотации, то сортировка производится в памяти только в пределах текущей страницы.

    Если колонка таблицы ссылается на неперсистентный атрибут, то сортировка на базе данных производится по атрибутам, указанным в параметре related() аннотации @MetaProperty. Если такой параметр не указан, то сортировка производится в памяти только в пределах текущей страницы.

    Если таблица соединена со вложенным property container, который содержит коллекцию связанных сущностей, то для того, чтобы таблицу можно было сортировать, атрибут-коллекция должен быть упорядоченного типа (List или LinkedHashSet). Если атрибут имеет тип Set, то атрибут sortable не оказывает влияния и пользователи не смогут сортировать таблицу.

    Если необходимо, можно создать собственную реализацию сортировки.

  • Атрибут presentations управляет механизмом представлений. Значение по умолчанию равно false. Когда значение атрибута равно true, то в верхнем правом углу таблицы появляется значок gui_presentation. Механизм представлений реализован только для блока Web Client.

  • Установка атрибута columnControlVisible в false запрещает пользователю скрывать колонки с помощью меню, выпадающего при нажатии на кнопку gui_table_columnControl в правой части шапки таблицы. Флажками в меню отмечаются отображаемые в данный момент колонки. Существуют дополнительные пункты меню:

    • Select all − показать все колонки таблицы;

    • Deselect all − спрятать все колонки, кроме первой. Первая колонка не скрывается для правильного отображения таблицы.

    gui table columnControl all
  • Установка атрибута reorderingAllowed в false запрещает пользователю менять местами колонки, перетаскивая их с помощью мыши.

  • Установка атрибута columnHeaderVisible в false скрывает заголовок таблицы.

  • При установленном в false атрибуте showSelection текущая строка не имеет выделения.

  • Атрибут contextMenuEnabled разрешает или запрещает показывать контекстное меню. По умолчанию атрибут имеет значение true. В контекстном меню отображаются действия таблицы (если они есть), и пункт Системная информация, содержащий информацию о выбранной сущности (если у пользователя есть разрешение cuba.gui.showInfo).

  • Если атрибуту multiLineCells таблицы присвоить значение true, то ячейки, содержащие текст с переносами строк, будут отображать его в несколько строк. В таком режиме в веб-клиенте для правильной работы полосы прокрутки все строки текущей страницы таблицы будут загружены веб-браузером сразу, без ленивой загрузки видимой части таблицы. По умолчанию атрибут имеет значение false.

  • Атрибут aggregatable включает режим агрегации строк таблицы. Поддерживаются следующие операции:

    • SUM - сумма

    • AVG - среднее значение

    • COUNT - количество

    • MIN - минимальное значение

    • MAX - максимальное значение

    Для агрегируемых колонок необходимо указать элемент aggregation с атрибутом type, задающим функцию агрегации. По умолчанию в агрегируемых колонках поддерживаются только числовые типы данных, такие как Integer, Double, Long и BigDecimal. Агрегированные значения столбцов выводятся в дополнительной строке вверху таблицы. Пример описания таблицы с агрегацией:

    <table id="itemsTable" aggregatable="true" dataContainer="itemsDc">
        <columns>
            <column id="product"/>
            <column id="quantity"/>
            <column id="amount">
                <aggregation type="SUM"/>
            </column>
        </columns>
    </table>

    Элемент aggregation может содержать атрибут editable. Установка атрибута в значение true совместно с использованием метода setAggregationDistributionProvider() позволяет реализовать функциональность распределения значения агрегируемой ячейки между строками таблицы.

    Элемент aggregation может также содержать атрибут strategyClass, указывающий класс, реализующий интерфейс AggregationStrategy (см. ниже пример установки стратегии агрегации программно).

    Атрибут valueDescription задает текст всплывающей подсказки, отображаемой при наведении курсора мыши по агрегированному значению. Для операций, перечисленных выше (SUM, AVG, COUNT, MIN, MAX), всплывающие подсказки уже есть по умолчанию.

    Для отображения агрегированного значения в виде, отличном от стандартного для данного Datatype, для него можно указать Formatter:

    <column id="amount">
        <aggregation type="SUM">
            <formatter class="com.company.sample.MyFormatter"/>
        </aggregation>
    </column>

    Атрибут aggregationStyle позволяет задать положение строки агрегации: TOP или BOTTOM. По умолчанию используется TOP.

    В дополнение к операциям, перечисленным выше, можно задать собственную стратегию агрегации путем создания класса, реализующего интерфейс AggregationStrategy, и передачи его методу setAggregation() класса Table.Column в составе экземпляра AggregationInfo. Например:

    public class TimeEntryAggregation implements AggregationStrategy<List<TimeEntry>, String> {
        @Override
        public String aggregate(Collection<List<TimeEntry>> propertyValues) {
            HoursAndMinutes total = new HoursAndMinutes();
            for (List<TimeEntry> list : propertyValues) {
                for (TimeEntry timeEntry : list) {
                    total.add(HoursAndMinutes.fromTimeEntry(timeEntry));
                }
            }
            return StringFormatHelper.getTotalDayAggregationString(total);
        }
        @Override
        public Class<String> getResultClass() {
            return String.class;
        }
    }
    AggregationInfo info = new AggregationInfo();
    info.setPropertyPath(metaPropertyPath);
    info.setStrategy(new TimeEntryAggregation());
    
    Table.Column column = weeklyReportsTable.getColumn(columnId);
    column.setAggregation(info);
  • Атрибут editable позволяет перевести таблицу в режим in-place редактирования ячеек. В этом режиме в колонках, имеющих атрибут editable = true, отображаются компоненты для редактирования значений атрибутов сущности, находящейся в источнике данных.

    Тип компонента для каждой редактируемой колонки выбирается автоматически на основании типа атрибута сущности. Например, для строковых и числовых атрибутов используется TextField, для Date - DateField, для перечислений - LookupField, для ссылок на другие сущности - PickerField.

    Для редактируемой колонки типа Date можно дополнительно указать атрибуты dateFormat или resolution аналогично описанным для DateField.

    Для редактируемой колонки, отображающей связанную сущность, можно дополнительно указать атрибуты optionsContainer и captionProperty. При указании optionsContainer вместо PickerField используется компонент LookupField.

    Произвольно настроить отображение ячеек, в том числе для редактирования содержимого, можно с помощью метода Table.addGeneratedColumn() - см. ниже.

  • В веб-клиенте с темой, основанной на Halo, атрибут stylename позволяет применять к таблице предопределенные стили Table. Стили задаются в XML-дексрипторе или контроллере экрана с помощью атрибута stylename:

    <table id="table"
           dataContainer="itemsDc"
           stylename="no-stripes">
        <columns>
            <column id="product"/>
            <column id="quantity"/>
        </columns>
    </table>

    Чтобы применить стиль программно, выберите одну из констант класса HaloTheme с префиксом компонента TABLE_:

    table.setStyleName(HaloTheme.TABLE_NO_STRIPES);
    Стили компонента Table
    • borderless - удаляет внешнюю рамку таблицы.

    • compact - уменьшает отступы внутри ячеек таблицы.

    • no-header - скрывает заголовки таблицы.

    • no-horizontal-lines - удаляет горизонтальные строковые разделители.

    • no-stripes - отключает чередование цветов строк таблицы.

    • no-vertical-lines - удаляет вертикальные разделители столбцов.

    • small - уменьшает размер шрифта и отступы внутри ячеек таблицы.

Методы интерфейса Table

  • метод addColumnCollapsedListener() позволяет отслеживать видимость колонок таблицы с помощью интерфейса слушателя ColumnCollapsedListener.

  • getSelected(), getSingleSelected() - возвращают экземпляры сущностей, соответствующие выделенным в таблице строкам. Коллекцию можно получить вызовом метода getSelected(). Если ничего не выбрано, возвращается пустой набор. Если multiselect отключен, удобно пользоваться методом getSingleSelected(), возвращающим одну выбранную сущность или null, если ничего не выбрано.

  • addSelectionListener() - позволяет отслеживать выделение строк таблицы, например:

    customersTable.addSelectionListener(customerSelectionEvent ->
            notifications.create()
                    .withCaption("You selected " + customerSelectionEvent.getSelected().size() + " customers")
                    .show());

    Также отслеживание изменений можно реализовать, подписавшись на соответствующее событие:

    @Subscribe("customersTable")
    protected void onCustomersTableSelection(Table.SelectionEvent<Customer> event) {
        notifications.create()
                .withCaption("You selected " + customerSelectionEvent.getSelected().size() + " customers")
                .show();
    }

    Источник события SelectionEvent можно отследить с помощью метода isUserOriginated().

  • Метод addGeneratedColumn() позволяет задать собственное представление данных в колонке. Он принимает два параметра: идентификатор колонки и реализацию интерфейса Table.ColumnGenerator. Идентификатор может совпадать с одним из идентификаторов, указанных для колонок таблицы в XML-дескрипторе - в этом случае новая колонка вставляется вместо заданной в XML. Если идентификатор не совпадает ни с одной колонкой, создается новая справа.

    Метод generateCell() интерфейса Table.ColumnGenerator вызывается таблицей для каждой строки, и в него передается экземпляр сущности, отображаемой в данной строке. Метод generateCell() должен вернуть визуальный компонент, который и будет отображаться в ячейке.

    Пример использования:

    @Inject
    private GroupTable<Car> carsTable;
    @Inject
    private CollectionContainer<Car> carsDc;
    @Inject
    private CollectionContainer<Color> colorsDc;
    @Inject
    private UiComponents uiComponents;
    @Inject
    private Actions actions;
    
    @Subscribe
    protected void onInit(InitEvent event) {
        carsTable.addGeneratedColumn("color", entity -> {
            LookupPickerField<Color> field = uiComponents.create(LookupPickerField.NAME);
            field.setValueSource(new ContainerValueSource<>(carsTable.getInstanceContainer(entity), "color"));
            field.setOptions(new ContainerOptions<>(colorsDc));
            field.addAction(actions.create(LookupAction.class));
            field.addAction(actions.create(OpenAction.class));
            return field;
        });
    }

    В данном случае в ячейках колонки color таблицы отображается компонент LookupPickerField. Компонент будет сохранять свое значение в атрибут color сущности, экземпляр которой отображается в данной строке.

    Метод getInstanceContainer(), возвращающий контейнер с текущим экземпляром сущности, должен использоваться только в data binding компонентов, создаваемых при генерации ячеек таблицы.

    Если в ячейке необходимо отобразить просто динамически сформированный текст, вместо компонента Label используйте класс Table.PlainTextCell. Это упростит отрисовку и сделает таблицу быстрее.

    Если в метод addGeneratedColumn() передан идентификатор колонки, не объявленной в XML-дескрипторе, то может понадобиться установить заголовок новой колонки следующим образом:

    carsTable.getColumn("colour").setCaption("Colour");

    Существует также более декларативный подход, использующий XML-атрибут generator.

  • Метод requestFocus() позволяет установить фокус на определенное поле конкретной записи. Принимает два параметра: экземпляр сущности, определяющий строку и идентификатор колонки. Пример программной установки фокуса:

    table.requestFocus(item, "count");
  • Метод scrollTo() позволяет программно прокрутить таблицу до нужной записи. Метод принимает экземпляр сущности, определяющий нужную строку в таблице.

    Пример использования метода:

    table.scrollTo(item);
  • Метод setCellClickListener() может избавить от необходимости добавлять генерируемые колонки с компонентами, если нужно нарисовать что-либо в ячейках и получать оповещения когда пользователь кликает на эти ячейки. Имплементация класса CellClickListener, передаваемая в данный метод, получает текущий экземпляр сущности и идентификатор колонки. Содержимое ячеек будет завернуто в элемент span со стилем cuba-table-clickable-cell, который можно использовать для задания отображения ячеек.

    Пример использования CellClickListener:

    @Inject
    private Table<Customer> customersTable;
    @Inject
    private Notifications notifications;
    
    @Subscribe
    protected void onInit(InitEvent event) {
        customersTable.setCellClickListener("name", customerCellClickEvent ->
                notifications.create()
                        .withCaption(customerCellClickEvent.getItem().getName())
                        .show());
    }
  • С помощью метода setAggregationDistributionProvider() можно задать провайдер AggregationDistributionProvider, определяющий правила распределения агрегированного значения между ячейками таблицы. Если пользователь вводит значение в агрегированную ячейку, оно распределяется по составляющим ячейкам в соответствии с кастомным алгоритмом. Алгоритм может учитывать и существующие значения ячеек. Поддерживается только для стиля агрегации TOP. Для того чтобы сделать агрегированные ячейки редактируемыми, используйте атрибут editable элемента aggregation.

    При создании провайдера используется объект AggregationDistributionContext<E>, который содержит данные, необходимые для распределения агрегируемого значения:

    • Column column − колонка, в которой произошло изменение значения в общей или групповой агрегации;

    • Object value − новое значение агрегации;

    • Collection<E> scope − коллекция сущностей, на которые повлияет изменение значения агрегации;

    • boolean isTotalAggregation указывает, в какой агрегации произошли изменения: в общей или групповой.

      В качестве примера рассмотрим таблицу, представляющую бюджет. Пользователь создает категории бюджета и задает для каждой из них проценты, в соответствии с которыми должна распределяться сумма дохода. Далее в агрегируемой ячейке указывается общая сумма дохода, после чего происходит распределение по категориям.

      Пример описания в дескрипторе:

      <table id="budgetItemsTable"
             width="100%"
             dataContainer="budgetItemsDc"
             aggregatable="true"
             editable="true"
             showTotalAggregation="true">
              ...
          <columns>
              <column id="category"/>
              <column id="percent"/>
              <column id="sum">
                  <aggregation editable="true"
                               type="SUM"/>
              </column>
          </columns>
              ...
      </table>

      Реализация в контроллере:

      budgetItemsTable.setAggregationDistributionProvider(context -> {
          Collection<BudgetItem> scope = context.getScope();
          if (scope.isEmpty()) {
              return;
          }
      
          double value = context.getValue() != null ?
                  ((double) context.getValue()) : 0;
      
          for (BudgetItem budgetItem : scope) {
              budgetItem.setSum(value / 100 * budgetItem.getPercent());
          }
      });
  • Метод getAggregationResults() возвращает мэп с результатами агрегации, где ключи в мэп − идентификаторы столбцов таблицы, а значения − значения агрегации.

  • Метод setStyleProvider() позволяет задать стиль отображения ячеек таблицы. Параметром метода должна быть реализация интерфейса Table.StyleProvider. Метод getStyleName() этого интерфейса вызывается таблицей отдельно для каждой строки и для каждой ячейки. Если метод вызван для строки, то первый параметр содержит экземпляр сущности, отображаемый этой строкой, а второй параметр null. Если же метод вызван для ячейки, то второй параметр содержит имя атрибута, отображаемого этой ячейкой.

    Пример задания стилей:

    @Inject
    protected Table customersTable;
    
    @Subscribe
    protected void onInit(InitEvent event) {
        customersTable.setStyleProvider((customer, property) -> {
            if (property == null) {
                // style for row
                if (hasComplaints(customer)) {
                    return "unsatisfied-customer";
                }
            } else if (property.equals("grade")) {
                // style for column "grade"
                switch (customer.getGrade()) {
                    case PREMIUM: return "premium-grade";
                    case HIGH: return "high-grade";
                    case MEDIUM: return "medium-grade";
                    default: return null;
                }
            }
            return null;
        });
    }

    Далее нужно определить заданные для строк и ячеек стили в теме приложения. Подробная информация о создании темы находится в Создание темы приложения. Для веб-клиента новые стили определяются в файле styles.scss. Имена стилей, заданные в контроллере, совместно с префиксами, обозначающими строку или колонку таблицы, образуют CSS-селекторы. Например:

    .v-table-row.unsatisfied-customer {
      font-weight: bold;
    }
    .v-table-cell-content.premium-grade {
      background-color: red;
    }
    .v-table-cell-content.high-grade {
      background-color: green;
    }
    .v-table-cell-content.medium-grade {
      background-color: blue;
    }
  • Метод addPrintable() позволяет задать специфическое представление данных колонки при выводе в XLS-файл, осуществляемом стандартным действием excel или напрямую с помощью класса ExcelExporter. Метод принимает идентификатор колонки и реализацию интерфейса Table.Printable для нее. Например:

    ordersTable.addPrintable("customer", new Table.Printable<Customer, String>() {
        @Override
        public String getValue(Customer customer) {
            return "Name: " + customer.getName;
        }
    });

    Метод getValue() интерфейса Table.Printable должен возвращать данные, которые будут находиться в ячейке таблицы. Это может быть не только строка - метод может возвращать значения других типов, например, числовые данные или даты, и они будут представлены в XLS-файле соответствующим образом.

    Если форматированный вывод в XLS необходим для генерируемой колонки, нужно использовать реализацию интерфейса Table.PrintableColumnGenerator, передавая ее методу addGeneratedColumn(). Значение для вывода в ячейку XLS-документа задается в методе getValue() этого интерфейса:

    ordersTable.addGeneratedColumn("product", new Table.PrintableColumnGenerator<Order, String>() {
        @Override
        public Component generateCell(Order entity) {
            Label label = uiComponents.create(Label.NAME);
            Product product = order.getProduct();
            label.setValue(product.getName() + ", " + product.getCost());
            return label;
        }
    
        @Override
        public String getValue(Order entity) {
            Product product = order.getProduct();
            return product.getName() + ", " + product.getCost();
        }
    });

    Если генерируемой колонке тем или иным способом не задано представления Printable, то в случае, если колонке соответствует атрибут сущности, будет выведено его значение, в противном случае не будет выведено ничего.

  • Метод setItemClickAction() позволяет задать действие, выполняемое при двойном клике на строке таблицы. Если такое действие не задано, при двойном клике таблица пытается найти среди своих действий подходящее в следующем порядке:

    • Действие, назначенное на клавишу Enter посредством свойства shortcut.

    • Действие с именем edit.

    • Действие с именем view.

      Если такое действие найдено и имеет свойство enabled = true, оно выполняется.

  • Метод setEnterPressAction() позволяет задать действие, выполняемое при нажатии клавиши Enter. Если такое действие не задано, таблица пытается найти среди своих действий подходящее в следующем порядке:

    • Действие, назначенное методом setItemClickAction().

    • Действие, назначенное на клавишу Enter посредством свойства shortcut.

    • Действие с именем edit.

    • Действие с именем view.

    Если такое действие найдено и имеет свойство enabled = true, оно выполняется.

  • setEmptyStateLinkClickHandler позволяет задать обработчик, который будет вызван после нажатия на гиперссылку в сообщении, установленном в атрибуте emptyStateLinkMessage:

    @Subscribe
    public void onInit(InitEvent event) {
        customersTable.setEmptyStateLinkClickHandler(emptyStateClickEvent ->
                    screenBuilders.editor(emptyStateClickEvent.getSource())
                        .newEntity()
                        .show());
    }
  • Метод setItemDescriptionProvider задает провайдер, служащий для генерации всплывающих подсказок для ячеек таблицы.

    В приведенном ниже примере мы покажем использование метода setItemDescriptionProvider для таблицы departmentsTable. Сущность Department имеет три атрибута: name, active, parentDept.

    @Inject
    private Table<Department> departmentsTable;
    
    @Subscribe
    public void onInit(InitEvent event) {
        departmentsTable.setItemDescriptionProvider(((department, property) -> {
            if (property == null) { (1)
                if (department.getParentDept() == null) {
                    return "Parent Department";
                }
            } else if (property.equals("active")) { (2)
                return department.getActive()
                        ? "Active department"
                        : "Inactive department";
            }
            return null;
        }));
    }
    1 – описание для строки.
    2 – описание для колонки "active".

Внешний вид компонента Table можно настроить с помощью переменных SCSS с префиксом $cuba-table-*. Эти переменные можно изменить в визуальном редакторе после расширения темы или создания новой темы.


Атрибуты table

align - aggregatable - aggregationStyle - caption - captionAsHtml - columnControlVisible - columnHeaderVisible - contextHelpText - contextHelpTextHtmlEnabled - contextMenuEnabled - css - dataContainer - description - descriptionAsHtml - editable - emptyStateLinkMessage - emptyStateMessage - enable - box.expandRatio - height - htmlSanitizerEnabled - id - metaClass - multiLineCells - multiselect - presentations - reorderingAllowed - settingsEnabled - showSelection - sortable - stylename - tabIndex - textSelectionEnabled - visible - width

Элементы table

actions - buttonsPanel - columns - rows - rowsCount

Атрибуты columns

includeAll - exclude

Атрибуты column

align - caption - captionAsHtml - captionProperty - collapsed - dateFormat - editable - expandRatio - generator - id - link - linkInvoke - linkScreen - linkScreenOpenType - maxTextLength - optionsContainer - resolution - sort - sortable - visible - width

Элементы column

aggregation - formatter

Атрибуты aggregation

editable - strategyClass - type - valueDescription

Предопределенные стили table

borderless - compact - no-header - no-horizontal-lines - no-stripes - no-vertical-lines - small

API

addGeneratedColumn - addPrintable - addColumnCollapseListener - addSelectionListener - applySettings - generateCell - getAggregationResults - getSelected - requestFocus - saveSettings - scrollTo - setAggregationDistributionProvider - setClickListener - setEmptyStateLinkClickHandler - setEnterPressAction - setItemClickAction - setItemDescriptionProvider - setStyleProvider