2

简而言之: 在编辑模式下,我的表格的每个字段中的组合框在选择项目时给了我一个转换错误,但是相同的逻辑和容器在 TableFieldFactory (createField())之外工作得很好。我究竟做错了什么?

更长的解释: 我有一个包含多个属性(列)和项目(行)的容器。当我编辑连接到此容器的表时,我希望某些列字段上有组合框。我为此使用了 TableFieldFactory,它的工作原理就像一个魅力。

我希望每个字段中的组合框包含来自其各自属性的不同元素。我对此的解决方案是在我的 Container 类中实现一个方法,该方法遍历容器中的所有属性,并为每个属性创建一个新的 IndexedContainer,该属性具有唯一值。该方法返回一个带有 PropertyIds/Containers 的映射,因此我可以在 createField() 中从我想要为其设置组合框的每个属性中选择每个容器。

例子

所以,假设我有三个 propertyId,Foo,Bar 和 Baz,每个“包含”几个项目,其中一些项目是相同的,如下所示:

  • 克里斯
  • 克里斯
  • 梅格
  • 梅格
  • 梅格
  • 斯图维
  • 斯图维

...对于 Bar 和 Baz 也是如此,只有其他值...

getDistinctContainers() 方法返回一个Map,如下所示:

Key: PropertyId: Foo
Value: Container: contains propertyId [Foo] and the unique values of Foo, ie. [Chris, Meg, Stewie]
Key: PropertyId: Bar
Value: ... and so forth...

当我要在 createField() 中设置容器数据源时,容器看起来像这样(对于属性 Foo):

allItemIds: [0, 1, 2]
items: {2={Foo=Stewie}, 1={Foo=Meg}, 0={Foo=Chris}}
propertyIds: [Foo]

……我觉得还可以……

现在,该表按预期显示了每个字段中的组合框。但是当我单击组合框中的一个项目时,它会给我以下转换错误:

 com.vaadin.data.util.converter.Converter$ConversionException: Unable to convert value of type java.lang.Integer to model type class java.lang.String. No converter is set and the types are not compatible.
    at com.vaadin.data.util.converter.ConverterUtil.convertToModel(ConverterUtil.java:181)
    at com.vaadin.ui.AbstractField.convertToModel(AbstractField.java:745)

笔记:

我尝试在表格之外创建相同的场景,并且效果很好。因此,具有相同逻辑和相同容器的组合框似乎可以在 TableFieldFactory 和 createFields() 方法之外正常工作。我无法解释为什么他们不应该在 TableFieldFactory 中工作......

问题:

  • 我该怎么做才能让组合框设置正确的值?

这是我的容器类:

public class SomeContainer extends IndexedContainer {

    private static final long serialVersionUID = 1L;

    public void addContainerProperties() {
        addContainerProperty("Foo", String.class, null);
        addContainerProperty("Bar", String.class, null);
        addContainerProperty("Baz", String.class, null);
    }

    public Map<String, Container> getDistinctContainers() {

        Map<String, Container> m = new HashMap<String, Container>();
        ArrayList<Object> filter = new ArrayList<Object>();

        int id = 0;

        for (Object propertyId : this.getContainerPropertyIds()) {

            Container cont = new IndexedContainer();

            cont.addContainerProperty(propertyId, propertyId.getClass(), null);

            for (Object itemId : this.getItemIds()) {
                Object ob = ((Item) this.getItem(itemId)).getItemProperty(propertyId).getValue();
                if ((!filter.contains(ob.toString())) && (ob != null)) {
                    filter.add(ob.toString());
                    Item item = cont.addItem(id);
                    item.getItemProperty(propertyId).setValue(ob);
                    id++;
                }
            }
            m.put(propertyId.toString(), cont);
        }
        return m;
    }
}

...这是createField的相关代码:

@Override
public Field<?> createField(Container container, Object itemId, Object propertyId, com.vaadin.ui.Component uiContext) {

    TextField tField = (TextField) DefaultFieldFactory.get().createField(container, itemId, propertyId, uiContext);
    tField.setImmediate(true);

    // ...some code here that uses the TextField

    if (propertyId.equals("Foo")) {
        ComboBox select = new ComboBox();
        for (Map.Entry<String, Container> entry : distinctContainers.entrySet()) {
            if (entry.getKey().equals(propertyId)) {
                select.setContainerDataSource(entry.getValue());
            }
        }
        select.setImmediate(true);
        select.setItemCaptionPropertyId(propertyId);
        select.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);

        return select;
    }
    // ...  if statements for Bar and Baz left out for brevity...

    return tField;
}

请帮助我了解我所缺少的!

提前致谢!

4

1 回答 1

1

从上面的异常和代码片段我们可以看出,需要在Integer(表示类型)和String(模型)之间进行转换。在这种特殊情况下:

  • 演示类型:ItemId = {0,1,2}
  • 模型:PropertyId 的值 = {“Chris”、“Meg”、“Stewie”}

由于 Vaadin 没有内置的 IntegerToStringConverter,因此您需要一个自定义转换器:

...
select.setContainerDataSource(entry.getValue());
select.setConverter(new Converter<Object, String>() {

    @Override
    public String convertToModel(Object itemId, Class<? extends String> paramClass, Locale paramLocale) throws ConversionException {
        if (itemId != null) {
            IndexedContainer c = (IndexedContainer) entry.getValue();
            Object propertyId = c.getContainerPropertyIds().iterator().next();
            Object name = c.getItem(itemId).getItemProperty(propertyId).getValue();
            return (String) name;
        }
        return null;
    }

    @Override
    public Object convertToPresentation(String value, Class<? extends Object> paramClass, Locale paramLocale) throws ConversionException {
        if (value != null) {
            IndexedContainer c = (IndexedContainer) entry.getValue();
            Object propertyId = c.getContainerPropertyIds().iterator().next();
            for (Object itemId : container.getItemIds()) {
                Object name = c.getContainerProperty(itemId, propertyId).getValue();
                if (value.equals(name)) {
                    return itemId;
                }
            }
        }
        return null;
    }

    @Override
    public Class<String> getModelType() {
        return String.class;
    }

    @Override
    public Class<Object> getPresentationType() {
        return Object.class;
    }
});

请注意,不能使用显式 Integer<-->String 转换

select.setConverter(new Converter<Integer, String>());

因为编译器拒绝它。问题已在此处描述。


有关 Vaadin 转换器的更多信息,请参见:
Book of Vaadin,第 9.2.3 章:在属性类型和表示之间
进行转换 更改应用程序的默认转换器
创建您自己的字符串转换器 - MyType 转换

我希望它有所帮助。

于 2013-09-19T12:11:52.377 回答