Vaadin Web应用开发教程(23):UI组件-Form组件

jerry VaadinWeb 2015年11月25日 收藏

大部分的Web应用都包含窗体(Form),Vaadin中的Form组件提供了创建窗体的简洁方法。窗体中的填充域可以直接由绑定的数据源自动生成。BeamItem 适配器(Adapter)支持使用Java Bean对象或是普通的Java 对象做为数据源。 Form组件支持窗体数据的缓存从而只需在填写Form完成后一次性提交。
Form 组件从Layout 派生,可以有边框,标题,描述以及错误提示标识。
和大部分UI组件不同的是,Form构造函数不支持传入窗体标题参数,因为From经常不需要显示标题。你可以使用setCaption 为窗体添加标题。setDescription 可以为窗体添加帮助提示。Form组件缺省使用FormLayout 布局,但你可以使用setLayout 为Form组件设置其它Layout对象。
Form组件可以包含其它UI组件,你可以直接创建UI组件如何添加到Form组件的Layout对象中,但更好的方法是使用数据绑定。
下面代码显示两种方法为Form添加其它UI输入组件,如何添加到窗体中:

Form form = new Form();
form.setCaption("Form Caption");
form.setDescription("This is a description of the Form that is " +
"displayed in the upper part of the form. You normally " +
"enter some descriptive text about the form and its " +
"use here.");

// Add a field directly to the layout. This field will
// not be bound to the data source Item of the form.
form.getLayout().addComponent(new TextField("A Field"));

// Add a field and bind it to an named item property.
form.addField("another", new TextField("Another Field"));

Form组件可以显示输入错误标识,它可以显示下面几种错误类型:

  • 由setComponentError 设置的错误内容。
  • 由addValidator 添加到窗体的Validator 生成的错误。
  • 由窗体中UI域所关联的Validator引起的错误。此时setValidatorVisible(true)
  • 当setRequired(true) 和setRequiredError 同时设置时未填写某个必需内容时引发的校验错误。

    但Form组件同时只能显示单个错误。
    此外Form组件还定义了页脚区域(footer),footer 缺省使用HorizontalLayout布局。但也可以使用setFooter 来修改缺省布局。

// Set the footer layout.
form.setFooter(new VerticalLayout());

form.getFooter().addComponent(
new Label("This is the footer area of the Form. "+
"You can use any layout here. "+
"This is nice for buttons."));

// Have a button bar in the footer.
HorizontalLayout okbar = new HorizontalLayout();
okbar.setHeight("25px");
form.getFooter().addComponent(okbar);

// Add an Ok (commit), Reset (discard), and Cancel buttons
// for the form.
Button okbutton = new Button("OK", form, "commit");
okbar.addComponent(okbutton);
okbar.setComponentAlignment(okbutton, Alignment.TOP_RIGHT);
okbar.addComponent(new Button("Reset", form, "discard"));
okbar.addComponent(new Button("Cancel"));

上面介绍了Form组件的基本用法,接着介绍Form组件如何利用数据绑定来自动创建UI填充域。
数据绑定使用的数据源可以为任何实现Item 接口的Java对象。你可以自行实现Item接口或是使用BeamItem Adapter将Form组件绑定到任意的JavaBean对象。 也可以使用PropertysetItem 将Form组件绑定到一个Propert 对象集合。
下面代码定义了个简单的Java Bean对象-PersonBean.

/** A simple JavaBean. */
public class PersonBean {
String name;
String city;

public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setCity(String city) {
this.city = city;
}

public String getCity() {
return city;
}
}

如何使用BeanItem 适配器将一个PersonBean对象绑定到Form 组件。

// Create a form and use FormLayout as its layout.
final Form form = new Form();

// Set form caption and description texts
form.setCaption("Contact Information");
form.setDescription("Please specify name of the person and the city where the person lives in.");

// Create the custom bean.
PersonBean bean = new PersonBean();

// Create a bean item that is bound to the bean.
BeanItem item = new BeanItem(bean);

// Bind the bean item as the data source for the form.
form.setItemDataSource(item);

绑定数据源后,Form组件使用FormLayout,并为Java Bean的每个属性自动创建对应的UI组件(如文本框)。如下图所示:

这种自动创建的UI域的顺序可以不是我们所希望的,这时可以使用setVisibleItemPropertyies 来修改UI域的显示顺序,比如:

// Set the order of the items in the form.
Vector order = new Vector();
order.add("city");
order.add("name");
form.setVisibleItemProperties(order);

这种自动创建的UI组件的标题缺省使用JavaBean对应的属性名称,你可以使用FieldFactory 来修改缺省标题。
自动创建的UI域具有一定的局限性,比如String, int 或double 类型的属性会自动对应到TextField 组件。而此时你可以希望使用Combo组件来输入城市名称。 FormFieldFactory接口用来解决这些局限。
FieldFactory 的缺省实现DefaultFieldFactory 也用于Table组件。 通常可以通过派生DefaultFieldFactory 的方法来定制FieldFactory。
下面为FormFieldFactory接口的一个简单实现,为city 使用一个Select 组件。

class MyFieldFactory implements FormFieldFactory {
public Field createField(Item item, Object propertyId,
Component uiContext) {
// Identify the fields by their Property ID.
String pid = (String) propertyId;
if ("name".equals(pid)) {
return new TextField("Name");
} else if ("city".equals(pid)) {
Select select = new Select("City");
select.addItem("Berlin");
select.addItem("Helsinki");
select.addItem("London");
select.addItem("New York");
select.addItem("Turku");
select.setNewItemsAllowed(true);
return select;
}

return null; // Invalid field (property) name.
}
}

...

form.setFormFieldFactory(new MyFieldFactory());

此外使用Form组件的一个重要功能是验证用户输入,Vaadin再UI 域(Field)可以关联到validator来验证用户输入以保证输入合法。
Vaadin的validator 为实现了Validator 接口的类。 这个接口定义了两个方法,isValid 和validate.
Vaadin 内置了一些常用的验证类,如IntegerValidator, DoubleValidator, StringLengthValidator, EmailValidator以及RegexValidator 等。
Form校验发生在用户点击“提交”按钮时,当窗体中任何一个Validator失败时,窗体提交都会失败,并显示与之关联的错误标识。如果提交成功,输入数据则写到数据源中。
比如下面代码要求邮编满足给定格式。

// Postal code that must be 5 digits (10000-99999).
TextField field = new TextField("Postal Code");
field.setColumns(5);

// Create the validator
Validator postalCodeValidator = new RegexpValidator(
"[1-9][0-9]{4}", "Postal code must be a number 10000-99999.");
field.addValidator(postalCodeValidator);

如果输入错误则窗体显示错误提示:

如果需要指定窗体中某些域是必需填写的,可以使用setRequired(true),并使用setRequiredError设置错误信息在用户没有填写必填输入内容时显示。

form.getField("name").setRequired(true);
form.getField("name").setRequiredError("Name is missing");
form.getField("address").setRequired(true); // No error message

最后提一下Form组件的缓存功能,可以只在用户点击?提交“按钮后才将用户输入数据写回数据源。其实Vaadin的所有Field组件都支持缓存功能。而Form的commit ,discard 实际上是调用对应的Field组件的相关功能。当调用discard 后,将失去之前用户所有修改,UI输入域恢复到数据源的初始内容。

final Form form = new Form();
...add components...

// Enable buffering.
form.setWriteThrough(false);

// The Ok button calls form.commit().
Button commit = new Button("Ok", form, "commit");

// The Restore button calls form.discard().
Button restore = new Button("Restore", form, "discard");