Forms are often used to collect related pieces of information from a user. For example, an application that manages a user's music collection might provide a form that allows the user to enter such information as song title, artist, and album name, and a content management system might provide a form that allows a user to specify the title, author, and publication date of an article.
Form contents are commonly organized into sections, to make it easier for the user to read. A contact management application might use a form such as the one shown below to collect information about the user's contacts. The form is divided into four sections, one for each aspect of the contact record: name, addresses, phone numbers, and email addresses. Note the use of the <Form.Section> elements to define the sections; the Form's skin automatically inserts separators to visually partition the section content and uses the Form.Section heading as the Separator heading:
The BXML for this example is shown below:
<layout:Forms title="Forms" maximized="true" xmlns:bxml="http://pivot.apache.org/bxml" xmlns:layout="org.apache.pivot.tutorials.layout" xmlns="org.apache.pivot.wtk"> <Border styles="{padding:6}"> <TablePane> <columns> <TablePane.Column width="1*"/> </columns> <TablePane.Row height="1*"> <Form> <Form.Section> <BoxPane bxml:id="nameBoxPane" Form.label="Name"> <TextInput bxml:id="lastNameTextInput" prompt="Last"/> <TextInput bxml:id="firstNameTextInput" prompt="First"/> </BoxPane> </Form.Section> <Form.Section heading="Addresses"> <BoxPane Form.label="Home" orientation="vertical"> <TextInput prompt="Street" textSize="24"/> <BoxPane> <TextInput prompt="City"/> <TextInput prompt="State" textSize="6"/> <TextInput prompt="Zip" textSize="10"/> </BoxPane> </BoxPane> <BoxPane Form.label="Work" orientation="vertical"> <TextInput prompt="Street" textSize="24"/> <BoxPane> <TextInput prompt="City"/> <TextInput prompt="State" textSize="6"/> <TextInput prompt="Zip" textSize="10"/> </BoxPane> </BoxPane> </Form.Section> <Form.Section heading="Phone Numbers"> <TextInput Form.label="Home"/> <TextInput Form.label="Work"/> </Form.Section> <Form.Section heading="Email Addresses"> <TextInput Form.label="Home"/> <TextInput Form.label="Work"/> </Form.Section> </Form> </TablePane.Row> <TablePane.Row height="-1"> <Separator/> </TablePane.Row> <TablePane.Row height="-1"> <TablePane> <columns> <TablePane.Column width="1*"/> <TablePane.Column width="-1"/> </columns> <TablePane.Row> <BoxPane styles="{verticalAlignment:'center'}"> <Label bxml:id="errorLabel" styles="{color:22}"/> </BoxPane> <BoxPane styles="{horizontalAlignment:'right', verticalAlignment:'center'}"> <PushButton bxml:id="submitButton" buttonData="Submit" styles="{minimumAspectRatio:3}"/> </BoxPane> </TablePane.Row> </TablePane> </TablePane.Row> </TablePane> </Border> </layout:Forms>
Also note the use of the Form.label attribute - this is an example of an "attached property", also called an "attribute" in WTK. An attribute is a property that can be specified on a component only when it is a child of the container that defines the property. The same result can be achieved programmatically by calling the static Form.setName() method on a component after it has been added to the form. Several other containers, including TabPane and TablePane, define similar attributes.
Note also that section components are not required to be typical form elements such as TextInput or PushButton. They can also be containers, allowing the arrangement of components within a section to be customized.
Form Validation
Pressing the "Submit" button performs some simple validation on the name fields, ensuring that the user has provided some text in each field. If either field is empty, an error message is displayed at the bottom of the form, and the row containing the text fields is highlighted with a red flag. This demonstrates the use of another Form attribute: the flag. A flag is an instance of Form.Flag that allows a user to tag a form element as requiring attention from the user. It is a simple class that contains a message type (error, warning, info, etc.) and a message. Mousing over the flag displays a tooltip containing the message.
The button press handler in the code sample below shows how a flag is set on the name fields:
package org.apache.pivot.tutorials.layout; import java.net.URL; import org.apache.pivot.beans.Bindable; import org.apache.pivot.collections.Map; import org.apache.pivot.util.Resources; import org.apache.pivot.wtk.Button; import org.apache.pivot.wtk.ButtonPressListener; import org.apache.pivot.wtk.BoxPane; import org.apache.pivot.wtk.Form; import org.apache.pivot.wtk.Label; import org.apache.pivot.wtk.MessageType; import org.apache.pivot.wtk.Prompt; import org.apache.pivot.wtk.PushButton; import org.apache.pivot.wtk.TextInput; import org.apache.pivot.wtk.Window; public class Forms extends Window implements Bindable { private BoxPane nameBoxPane = null; private TextInput lastNameTextInput = null; private TextInput firstNameTextInput = null; private PushButton submitButton = null; private Label errorLabel = null; @Override public void initialize(Map<String, Object> namespace, URL location, Resources resources) { nameBoxPane = (BoxPane)namespace.get("nameBoxPane"); lastNameTextInput = (TextInput)namespace.get("lastNameTextInput"); firstNameTextInput = (TextInput)namespace.get("firstNameTextInput"); submitButton = (PushButton)namespace.get("submitButton"); errorLabel = (Label)namespace.get("errorLabel"); submitButton.getButtonPressListeners().add(new ButtonPressListener() { @Override public void buttonPressed(Button button) { String lastName = lastNameTextInput.getText(); String firstName = firstNameTextInput.getText(); Form.Flag flag = null; if (lastName.length() == 0 || firstName.length() == 0) { flag = new Form.Flag(MessageType.ERROR, "Name is required."); } Form.setFlag(nameBoxPane, flag); if (flag == null) { errorLabel.setText(""); Prompt.prompt("Pretending to submit...", Forms.this); } else { errorLabel.setText("Some required information is missing."); } } }); } }
Next: Panels