有没有办法在可编辑的 Vaadin 8 网格中设置验证和编辑长值

Is there a way to set a validation and edit a long value in an editable Vaadin 8 Grid

我有一个 Vaadin 8 网格,我想在其中将一列设置为可编辑。为此,我有 Food.calories 是 long 的地方(是的,在这种情况下它可能是 int 但请记住,这是一个示例,我的特定用例需要 long):

Binder<Food> binder = foodGrid.getEditor().getBinder();
TextField caloriesTextField = new TextField();
binder.forField(caloriesTextField)
        .withValidator(CustomCaloryValidator::isValidValue, "Must be valid a positive amount")
        .withConverter(new StringToCaloriesConverter("Must be an integer"))
        .bind(Food::getCalories, Food::setCalories);

// This line fails with the error because the types do not match.
foodGrid.addColumn(Food::getCalories, new NumberRenderer(myNumberFormat))
        .setEditorComponent(new TextField(), Food::setCalories);

不幸的是,这不起作用并出现以下错误:

类型参数 'C' 的推断类型 'C' 不在其范围内;应该实施 'com.vaadin.data.HasValue'

我到处寻找,但除了简单的编辑之外,找不到任何例子。 demo sampler 确实有一个使用滑块的更复杂的示例,但我不知道如何从该示例中推断...

我明白这个错误,它正在尝试将 long 映射到 String。但是我找不到向 addColumn 添加转换器以使其工作的方法...

首先主要问题是Binder没有指定泛型类型,需要是:

Binder<Food> binder = foodGrid.getEditor().getBinder();

而不是:

Binder binder = foodGrid.getEditor().getBinder();

也就是说还有其他几个问题。首先,当您执行 forField() 时,您需要跟踪该绑定,以便稍后使用该列进行设置。这对我来说一点都不清楚。具体来说,您需要:

Binder.Binding<Food, Long> caloriesBinder = binder.forField(caloriesTextField)
        .withValidator(CustomCaloryValidator::isValidValue, "Must be valid a positive amount")
        .withConverter(new StringToCaloriesConverter("Must be an integer"))
        .bind(Food::getCalories, Food::setCalories);

我不是 100% 确定 caloriesBinder,因为我的代码不同,这是一个示例,但您需要该绑定。然后你接受那个绑定并做:

foodGrid.getColumn("calories").setEditorBinding(caloriesBinding);

这允许正确的编辑器工作。这在文档中,但示例非常简单,所以我错过了。

下一步非常重要,具体取决于您要显示的内容,即添加渲染器,否则您可能 运行 遇到一些奇怪的问题。例如,如果您使用 long 来存储货币,那么您需要将其转换为显示货币金额。同样,如果您使用的是日期,那么您可能还想对其进行格式化。然后你需要添加一个渲染器。我能找到没有编译错误(类型不匹配)的唯一方法是:

((Grid.Column<Food, Long>)foodGrid.getColumn("calories")).setRenderer(new CaloriesRenderer());

为了完整起见,您需要启用编辑器:

foodGrid.getEditor().setEnabled(true);

最后,如果 table 是更大 bean 的一部分,那么您需要调用 foodGrid.setItems(),您不能只依赖 binder.readBean(),因为它不能接受列表。因此,例如,如果豆子不是食物而是包含多种成分的一餐,那么你不能做 binder.readBean(meal) 也不能做 binder.readBean(meal.getIngredients) 即使你可以做 binder.readBean(meal)表格的其余部分。我能让它工作的唯一方法是:

binder.readBean(meal);
foodGrid.setItems(meal.getIngredients);