在 ComboBox 上添加新元素

Adding new elements on ComboBox

我正在开发一个 Vaadin 应用程序,我决定使用 SuggestingComboBox 想法,它可以更好地在项目之间进行搜索。这很好用,但现在我不知道如何使用 setNewItemHandler 方法添加容器中尚未存在的新元素。
作为参考,这里是 SuggestingComBox 代码:

public class SuggestingComboBox extends ComboBox {

    public SuggestingComboBox() {
        setItemCaptionMode(ItemCaptionMode.PROPERTY);
        setItemCaptionPropertyId("name");
    }

    @Override
    protected Filter buildFilter(String filterString, 
            FilteringMode filteringMode) {
        return new SuggestingContainer.SuggestionFilter(filterString);
    }
}

组合框附带的 SuggestingContainer 代码:

public abstract class SuggestingContainer<T> extends BeanItemContainer<T> {

    public SuggestingContainer(Class<? super T> type)
            throws IllegalArgumentException {
        super(type);
    }

    @Override
    protected void addFilter(Filter filter) 
            throws UnsupportedFilterException {
        if(filter instanceof SuggestionFilter) {
            SuggestionFilter suggestionFilter = (SuggestionFilter) filter;
            filterItems(suggestionFilter.getFilterString());
        } else 
            super.addFilter(filter);
    }

    //This method is to be overriden
    protected abstract void filterItems(String filterString);

   public static class SuggestionFilter implements Container.Filter {
       private String filterString;

       public SuggestionFilter(String filterString) {
           this.filterString = filterString;
       }

       public String getFilterString() {
           return filterString;
       }

       @Override
       public boolean passesFilter(Object itemId, Item item) 
               throws UnsupportedOperationException {
           return false;
       }

       @Override
       public boolean appliesToProperty(Object propertyId) {
           return false;
       }
  }

这个容器是这样使用的:

public SuggestingField extends CustomField<Model> {
    private SuggestingComboBox suggestingCB;
    private SuggestingContainer<ObjectItem> container;

    public SuggestingField() {
        suggestingCB = new SuggestingComboBox();
        container = new SuggestingContainer<ObjectItem>(ObjectItem.class) {
            @Override
            protected void filterItems(String filterString) {               
                removeAllItems();

                List<Model> result; //Obtain here the results
                List<ObjectItem> lItems = result.stream()
                        .map(m -> new ObjectItem(m.getId()+"", m.toString(), m))
                        .collect(Collectors.toList());
                addAll(lItems);
            }
        };
        suggestingCB.setContainerDataSource(container);
        suggestingCB.setImmediate(true);
        suggestingCB.setItemCaptionPropertyId("text");
    }
}

此外,我有一个 POJO ModelObjectItem class,我必须使用它,因为我无法使用 toString 标题模式。

public class Model {
    private int id;
    private String name;
    //Getters and setters; equals/hash
}
public class ObjectItem {
    private String id;
    private String text;
    private Object o;
    //Equals/hash and getters/setters
}

所以,我的问题是:我试图允许使用 setNewItemHandler 方法在字段中创建新的 Model(s)。这是我到目前为止尝试过的。

public SuggestingField extends CustomField<Model> {
...
    public void setNewElementsAllowed(boolean allowed) {
        this.suggestingCB.setNewItemsAllowed(allowed);
        this.suggestingCB.setImmediate(allowed);
        if(allowed) {
            suggestingCB.setNewItemHandler(caption -> {
                Model m = new Model();
                m.setNombre(caption);

                setValue(m);
            });
        }
    }
    public void setValue(Model m) {
        super.setValue(m);
        if(m == null)
            suggestingCB.setValue(null);
        else {
            ObjectItem it = new ObjectItem(""+m.getId(),
                m.getName(), m);
            if(container.size() == 0 || !container.containsId(it.getId()))
                container.addItem(it);

            suggestingCB.setValue(it);
            suggestingCB.select(it);
        }
    }

在调试这段代码后,我发现使用了 newElementHandler,它向容器中添加了一个新项目,但是在 ComboBox 和下一个处理程序的执行中没有显示任何内容,容器是空的,好像没有插入任何项目。

我已经能够识别错误。当您 select ComboBox 中的一项时,filterString 变为 "",因此,如果您 select 数据库中不存在的内容,请回想一下查询,它不会在 List<Model> result 中,因此,它将未被 select 编辑。
克服这个问题的一种方法是修改 SuggestingField,如下所示:

public SuggestingField extends CustomField<Model> {
    private Model model;
    ...
    public SuggestingField() {
        ...
        container = new SuggestingContainer<ObjectItem>(ObjectItem.class) {
            @Override
            protected void filterItems(String filterString) {               
                removeAllItems();

                if("".equals(filterString)) {
                    if(model != null) {
                        ObjectItem it = new ObjectItem();
                        it.setId(model.getId()+"");
                        it.setText(model.toString());
                        it.setObject(model);

                        addItem(it);
                        return;
                    }
                }

                List<Model> result; //Obtain here the results
                List<ObjectItem> lItems = result.stream()
                    .map(m -> new ObjectItem(m.getId()+"", m.toString(), m))
                    .collect(Collectors.toList());
                addAll(lItems);
            }
        };
        suggestingCB.addValueChangeListener(ev -> {
            this.model = (Model) suggestingCB.getValue();
        });

这允许通过过滤器维护新项目。