Table

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

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

Основы

Ниже представлена типичная таблица:

table anatomy
  1. Строка заголовка

  2. Строки

  3. Кнопка управления колонкой

  4. Разбивка на страницы

  5. Кнопка сортировки

  6. Панель кнопок

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

<data>
    <collection id="customersDc" class="ui.ex1.entity.Customer">
        <fetchPlan extends="_base"/>
        <loader id="customersDl">
            <query>
                <![CDATA[select e from uiex1_Customer e]]>
            </query>
        </loader>
    </collection>
</data>
<layout>
    <table id="customersTable"
           width="100%"
           dataContainer="customersDc">
        <actions>
            <action id="create" type="create"/>
            <action id="edit" type="edit"/>
            <action id="remove" type="remove"/>
            <action id="sendByEmail" type="sendByEmail">
                <properties>
                    <property name="recipientAddress" value="peter@example.com"/>
                </properties>
            </action>
        </actions>
        <columns>
            <column id="level"/>
            <column id="age"/>
            <column id="hobby"/>
            <column id="firstName"/>
            <column id="lastName"/>
            <column id="rewardPoints"/>
        </columns>
        <simplePagination/>
        <buttonsPanel id="buttonsPanel" alwaysVisible="true">
            <button id="createBtn" action="customersTable.create"/>
            <button id="editBtn" action="customersTable.edit"/>
            <button id="removeBtn" action="customersTable.remove"/>
            <button id="sendBtn" action="customersTable.sendByEmail"/>
        </buttonsPanel>
    </table>
</layout>

В приведенном примере есть контейнер коллекции для сущности Customer. Таблица привязана к контейнеру с помощью атрибута dataContainer, в то время как его элемент columns определяет, какие атрибуты сущности отображаются в колонках таблицы.

Привязка к данным

Декларативная привязка

Обычно компонент table привязывается к данным декларативно в XML-дескрипторе экрана, используя атрибут dataContainer. Он должен ссылаться на контейнер коллекции.

Использование контейнеров Key-Value

Таблицу можно привязать к контейнеру key-value для отображения результатов запроса, который возвращает скалярные значения и/или агрегаты. Например:

<data>
    <keyValueCollection id="salesDc">
        <loader id="salesLoader">
            <query>
                <![CDATA[select o.customer, o.customer.firstName,
                sum(o.amount) from uiex1_Order o group by o.customer]]>
            </query>
        </loader>
        <properties>
            <property class="ui.ex1.entity.Customer" name="customerEntity"/>
            <property datatype="string" name="customerName"/>
            <property datatype="decimal" name="sum"/>
        </properties>
    </keyValueCollection>
</data>
<layout>
    <table id="keyValueTable" width="100%" dataContainer="salesDc">
        <columns>
            <column id="customerName" caption="Customer"/>
            <column id="sum" caption="Summary amount" align="RIGHT"/>
        </columns>
    </table>
</layout>

Программная привязка

Если необходимо определить контейнер данных программно в контроллере экрана, установите атрибут metaClass вместо dataContainer в XML-дескрипторе:

<table id="customersTable1" width="100%" metaClass="uiex1_Customer">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
    </columns>
</table>

В контроллере экрана используйте класс ContainerDataGridItems для привязки таблицы к контейнеру данных:

customersTable1.setItems(new ContainerTableItems<>(customersDc));

Columns

Набор колонок таблицы определяется элементом columns. Если он не задан, то колонки таблицы будут автоматически взяты из фетч-плана, определенного в dataContainer.

Элемент columns имеет следующие атрибуты:

  • includeAll включает все атрибуты из fetchPlan, определенного в dataContainer.

    В приведенном ниже примере мы покажем все атрибуты из фетч-плана, используемого в customersDc:

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

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

    <data>
        <collection id="customersDc1" class="ui.ex1.entity.Customer">
            <fetchPlan extends="_base">
                <property name="city" fetchPlan="_base">
                    <property name="country" fetchPlan="_base"/>
                </property>
            </fetchPlan>
            <loader id="customersDl1">
                <query>
                    <![CDATA[select e from uiex1_Customer e]]>
                </query>
            </loader>
        </collection>
    </data>
    <layout>
        <table id="tableIncludeAllReference"
               width="100%"
               dataContainer="customersDc1">
            <columns includeAll="true">
                <column id="city.country.name"/>
            </columns>
        </table>
    </layout>
  • exclude содержит разделенный запятыми список атрибутов, которые не должны быть показаны в DataGrid.

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

    <table id="tableExclude"
           width="100%"
           dataContainer="customersDc1">
        <columns includeAll="true"
                 exclude="id,maritalStatus,email"/>
    </table>

Column

Каждая колонка описывается во вложенном элементе column.

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

<columns>
    <column id="firstName"/>
    <column id="lastName"/>
    <column id="city.name"/>
    <column id="city.country.name"/>
</columns>

Выравнивание колонок

Поддерживаются три различных выравнивания колонок: LEFT (по умолчанию), CENTER, and RIGHT.

Как правило, имеет смысл выровнять числа по правому краю и выровнять по левому краю все остальное содержимое. Например:

<table id="keyValueTable" width="100%" dataContainer="salesDc">
    <columns>
        <column id="customerName" caption="Customer"/>
        <column id="sum" caption="Summary amount" align="RIGHT"/>
    </columns>
</table>
table column align

Заголовок колонки

caption - необязательный атрибут, содержит заголовок колонки. Если не задан, будет отображено локализованное название атрибута сущности.

captionAsHtml - необязательный атрибут, определяющий возможность использовать HTML-теги в заголовке колонки. По умолчанию – false.

<column id="firstName"
        captionAsHtml="true"
        caption="msg://firstName"/> (1)
<column id="lastName"/> (2)
1 Заголовок колонки с HTML-тегами:
ui.ex1.screen.component.table/firstName=<em>First Name</em>
2 Колонка с заголовком по умолчанию
table captions

Видимость колонок

collapsed - необязательный атрибут, при указании true колонка будет изначально скрыта. Пользователи могут управлять видимостью колонки с помощью меню, доступного по нажатию кнопки table column control button в правом верхнем углу таблицы, если атрибут columnsCollapsingAllowed имеет значение true. По умолчанию имеет значение false.

Атрибут visible устанавливает видимость колонки. Возможные значения – true, false. По умолчанию все колонки видимы.

Рассмотрим разницу между атрибутами collapsed и visible в следующем примере.

<columns>
    <column id="firstName"
            collapsed="true"/>
    <column id="lastName"
            visible="false"/>
    <column id="city"/>
</columns>
table columns visibility

Как можно видеть, колонка firstName по умолчанию свернута, но пользователи могут развернуть ее из выпадающего меню кнопки table column control button.

В то же время колонка lastName не может быть свернута пользователем.

Ширина колонки

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

<columns>
    <column id="firstName" width="100"/>
    <column id="lastName" width="150"/>
    <column id="city" width="100"/>
</columns>
table column width

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

<columns>
    <column id="firstName" expandRatio="1"/>
    <column id="lastName" expandRatio="1.5"/>
    <column id="city" expandRatio="1"/>
</columns>
table column expand ratio

Пользователи могут изменять размеры колонок:

table columns resize

Ширина колонки остается фиксированной только если атрибут enable установлен в false для всей таблицы.

Изменение порядка колонок

Table позволяет пользователям менять порядок колонок с помощью перетаскивания.

table columns reordering

Возможность менять порядок колонок включена по умолчанию. Чтобы отключить ее, задайте для атрибута reorderingAllowed значение false.

<column id="firstName"
        link="true"
        linkScreenOpenMode="DIALOG"/>
<column id="lastName"/>
<column id="city"/>
table columns link

Максимальная длина текста

maxTextLength – необязательный атрибут, позволяет ограничивать количество символов в ячейке. Лишние символы заменяются многоточием. Для просмотра полной записи пользователю надо кликнуть на ее видимую часть.

Если разница между фактическим и допустимым количеством символов не превышает порог в 10 символов, "лишние" символы не скрываются.

В приведенном ниже примере некоторые ячейки содержат значения длиннее чем maxTextLength+10 и обрезаются:

<columns>
    <column id="firstName"/>
    <column id="lastName"/>
    <column id="email" maxTextLength="15"/>
    <column id="city"/>
</columns>
table max text length

Форматирование текста

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

<table id="tableColumnFormatter"
       width="100%"
       dataContainer="ordersDc">
    <columns>
        <column id="customer"/>
        <column id="amount"/>
        <column id="deliveryTime">
            <formatter>
                <date format="h:mm a"/>
            </formatter>
        </column>
    </columns>
</table>

captionProperty

Атрибут captionProperty указывает имя атрибута сущности, который должен быть отображен в колонке вместо указанного в id. Например, если имеется связанная сущность City с атрибутами name и id, можно определить следующую колонку:

<column id="city"
        caption="City ID"
        captionProperty="id"/>

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

table captions

Перенос строк в ячейке

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

table multi line cell

Выделение

Компонент Table позволяет пользователям выделять одну или несколько строк.

Единичный выбор строки

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

Множественный выбор

Атрибут multiselect включает множественный выбор строк таблицы. Если ему задано значение true, то пользователи смогут выделять несколько строк за раз, используя клавиатуру или мышь и зажимая клавиши Ctrl или Shift. По умолчанию множественный выбор отключен.

Видимость выделения

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

Выделение текста

Атрибут textSelectionEnabled определяет, разрешено ли выделение текста в ячейках таблицы. По умолчанию false.

Заполнитель

Table позволяет задать позволяет настроить заполнитель в виде сообщения и/или ссылки, отображаемый в случае, если контейнер данных пуст или не задан.

Заполнитель-сообщение определяется атрибутом emptyStateMessage. Он должен содержать информацию о том, почему таблица пуста.

Например:

<table id="tablePlaceholder"
       width="100%"
       height="200"
       metaClass="uiex1_Customer"
       emptyStateMessage="No customers added."
       emptyStateLinkMessage="Add customer">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
    </columns>
</table>
table placeholder

Сгенерируйте emptyStateLinkClickHandler для обработки нажатий по ссылке:

@Install(to = "tablePlaceholder", subject = "emptyStateLinkClickHandler")
private void tablePlaceholderEmptyStateLinkClickHandler(
        Table.EmptyStateClickEvent<Customer> emptyStateClickEvent) {
    screenBuilders.editor(emptyStateClickEvent.getSource())
            .newEntity()
            .show();
}

Чтобы создать слушателя нажатий программно, используйте метод компонента setEmptyStateLinkClickHandler().

И emptyStateMessage, и emptyStateLinkMessage могут загружать сообщения из пакета сообщений.

Видимость заголовка

Атрибут columnHeaderVisible устанавливает видимость заголовка таблицы. По умолчанию имеет значение true.

Управление видимостью колонок

Пользователи могут выбрать, какие колонки будут видимы, используя кнопку управления колонками table column control button в правой части заголовка таблицы.

Отображаемые в данный момент колонки отмечены в выпадающем меню. В нем есть дополнительные пункты:

  • Select all - показать все колонки;

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

table column control using

Если columnControlVisible имеет значение false, пользователи не смогут скрывать колонки.

Агрегация

Table поддерживает агрегацию значений в строки.

Поддерживаются следующие операции:

  • SUM - вычисление суммы;

  • AVG - вычисление среднего значения;

  • COUNT - вычисление общего количества;

  • MIN - вывод минимального значения;

  • MAX - вывод максимального значения.

Чтобы включить агрегацию для таблицы, необходимо:

  1. Установить для атрибута aggregatable значение true.

  2. Указать элемент aggregation для агрегируемых колонок.

  3. Указать для элемента aggregation атрибут type, задающий функцию агрегации.

Агрегированные значения выводятся в дополнительной строке.

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

По умолчанию в агрегируемых колонках поддерживаются только числовые типы данных, такие как Integer, Double, Long, и BigDecimal.

Пример описания таблицы с агрегацией:

<table id="tableAggregation"
       width="100%"
       aggregatable="true"
       dataContainer="customersDc1">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="rewardPoints"/>
        <column id="age">
            <aggregation type="AVG"/>
        </column>
    </columns>
</table>
table aggregation

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

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

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

<column id="amount">
    <aggregation type="SUM">
        <formatter>
            <number format="#,##0.00"/>
        </formatter>
    </aggregation>
</column>

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

public class TableCustomerHobbyAggregation implements AggregationStrategy<Hobby, String> {
    @Override
    public String aggregate(Collection<Hobby> propertyValues) {
        Hobby mostFrequent = null;
        long max = 0;
        if (CollectionUtils.isNotEmpty(propertyValues)) {
            for (Hobby hobby : Hobby.values()) {
                long current = propertyValues.stream()
                        .filter(customerHobby -> customerHobby.equals(hobby))
                        .count();

                if (current > max) {
                    mostFrequent = hobby;
                    max = current;
                }
            }
        }

        if (mostFrequent != null) {
            return String.format("%s: %d/%d", mostFrequent.name(), max, propertyValues.size());
        }

        return null;
    }

    @Override
    public Class<String> getResultClass() {
        return String.class;
    }
}
<table id="tableAggregationStrategy"
       width="100%"
       aggregatable="true"
       dataContainer="customersDc">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="hobby">
            <aggregation
                    strategyClass="ui.ex1.screen.component.table.TableCustomerHobbyAggregation"/>
        </column>
    </columns>
</table>

Сортировка

Table позволяет пользователям сортировать данные колонки. Функция сортировки включена по умолчанию.

Атрибут sortable позволяет сортировать данные в таблице. По умолчанию имеет значение true. Если сортировка разрешена, при щелчке по заголовку колонки появится table sortable down/table sortable up значок справа от названия колонки.

Можно отключить сортировку для конкретной колонки, используя ее атрибут sortable.

В примере ниже отключим сортировку по колонке lastName:

<columns>
    <column id="firstName"/>
    <column id="lastName" sortable="false"/>
    <column id="city"/>
</columns>

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

  • ASCENDING - сортировка по возрастанию (0 → 9 → A → Z).

  • DESCENDING - сортировка по убыванию (Z → A → 9 → 0).

Например:

<columns>
    <column id="firstName" sort="DESCENDING"/>
    <column id="lastName"/>
    <column id="city"/>
</columns>

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

Разбивка на страницы

Компонент SimplePagination может быть использован внутри table для обеспечения разбивки на страницы:

<table id="tablePaging"
       width="100%"
       dataContainer="customersDc">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="hobby"/>
        <column id="age"/>
    </columns>
    <simplePagination
            itemsPerPageVisible="true"
            itemsPerPageOptions="2, 4, 6"/>
</table>
table pagination

В качестве альтернативы можно использовать отдельный компонент Pagination.

Действия Table

Компонент Table реализует интерфейс ActionsHolder и может содержать настраиваемые действия и стандартные действия со списками.

Действия таблицы определяются во вложенном элементе actions.

Если действие имеет название, оно отображается как элемент контекстного меню таблицы. Кроме того, действие таблицы может быть назначено кнопке, расположенной в любом месте экрана.

Для отображения кнопок действий над таблицей данных можно использовать контейнер ButtonsPanel.

<table id="tableWithActions"
       width="100%"
       dataContainer="customersDc">
    <actions>
        <action id="create" type="create"/> (1)
        <action id="edit" type="edit"/>
        <action id="remove" type="remove"/>
        <action id="about" caption="Get info"/> (2)
    </actions>
    <columns>
        <column id="age"/>
        <column id="firstName"/>
        <column id="lastName"/>
    </columns>
    <buttonsPanel id="buttonsActionsPanel" alwaysVisible="true"> (3)
        <button id="create" action="tableWithActions.create"/>
        <button id="edit" action="tableWithActions.edit"/>
        <button id="remove" action="tableWithActions.remove"/>
        <button id="about" action="tableWithActions.about"/>
    </buttonsPanel>
</table>
1 Определение стандартного действия create.
2 Определение настраиваемого действия about.
3 Определение контейнера ButtonsPanel в таблице.
table actions

Генерация колонок

Обработчик columnGenerator позволяет задавать собственное отображение данных в колонке.

Этот обработчик вызывается фреймворком для каждой ячейки при рендеринге таблицы. Он получает экземпляр сущности, соответствующий отображаемой строке, и должен вернуть визуальный компонент, который будет отображаться в ячейке.

Обработчик columnGenerator для таблицы можно создать с помощью Studio (см. ниже) и реализовать его следующим образом:

@Install(to = "tableGeneratedColumn.hasEmail", subject = "columnGenerator")
private Component tableGeneratedColumnIsEmailColumnGenerator(Customer customer) {
    CheckBox hasEmail = uiComponents.create(CheckBox.class);
    hasEmail.setValue(customer.getEmail() != null);
    return hasEmail;
}

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

@Install(to = "tableGeneratedColumn.fullName", subject = "columnGenerator")
private Component tableGeneratedColumnFullNameColumnGenerator(Customer customer) {
    return new Table.PlainTextCell(customer.getFirstName() + " " + customer.getLastName());
}
<table id="tableGeneratedColumn"
       width="100%"
       dataContainer="customersDc">
    <columns>
        <column id="age"/>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="fullName" caption="Full name"/>
        <column id="email"/>
        <column id="hasEmail" caption="Has email"/>
    </columns>
</table>

fullName и isEmail являются генерированными колонками.

table generated columns

Если идентификатор колонки указывает на атрибут связанной сущности (то есть содержит точки), то обработчик columnGenerator должен быть объявлен как на примере ниже.

  • Колонка, ассоциированная с атрибутом связанной сущности:

    <column id="city.country.name"/>
  • Соответствующий обработчик columnGenerator:

    @Install(to = "countryTable.[city.country.name]", subject = "columnGenerator")
    private Component countryTableCityCountryNameColumnGenerator(Customer customer) {
        return new Table.PlainTextCell(customer.getCity().getCountry().getName());
    }

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

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

Экспорт значений колонок

Чтобы экспортировать содержимое компонента Table в виде файла в одном из поддерживаемых форматов, используйте дополнение Grid Export Actions.

После установки дополнения вы можете определить для таблицы действие excelExport или jsonExport или использовать TableExporter.

Если вы используете собственные генерируемые колонки, их содержимое по умолчанию не экспортируется. См. пример в разделе Экспорт таблиц со сгенерированными колонками.

Ниже приведен пример настройки пользовательского представления данных в колонке при экспорте в файл XLS с помощью действия excelExport.

Дескриптор экрана:

<table id="printableTable"
       width="100%"
       dataContainer="customersDc1">
    <actions>
        <action id="excelExport" type="excelExport"/>
    </actions>
</table>

Контроллер экрана:

@Named("printableTable.excelExport")
protected ExcelExportAction printableTableExcelExport;

@Subscribe
public void onInit(InitEvent event) {
    printableTableExcelExport.addColumnValueProvider("firstName", context -> { (1)
        Customer customer = context.getEntity();
        return "Name: " + customer.getFirstName();
    });
}
1 Метод принимает идентификатор колонки и функцию для получения значения из колонки.

Редактирование значений

Таблица может быть настроена таким образом, чтобы разрешить внутристрочное редактирование.

Используйте атрибут editable для переключения таблицы в режим редактирования.

В этом режиме в колонках, имеющих атрибут editable = true, отображаются компоненты для редактирования значений атрибутов соответствующей сущности. Изменение этого атрибута во время выполнения не поддерживается.

Тип компонента для каждой редактируемой колонки выбирается автоматически на основе типа соответствующего атрибута сущности. Например, для строковых и числовых атрибутов приложение будет использовать TextField, для DateDateField, для перечислений – ComboBox, для ссылок на другие сущности – EntityPicker.

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

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

Контекстное меню

Контекстное меню активируется щелчком правой кнопки мыши в таблице данных.

Атрибут contextMenuEnabled включает или выключает контекстное меню. По умолчанию имеет значение true. В контекстном меню отображаются действия таблицы (если таковые имеются).

table context menu

Стили

Компоненту Table можно задать предопределенные стили с помощью атрибута stylename в XML-дескрипторе или в контроллере экрана:

<table id="tableBorderless"
       caption="Table with borderless style"
       width="100%"
       stylename="borderless"
       dataContainer="customersDc1">
tableBorderless.setStyleName(ThemeClassNames.TABLE_BORDERLESS);

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

  • borderless - удаляет внешнюю рамку;

  • no-header - скрывает заголовки колонок;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      Пример задания ItemClickAction для компонента Table, определенного в XML-файле экрана с идентификатором tableClick:

      @Autowired
      private Table<Customer> tableClick;
      
      @Subscribe
      public void onInit(InitEvent event) {
          tableClick.setItemClickAction(new BaseAction("itemClickAction")
                  .withHandler(actionPerformedEvent -> {
                      Customer customer = tableClick.getSingleSelected();
                      if (customer != null) {
                          notifications.create()
                                  .withCaption("Item clicked for: " + customer.getFirstName()+
                                          "" + customer.getLastName())
                                  .show();
                      }
                  }));
      }
  • Метод setEnterPressAction() позволяет задать действие, выполняемое при нажатии клавиши Enter. Если такое действие не задано, таблица пытается найти среди своих действий подходящее в следующем порядке:

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

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

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

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

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

      Пример задания ItemClickAction для компонента Table, определенного в XML-файле экрана с идентификатором tableClick:

      @Autowired
      private Table<Customer> tableClick;
      
      @Subscribe
      public void onInit(InitEvent event) {
          tableClick.setEnterPressAction(new BaseAction("enterPressAction")
                  .withHandler(actionPerformedEvent -> {
                      Customer customer = tableClick.getSingleSelected();
                      if (customer != null) {
                          notifications.create()
                                  .withCaption("Enter pressed for: " + customer.getFirstName()+
                                          "" + customer.getLastName())
                                  .show();
                      }
                  }));
      }
  • Метод getAggregationResults() возвращает мэп с результатами агрегации, где ключи в мэп – идентификаторы колонок таблицы, а значения – значения агрегации.

Слушатели и события

Чтобы сгенерировать заглушку слушателя в Jmix Studio, выберите компонент в XML-дескрипторе экрана или на панели Component Hierarchy и используйте вкладку Handlers панели Component Inspector.

В качестве альтернативы вы можете воспользоваться кнопкой Generate Handler на верхней панели контроллера экрана.

AggregationDistributionProvider

Определяет правила распределения агрегированного значения между ячейками таблицы в соответствии с кастомным алгоритмом. Если пользователь вводит значение в агрегированную ячейку, оно распределяется по составляющим ячейкам. Поддерживается только для стиля агрегации TOP. Для того чтобы сделать агрегированные ячейки редактируемыми, используйте атрибут editable элемента aggregation.

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

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

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

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

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

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

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

<table id="budgetTable"
       width="100%"
       aggregatable="true"
       dataContainer="budgetItemsDc">
    <columns>
        <column id="category"/>
        <column id="percent"/>
        <column id="amount">
            <aggregation type="SUM"
                         editable="true"/>
        </column>
    </columns>
</table>

Пример в контроллере экрана:

@Install(to = "budgetTable", subject = "aggregationDistributionProvider")
private void budgetTableAggregationDistributionProvider(
        Table.AggregationDistributionContext<BudgetItem> context) {
    Collection<BudgetItem> scope = context.getScope();
    if (scope.isEmpty()) {
        return;
    }

    double value = context.getValue() != null ?
            ((double) context.getValue()) : 0;

    for (BudgetItem budgetItem : scope) {
        budgetItem.setAmount(value / 100 * budgetItem.getPercent());
    }
}
table aggregation budget

Чтобы создать провайдера программно, используйте метод компонента setAggregationDistributionProvider().

ColumnCollapseEvent

ColumnCollapseEvent отправляется при изменении видимости колонки.

Пример подписки на событие таблицы, объявленного в XML с идентификатором tableCollapsed:

@Subscribe("tableCollapsed")
public void onTableCollapsedColumnCollapse(Table.ColumnCollapseEvent<Customer> event) {
    notifications.create()
            .withCaption((event.isCollapsed() ? "Collapsed: " : "Expanded: ") +
                    event.getColumn().getCaption())
            .show();
}

Чтобы создать слушателя события программно, используйте метод компонента addColumnCollapseListener().

ColumnReorderEvent

ColumnReorderEvent отправляется при изменении пользователем порядка колонок.

Пример подписки на событие таблицы, объявленного в XML с идентификатором tableReorder:

@Subscribe("tableReorder")
public void onTableReorderColumnReorder(Table.ColumnReorderEvent<Customer> event) {
    notifications.create()
            .withCaption("Columns were reordered!")
            .show();
}

Чтобы создать слушателя события программно, используйте метод компонента addColumnReorderListener().

ContextHelpIconClickHandler

IconProvider

Данный провайдер позволяет добавлять значок в начало каждой строки таблицы:

@Install(to = "tableWithIcons", subject = "iconProvider")
private String tableWithIconsIconProvider(Customer customer) {
    return customer.getEmail() != null ?
            JmixIcon.MAIL_FORWARD.source() : JmixIcon.CANCEL.source();
}
table icon provider

Чтобы создать провайдер программно, используйте метод компонента setIconProvider().

ItemDescriptionProvider

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

В приведенном ниже примере покажем использование ItemDescriptionProvider для tableWithDescription:

@Install(to = "tableWithDescription", subject = "itemDescriptionProvider")
private String tableWithDescriptionItemDescriptionProvider(
        Customer customer, String property) {
    if (property == null)
        return null;
    else if (property.equals("rewardPoints")) {
        return "Reward points are a part of the loyalty program affecting the rating of the " +
                customer.getFirstName() + " " + customer.getLastName();
    } else if (property.equals("level")) {
        switch (customer.getLevel()) {
            case SILVER:
                return "The customer gets special offers from sellers and birthday congratulations";
            case GOLD:
                return "The customer gets 2 coupons with a rating of $ 1";
            case PLATINUM:
                return "The customer gets a coupons with a par value of $ 3";
            case DIAMOND:
                return "The customer gets a coupon with a par value of $ 5";
        }
    }
    return null;
}
table item description

LookupSelectHandler

LookupSelectHandler – это обработчик, вызываемый, когда пользователь нажимает Enter или дважды щелкает по строке таблицы на экране выбора. Он принимает коллекцию выделенных сущностей. Можно определить данный обработчик следующим образом:

@Install(to = "tableLookupSelect", subject = "lookupSelectHandler")
private void tableLookupSelectLookupSelectHandler(Collection<Customer> collection) {
    checkCustomers(collection);
}

Чтобы создать обработчик программно, используйте метод компонента setLookupSelectHandler().

SelectionEvent

SelectionEvent отправляется при изменении выделения.

Пример подписки на событие таблицы, объявленного в XML с идентификатором tableSelectEvent:

@Autowired
private Table<Customer> tableSelectEvent;

@Subscribe("tableSelectEvent")
public void onTableSelectEventSelection(Table.SelectionEvent<Customer> event) {
    Customer customer = tableSelectEvent.getSingleSelected();
    notifications.create()
            .withCaption("You selected " + customer.getFirstName() +
                    " " + customer.getLastName() + " customer")
            .show();
}

Чтобы создать слушателя события программно, используйте метод компонента addSelectionListener().

StyleProvider

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

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

@Install(to = "styledTable", subject = "styleProvider")
private String styledTableStyleProvider(Customer entity, String property) {
    if (property == null) {
        if (Boolean.TRUE.equals(entity.getEmail() != null)) {
            return "customer-has-email";
        }
    } else if (property.equals("level")) {
        switch (entity.getLevel()) {
            case SILVER:
                return "level-silver";
            case GOLD:
                return "level-gold";
            case PLATINUM:
                return "level-platinum";
            case DIAMOND:
                return "level-diamond";
        }
    }
    return null;
}

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

.customer-has-email {
    font-weight: bold;
}

.level-silver {
    background-color: #f2f2f2;
    color: black;
}

.level-gold {
    background-color: #ffda79;
    color: black;
}

.level-platinum {
    background-color: #637497;
    color: white;
}

.level-diamond {
    background-color: #8befff;
    color: black;
}
table style provider

Чтобы создать провайдер программно, используйте метод компонента setStyleProvider().

Все XML-атрибуты

Просматривать и редактировать атрибуты, применимые к компоненту, можно с помощью панели Component Inspector конструктора экранов Studio.

XML-элементы Table

XML-атрибуты Columns

XML-элементы Column

XML-атрибуты Aggregation

XML-элементы Aggregation