Статьи

Стол мертв, да здравствует решетка

Vaadin 7.4.0 наконец-то вышел, и вместе с ним появился долгожданный преемник   компонента TableGrid . Что касается остальной части Ваадина, это довольно  хорошо задокументировано .

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

Первые шаги с сеткой

Первый проект реализации будет выглядеть так:

public class SampleGrid extends Grid {

    public SampleGrid(Container.Indexed indexed) {
        setContainerDataSource(indexed);
    }
}

Столбцы сетки

Это просто и довольно просто. На данный момент ничто не отличает новые  Grid от старых  Tableсортируемых столбцов только по умолчанию. Поскольку большинство приложений чата этого не допускают — и одно из мастерской, давайте отключим его:

public class SampleGrid extends Grid {

    public SampleGrid(Container.Indexed indexed) {
        setContainerDataSource(indexed);
        getColumns().stream().forEach(c -> c.setSortable(false));
    }
}

Таким образом,  Grid компонент имеет понятие столбцов. Можно получить ссылку на столбец из одного столбца, передав  propertyId элемент  getColumn(propertyId) или последовательность всех столбцов  getColumns(). Обратите внимание, что Java 8 помогает в обработке каждого столбца с помощью Stream API и простого использования лямбды.

Завернутый контейнер

Следующим шагом является скрытие столбца идентификатора сообщения; с  Table, это было достигнуто путем вызова setVisibleColumns() и пропуска  id свойства в массиве параметров. В Vaadin 7.4 Container иерархия была обогащена шаблоном «Делегат»:  GeneratedPropertyContainer это оболочка вокруг другого контейнера, но предлагает дополнительные методы, в том числе, removeContainerProperty(propertyId) которые эффективно скрывают свойство от упакованного контейнера. Это производит следующий код:

public class SampleGrid extends Grid {

    public SampleGrid(Container.Indexed indexed) {
        GeneratedPropertyContainer wrapperContainer = new GeneratedPropertyContainer(indexed);
        wrapperContainer.removeContainerProperty("id");
        setContainerDataSource(wrapperContainer);
        getColumns().stream().forEach(c -> c.setSortable(false));
    }
}

Renderers

Теперь давайте отформатируем столбец даты. Причем  Table, это требовало реализации выделенного  ColumnGenerator. На первый взгляд кажется, addGeneratedProperty что стоит использовать  упакованный контейнер, упомянутый в предыдущем разделе. Тем не менее, для простых вопросов форматирования Vaadin 7.4 предоставляет  Rendererинтерфейс: для любого средства визуализации может быть установлен любой столбец. Обледенение на торте,  DateRenderer предоставляется, который принимает строку формата в качестве аргумента.

public class SampleGrid extends Grid {

    private static final String FORMAT = "%1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS";

    public SampleGrid(Container.Indexed indexed) {
        GeneratedPropertyContainer wrapperContainer = new GeneratedPropertyContainer(indexed);
        wrapperContainer.removeContainerProperty("id");
        setContainerDataSource(wrapperContainer);
        getColumn("timeStamp").setRenderer(new DateRenderer(FORMAT));
        getColumns().stream().forEach(c -> c.setSortable(false));
    }
}

Обратите внимание, что строка формата использует шаблон из  Formatter, а не из  SimpleDateFormat.

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

Последняя задача — добавить функцию удаления. Готово, установка режима выбора на множественное создание нового столбца с флажками для выбора нескольких строк:

public class SampleGrid extends Grid {

    private static final String FORMAT = "%1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS";

    public SampleGrid(Container.Indexed indexed) {
        GeneratedPropertyContainer wrapperContainer = new GeneratedPropertyContainer(indexed);
        wrapperContainer.removeContainerProperty("id");
        setContainerDataSource(wrapperContainer);
        getColumn("timeStamp").setRenderer(new DateRenderer(FORMAT));
        getColumns().stream().forEach(c -> c.setSortable(false));
        setSelectionMode(SelectionMode.MULTI);
    }
}

Затем просто создайте простую кнопку, которая удалит все выделенные строки. Это делает работу. Однако это не оригинальный дизайн: на приведенном выше снимке экрана каждая строка имеет свою собственную выделенную кнопку. Pro, вы должны нажать на выбранную строку, чтобы предотвратить большинство ошибок; con, вы не можете пакетно удалить.

Наряду с средством визуализации даты, Vaadin 7.4 также предоставляет функцию,  ButtonRenderer которая принимает  RenderClickListener поведение для добавления. Это нужно только установить в  id столбце.

public class SampleGrid extends Grid {

    private static final String FORMAT = "%1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS";

    public SampleGrid(Container.Indexed indexed) {
        GeneratedPropertyContainer wrapperContainer = new GeneratedPropertyContainer(indexed);
        setContainerDataSource(wrapperContainer);
        getColumn("timeStamp").setRenderer(new DateRenderer(FORMAT));
        getColumn("id").setRenderer(new ButtonRenderer(event -> {
            Object itemId = event.getItemId();
            indexed.removeItem(itemId);
        }));
        getColumns().stream().forEach(c -> c.setSortable(false));
        setSelectionMode(SelectionMode.MULTI);
    }
}

Недостатком этого подхода является то, что вы не можете изменить метку кнопки, поскольку она взята из базового объекта без возможности его изменения. В этом случае идентификатор сообщения будет отображаться в кнопке, и пользователи могут по неосторожности удалить сообщение. Это не может быть и речи.

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

public class SampleGrid extends Grid {

    private static final String FORMAT = "%1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS";

    public SampleGrid(Container.Indexed indexed) {
        GeneratedPropertyContainer wrapperContainer = new GeneratedPropertyContainer(indexed);
        wrapperContainer.removeContainerProperty("id");
        setContainerDataSource(wrapperContainer);
        wrapperContainer.addGeneratedProperty("delete", new PropertyValueGenerator<String>() {
            @Override
            public String getValue(Item item, Object itemId, Object propertyId) {
                return "Delete";
            }

            @Override
            public Class<String> getType() {
                return String.class;
            }
        });
        getColumn("delete").setRenderer(new ButtonRenderer(event -> {
            Object itemId = event.getItemId();
            indexed.removeItem(itemId);
        }));
        getColumn("timeStamp").setRenderer(new DateRenderer(FORMAT));
        getColumns().stream().forEach(c -> c.setSortable(false));
    }
}

Новое сгенерированное свойство добавляется с  PropertyValueGenerator всегда возвращаемой строкой  Delete. Более продвинутые требования могут использовать a  Locale для отображения в зависимости от предпочтений пользователя, но этого кода нам достаточно. Обратите внимание, что средство визуализации кнопок сохраняется, но назначается новому  delete сгенерированному столбцу вместо идентификаторов. Наконец, режим множественного выбора должен быть удален.

заголовок

Последний штрих — удалить заголовки столбцов, как и в любом приложении чата. Это просто сделано с setHeaderVisible(false).

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

Код для этой статьи можно просмотреть и разветвить на  Github .