大部分的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组件可以显示输入错误标识,它可以显示下面几种错误类型:
但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");