Java/Vaadin — реализация пользовательского скрытого компонента FormLayout

Я работаю над веб-приложением в vaadin и в настоящее время пытаюсь реализовать адресную книгу. Я просмотрел официальные реализации на github и попытался построить их.

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

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

Вот текущая реализация

package com.example.ecenter.view;

import com.vaadin.data.Binder;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.SpringView;
import com.vaadin.ui.Button;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.Grid;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;

import io.valhala.ecenter.temp.Client;

import java.util.Arrays;
import java.util.List;

@SpringView(name = AddressBookView.VIEW_NAME)
@SpringComponent
public class AddressBookView extends HorizontalLayout implements View
{
    public static final String VIEW_NAME = "Address Book";
    Grid<Client> contactList = new Grid<>(Client.class);
    private List<Client> clients = Arrays.asList(
        new Client("Sernie", "A", "123 Test St.", "[email protected]", "555-555-5554"),
        new Client("Ernie", "B", "123 Test St.", "[email protected]", "555-555-5555"),
        new Client("Bernie", "C", "123 Test St.", "[email protected]", "555-555-5556"),
        new Client("Ayy", "Lmao", "123 Test St.", "[email protected]", "555-555-5557"),
        new Client("Dax", "E", "123 Test St.", "[email protected]", "555-555-5558"),
        new Client("Avorion", "F", "123 Test St.", "[email protected]", "555-555-5559"),
        new Client("Xanion", "G", "123 Test St.", "[email protected]", "555-555-5560"),
        new Client("Trinium", "H", "123 Test St.", "[email protected]", "555-555-5561"),
        new Client("Naonite", "I", "123 Test St.", "[email protected]", "555-555-5562"),
        new Client("Squillium", "J", "123 Test St.", "[email protected]", "555-555-5563"),
        new Client("Picard", "K", "123 Test St.", "[email protected]", "555-555-5564"),
        new Client("Richard", "L", "123 Test St.", "[email protected]", "555-555-5565"),
        new Client("Rickard", "M", "123 Test St.", "[email protected]", "555-555-5566"),
        new Client("Bobby", "N", "123 Test St.", "[email protected]", "555-555-5567"),
        new Client("Bob", "O", "123 Test St.", "[email protected]", "555-555-5568"),
        new Client("Ron", "P", "123 Test St.", "[email protected]", "555-555-5569"),
        new Client("Bill", "Q", "123 Test St.", "[email protected]", "555-555-5570"),
        new Client("Greg", "R", "123 Test St.", "[email protected]", "555-555-5571"),
        new Client("Juan", "S", "123 Test St.", "[email protected]", "555-555-5572"),
        new Client("Squidward", "T", "123 Test St.", "[email protected]", "555-555-5573"));

private ContactForm contactForm = new ContactForm();
private TextField filter = new TextField();
private Button addContact = new Button("New Client");

public AddressBookView()
{
    initConfig();
    buildLayout();
}

private void buildLayout() 
{
    HorizontalLayout actionBar = new HorizontalLayout(filter, addContact);
    actionBar.setWidth("100%");
    filter.setWidth("100%");
    actionBar.setExpandRatio(filter, 1);

    VerticalLayout left = new VerticalLayout(actionBar, contactList);
    left.setSizeFull();
    contactList.setSizeFull();
    left.setExpandRatio(contactList, 1);

    HorizontalLayout mainLayout = new HorizontalLayout(left);
    mainLayout.setSizeFull();
    mainLayout.setExpandRatio(left, 1);

    //HorizontalLayout test = new HorizontalLayout(contactForm);
    addComponent(mainLayout);

    //addComponent(test);
    /*
     * even using a different layout still messes it up
     */

    //contactForm.setVisible(false);
}

private void initConfig() 
{
    addContact.addClickListener(event -> 
    {
        addComponent(contactForm);
        contactForm.setClient(new Client());
    });

    filter.setPlaceholder("Search clients...");
    addContact.addStyleName(ValoTheme.BUTTON_PRIMARY);
    //filter.addValueChangeListener(e -> refreshContacts(e.getText()));

    contactList.setSelectionMode(Grid.SelectionMode.SINGLE);
    contactList.setColumns("firstName", "lastName");
    contactList.setItems(clients);

    contactList.asSingleSelect().addValueChangeListener(event -> 
    {
        if(event.getValue() == null)
        {
            removeComponent(contactForm); //quick and dirty workaround
        }
        else
        {
            addComponent(contactForm); //quick and dirty workaround
            /* contactForm.setVisible(true); messes up the entire view */
            contactForm.setClient(event.getValue());
        }
    });
}

@Override
public void enter(ViewChangeEvent event) {
}

private class ContactForm extends FormLayout
{
    private Client client;
    private Button save, delete, cancel;
    private TextField firstName, lastName, email, address, phoneNumber;
    private Binder<Client> binder = new Binder<>(Client.class);
    public ContactForm()
    {
        initConf();
        initLayout();
        setSizeUndefined();
        binder.bindInstanceFields(this);
    }

    public void initConf() 
    {
        save = new Button("Save");
        cancel = new Button("Cancel");

        firstName = new TextField();
        firstName.setPlaceholder("First Name");

        lastName = new TextField();
        lastName.setPlaceholder("Last Name");

        email = new TextField();
        email.setPlaceholder("Email Address");

        address = new TextField();
        address.setPlaceholder("Address");

        phoneNumber = new TextField();
        phoneNumber.setPlaceholder("Phone Number");

    }
    public void initLayout() 
    {
        HorizontalLayout actions = new HorizontalLayout(save, cancel);
        actions.setSpacing(true);

        addComponents(actions, firstName, lastName, email, address, phoneNumber);
    }

    public void setClient(Client client)
    {
        //setVisible(true);
        this.client = client;
        binder.setBean(client);
    }
  }
}

На первом изображении показано, как представление реагирует на добавление формы в макет и установку скрытого состояния.

Второе и третье изображения показывают, как представление ДОЛЖНО реагировать. Хотя для достижения желаемых результатов мне пришлось заняться неаккуратным кодированием.

Наконец вопрос:

Как я могу решить эту проблему? Я попытался использовать внутренний класс для формы и создать его как собственный класс. Мое единственное предположение заключается в том, что в реализациях github они передают пользовательский интерфейс в эту форму, где адресная книга расширяет пользовательский интерфейс, а не является компонентом.

Вот как выглядит вид при попытке добавить компонент напрямую

Вот как это выглядит при использовании быстрого и грязного исправления (путем добавления и удаления компонента по мере необходимости), форма не должна отображаться здесь

И это после нажатия на сетку, вот как я хочу, чтобы она функционировала


person mlizbeth    schedule 10.07.2017    source источник
comment
какое условие делает его непокрытым?   -  person efekctive    schedule 10.07.2017
comment
contactList.asSingleSelect.addValueChangeListener(event -›) оттуда, если данные события != null, он вызывает setClient(клиентский клиент), который затем будет иметь setVisible(true), но если я сделаю это таким образом, форма никогда не появится. Он появляется только в том случае, если я добавляю компонент в макет, но тогда это портит сетку.   -  person mlizbeth    schedule 10.07.2017
comment
Итак, поведение: отображается сетка, затем выберите одну строку, затем отобразите форму с данными справа?   -  person efekctive    schedule 10.07.2017
comment
Что-то мешает расчету размера со всеми этими setSizeFull() и expandRatios, скрывая форму. Попробуйте изменить на left.setSizeUndefined() и mainLayout.setSizeUndefined() и вернуться к скрытию/отображению формы. P.S. Я не думаю, что вам нужен mainLayout, так как ваше представление само по себе является HorizontalLayout; просто сделай addComponents(left, contactForm)   -  person Morfic    schedule 10.07.2017
comment
Вы пытались просто добавить виджеты справа по ходу? И предыдущий комментарий по делу: это кажется запутанной установкой.   -  person efekctive    schedule 10.07.2017
comment
Спасибо @Morfic, это была проблема!   -  person mlizbeth    schedule 10.07.2017
comment
Да, я не совсем понимаю, как все это рассчитывается в вашей выборке, и я не хочу тратить больше времени на расследование, поэтому, если кто-то знает что-то достаточно любезное, чтобы предоставить подробности, я с радостью поблагодарю их. Между тем, я добавлю ответ с тем, что я нашел до сих пор.   -  person Morfic    schedule 10.07.2017


Ответы (1)


Что происходит, так это то, что комбинация, которую вы имеете, покидая свое представление (которое представляет собой горизонтальный макет) с неопределенным размером и установкой размеров на полный плюс скрытие формы, имеет странный результат. Таким образом, если вы проверите полученные элементы с помощью некоторых инструментов разработчика, вы увидите, что ваше представление (горизонтальное расположение) будет иметь высоту 147 пикселей, а оболочка таблицы сетки будет иметь высоту 24 пикселя:

grid-table-wrapper-size

Если бы вы установили высоту просмотра на 100%, то она расширилась бы, чтобы занять все доступное пространство, что, вероятно, не то, что вам нужно:

все в полном размере

Итак, просто оставьте размер left неопределенным и потеряйте mainLayout (ваш вид уже расширяет HorizontalLayout, поэтому просто используйте его) и вернитесь к использованию contactForm.setVisible(true/false). Таким образом, макет left будет расширяться, чтобы вместить любой размер, рассчитанный для панели действий + сетки:

private void buildLayout() {
    HorizontalLayout actionBar = new HorizontalLayout(filter, addContact);
    actionBar.setWidth("100%");
    filter.setWidth("100%");
    actionBar.setExpandRatio(filter, 1);

    VerticalLayout left = new VerticalLayout(actionBar, contactList);
    left.setSizeFull();
    left.setExpandRatio(contactList, 1);

    addComponents(left, contactForm);
    contactForm.setVisible(false);
}

скрытие-показ-макет-формы


P.S. Если кто-то может улучшить этот ответ, предоставив больше информации о том, как размеры рассчитываются в этом случае, пожалуйста, отредактируйте этот ответ!

person Morfic    schedule 10.07.2017