注意:form对象不是线程安全的,不能被多线程共享。
@author Michael Zhou* * Title * * * * ContentPane * * * * MenuBar *@author Chen Fishbein
Form
is a container for fields implementing {@link Field}interface. It provides support for any layouts and provides buffering interface for easy connection of commit and discard buttons. All the form fields can be customized by adding validators, setting captions and icons, setting immediateness, etc. Also direct mechanism for replacing existing fields with selections is given.
Form
provides customizable editor for classes implementing {@link com.vaadin.data.Item} interface. Also the form itself implements thisinterface for easier connectivity to other items. To use the form as editor for an item, just connect the item to form with {@link Form#setItemDataSource(Item)}. If only a part of the item needs to be edited, {@link Form#setItemDataSource(Item,Collection)} can be used instead.After the item has been connected to the form, the automatically created fields can be customized and new fields can be added. If you need to connect a class that does not implement {@link com.vaadin.data.Item} interface, mostproperties of any class following bean pattern, can be accessed trough {@link com.vaadin.data.util.BeanItem}.
FORM@author stefano.bertini[at]gmail.com
Form
is a Screen
that contains an arbitrary mixture of items: images, read-only text fields, editable text fields, editable date fields, gauges, choice groups, and custom items. In general, any subclass of the {@link Item Item} class may be contained within a form.The implementation handles layout, traversal, and scrolling. The entire contents of the Form
scrolls together. The items contained within a Form
may be edited using append, delete, insert, and set methods. Items
within a Form
are referred to by their indexes, which are consecutive integers in the range from zero to size()-1
, with zero referring to the first item and size()-1
to the last item.
An item may be placed within at most one Form
. If the application attempts to place an item into a Form
, and the item is already owned by this or another Form
, an IllegalStateException
is thrown. The application must remove the item from its currently containing Form
before inserting it into the new Form
.
If the Form
is visible on the display when changes to its contents are requested by the application, updates to the display take place as soon as it is feasible for the implementation to do so. Applications need not take any special action to refresh a Form's
display after its contents have been modified.
Layout policy in Form
is organized around rows. Rows are typically related to the width of the screen, respective of margins, scroll bars, and such. All rows in a particular Form
will have the same width. Rows do not vary in width based on the Items
contained within the Form
, although they may all change width in certain circumstances, such as when a scroll bar needs to be added or removed. Forms
generally do not scroll horizontally.
Forms
grow vertically and scroll vertically as necessary. The height of a Form
varies depending upon the number of rows and the height of each row. The height of each row is determined by the items that are positioned on that row. Rows need not all have the same height. Implementations may also vary row heights to provide proper padding or vertical alignment of Item
labels.
An implementation may choose to lay out Items
in a left-to-right or right-to-left direction depending upon the language conventions in use. The same choice of layout direction must apply to all rows within a particular Form
.
Prior to the start of the layout algorithm, the Form
is considered to have one empty row at the top. The layout algorithm considers each Item in turn, starting at Item
zero and proceeding in order through each Item
until the last Item
in the Form
has been processed. If the layout direction (as described above) is left-to-right, the beginning of the row is the left edge of the Form
. If the layout direction is right-to-left, the beginning of the row is the right edge of the Form
. Items
are laid out at the beginning of each row, proceeding across each row in the chosen layout direction, packing as many Items
onto each row as will fit, unless a condition occurs that causes the packing of a row to be terminated early. A new row is then added, and Items
are packed onto it as described above. Items
are packed onto rows, and new rows are added below existing rows as necessary until all Items
have been processed by the layout algorithm.
The layout algorithm has a concept of a current alignment. It can have the value LAYOUT_LEFT
, LAYOUT_CENTER
, or LAYOUT_RIGHT
. The value of the current alignment at the start of the layout algorithm depends upon the layout direction in effect for this Form
. If the layout direction is left-to-right, the initial alignment value must be LAYOUT_LEFT
. If the layout direction is right-to-left, the initial alignment value must be LAYOUT_RIGHT
. The current alignment changes when the layout algorithm encounters an Item
that has one of the layout directives LAYOUT_LEFT
, LAYOUT_CENTER
, or LAYOUT_RIGHT
. If none of these directives is present on an Item
, the current layout directive does not change. This rule has the effect of grouping the contents of the Form
into sequences of consecutive Items
sharing an alignment value. The alignment value of each Item
is maintained internally to the Form
and does not affect the Items'
layout value as reported by the {@link Item#getLayout Item.getLayout} method.
The layout algorithm generally attempts to place an item on the same row as the previous item, unless certain conditions occur that cause a "row break." When there is a row break, the current item will be placed at the beginning of a new row instead of being placed after the previous item, even if there is room.
A row break occurs before an item if any of the following conditions occurs:
LAYOUT_NEWLINE_BEFORE
directive; orStringItem
whose contents starts with "\n";ChoiceGroup
, DateField
, Gauge
, or a TextField
, and the LAYOUT_2
directive is not set; orItem
has a LAYOUT_LEFT
, LAYOUT_CENTER
, or LAYOUT_RIGHT
directive that differs from the Form's
current alignment.A row break occurs after an item if any of the following conditions occurs:
StringItem
whose contents ends with "\n"; orLAYOUT_NEWLINE_AFTER
directive; orChoiceGroup
, DateField
, Gauge
, or a TextField
, and the LAYOUT_2
directive is not set.The presence of the LAYOUT_NEWLINE_BEFORE
or LAYOUT_NEWLINE_AFTER
directive does not cause an additional row break if there is one already present. For example, if a LAYOUT_NEWLINE_BEFORE
directive appears on a StringItem
whose contents starts with "\n", there is only a single row break. A similar rule applies with a trailing "\n" and LAYOUT_NEWLINE_AFTER
. Also, there is only a single row break if an item has the LAYOUT_NEWLINE_AFTER
directive and the next item has the LAYOUT_NEWLINE_BEFORE
directive. However, the presence of consecutive "\n" characters, either within a single StringItem
or in adjacent StringItems
, will cause as many row breaks as there are "\n" characters. This will cause empty rows to be present. The height of an empty row is determined by the prevailing font height of the StringItem
within which the "\n" that ends the row occurs.
Implementations may provide additional conditions under which a row break occurs. For example, an implementation's layout policy may lay out labels specially, implicitly causing a break before every Item
that has a label. Or, as another example, a particular implementation's user interface style may dictate that a DateField item always appears on a row by itself. In this case, this implementation may cause row breaks to occur both before and after every DateField
item.
Given two items with adjacent Form
indexes, if none of the specified or implementation-specific conditions for a row break between them occurs, and if space permits, these items should be placed on the same row.
When packing Items
onto a row, the width of the item is compared with the remaining space on the row. For this purpose, the width used is the Item's
preferred width, unless the Item
has the LAYOUT_SHRINK
directive, in which case the Item's
minimum width is used. If the Item
is too wide to fit in the space remaining on the row, the row is considered to be full, a new row is added beneath this one, and the Item
is laid out on this new row.
Once the contents of a row have been determined, the space available on the row is distributed by expanding items and by adding space between items. If any items on this row have the LAYOUT_SHRINK
directive (that is, they are shrinkable), space is first distributed to these items. Space is distributed to each of these items proportionally to the difference between the each Item's
preferred size and its minimum size. At this stage, no shrinkable item is expanded beyond its preferred width.
For example, consider a row that has 30
pixels of space available and that has two shrinkable items A
and B
. Item A's
preferred size is 15
and its minimum size is 10
. Item B's
preferred size is 30
and its minimum size is 20
. The difference between A's
preferred and minimum size is 5
, and B's
difference is 10
. The 30
pixels are distributed to these items proportionally to these differences. Therefore, 10
pixels are distributed to item A
and 20
pixels to item B
.
If after expanding all the shrinkable items to their preferred widths, there is still space left on the row, this remaining space is distributed equally among the Items that have the LAYOUT_EXPAND
directive (the stretchable Items
). The presence of any stretchable items on a row will cause the Items
on this row to occupy the full width of the row.
If there are no stretchable items on this row, and there is still space available on this row, the Items
are packed as tightly as possible and are placed on the row according to the alignment value shared by the Items
on this row. (Since changing the current alignment causes a row break, all Items
on the same row must share the same alignment value.) If the alignment value is LAYOUT_LEFT
, the Items
are positioned at the left end of the row and the remaining space is placed at the right end of the row. If the alignment value is LAYOUT_RIGHT
, the Items
are positioned at the right end of the row and the remaining space is placed at the left end of the row. If the alignment value is LAYOUT_CENTER
, the Items
are positioned in the middle of the row such that the remaining space on the row is divided evenly between the left and right ends of the row.
Given the set of items on a particular row, the heights of these Items
are inspected. For each Item
, the height that is used is the preferred height, unless the Item
has the LAYOUT_VSHRINK
directive, in which case the Item's
minimum height is used. The height of the tallest Item
determines the height of the row. Items
that have the LAYOUT_VSHRINK
directive are expanded to their preferred height or to the height of the row, whichever is smaller. Items
that are still shorter than the row height and that have the LAYOUT_VEXPAND
directive will expand to the height of the row. The LAYOUT_VEXPAND
directive on an item will never increase the height of a row.
Remaining Items
shorter than the row height will be positioned vertically within the row using the LAYOUT_TOP
, LAYOUT_BOTTOM
, and LAYOUT_VCENTER
directives. If no vertical layout directive is specified, the item must be aligned along the bottom of the row.
StringItems
are treated specially in the above algorithm. If the contents of a StringItem
(its string value, exclusive of its label) contain a newline character ("\n"), the string should be split at that point and the remainder laid out starting on the next row.
If one or both dimensions of the preferred size of a StringItem
have been locked, the StringItem
is wrapped to fit that width and height and is treated as a rectangle whose minimum and preferred width and height are the width and height of this rectangle. In this case, the LAYOUT_SHRINK
, LAYOUT_EXPAND
, and LAYOUT_VEXPAND
directives are ignored.
If both dimensions of the preferred size of a StringItem
are unlocked, the text from the StringItem
may be wrapped across multiple rows. At the point in the layout algorithm where the width of the Item
is compared to the remaining space on the row, as much text is taken from the beginning of the StringItem
as will fit onto the current row. The contents of this row are then positioned according to the current alignment value. The remainder of the text in the StringItem
is line-wrapped to the full width of as many new rows as are necessary to accommodate the text. Each full row is positioned according to the current alignment value. The last line of the text might leave space available on its row. If there is no row break following this StringItem
, subsequent Items
are packed into the remaining space and the contents of the row are positioned according to the current alignment value. This rule has the effect of displaying the contents of a StringItem
as a paragraph of text set flush-left, flush-right, or centered, depending upon whether the current alignment value is LAYOUT_LEFT
, LAYOUT_RIGHT
, or LAYOUT_CENTER
, respectively. The preferred width and height of a StringItem
wrapped across multiple rows, as reported by the {@link Item#getPreferredWidth Item.getPreferredWidth} and{@link Item#getPreferredHeight Item.getPreferredHeight}methods, describe the width and height of the bounding rectangle of the wrapped text.
ImageItems
are also treated specially by the above algorithm. The foregoing rules concerning the horizontal alignment value and the LAYOUT_LEFT
, LAYOUT_RIGHT
, and LAYOUT_CENTER
directives, apply to ImageItems
only when the LAYOUT_2
directive is also present on that item. If the LAYOUT_2
directive is not present on an ImageItem
, the behavior of the LAYOUT_LEFT
, LAYOUT_RIGHT
, and LAYOUT_CENTER
directives is implementation-specific.
A Form's
layout is recomputed automatically as necessary. This may occur because of a change in an Item's
size caused by a change in its contents or because of a request by the application to change the Item's preferred size. It may also occur if an Item's
layout directives are changed by the application. The application does not need to perform any specific action to cause the Form's
layout to be updated.
For all cases where text is wrapped, line breaks must occur at each newline character ('\n'
= Unicode 'U+000A'
). If space does not permit the full text to be displayed it is truncated at line breaks. If there are no suitable line breaks, it is recommended that implementations break text at word boundaries. If there are no word boundaries, it is recommended that implementations break text at character boundaries.
Labels that contain line breaks may be truncated at the line break and cause the rest of the label not to be shown.
When a Form
is present on the display the user can interact with it and its Items
indefinitely (for instance, traversing from Item
to Item
and possibly scrolling). These traversing and scrolling operations do not cause application-visible events. The system notifies the application when the user modifies the state of an interactive Item
contained within the Form
. This notification is accomplished by calling the {@link ItemStateListener#itemStateChanged itemStateChanged()}method of the listener declared to the Form
with the {@link #setItemStateListener setItemStateListener()} method.
As with other Displayable
objects, a Form
can declare {@link Command commands} and declare a command listener with the{@link Displayable#setCommandListener setCommandListener()} method.{@link CommandListener CommandListener}objects are distinct from {@link ItemStateListener ItemStateListener} objects, and they are declaredand invoked separately.
Form
is designed to contain a small number of closely related UI elements. @see Item @since MIDP 1.0
Copyright (c) Xoetrope Ltd., 2002-2006
$Revision: 1.2 $
License: see License.txt
// The customer.address.state field TextField stateField = new TextField("address.state"); form.add(stateField); .. // Loads the customer address state into the form stateField Customer customer = getCustomer(); form.copyFrom(customer); .. // Copies form stateField value into the customer address state Customer customer = new Customer(); form.copyTo(customer);When populating an object from a form post Click will automatically create any null nested objects so their properties can be set. To do this Click uses the no-args constructor of the nested objects class. {@link #copyTo(Object)} and {@link #copyFrom(Object)} also supportsjava.util.Map as an argument. Examples of using java.util.Map are shown in the respective method descriptions.
Form form = new Form("form"); form.setJavaScriptValidation(true); // Add form fields .. form.add(new Submit("ok", " OK ", this, "onOkClicked"); Submit cancel = new Submit("cancel", "Cancel", this, "onCancelClicked"); cancel.setCancelJavaScriptValidation(true); addControl(form);Please note in that is this example the cancel submit button has {@link Submit#setCancelJavaScriptValidation(boolean)} set to true. Thisprevents JavaScript form validation being performed when the cancel button is clicked.
<html> <head> $headElements </head> <body> $form $jsElements </body> </html>
{@link #buttonAlign} | button alignment: ["left", "center", "right"] |
{@link #buttonStyle} | button <td> "style" attribute value |
{@link #columns} | number of form table columns, the default value number is 1 |
{@link #errorsAlign} | validation error messages alignment: ["left", "center", "right"] |
{@link #errorsPosition} | validation error messages position: ["top", "middle", "bottom"] |
{@link #errorsStyle} | errors <td> "style" attribute value |
{@link #fieldStyle} | field <td> "style" attribute value |
{@link #labelAlign} | field label alignment: ["left", "center", "right"] |
{@link #labelsPosition} | label position relative to field: ["left", "top"] |
{@link #labelStyle} | label <td> "style" attribute value |
click/control.css | control CSS styles, automatically deployed to the click web directory |
/click-control.properties | form and field messages and HTML, located under classpath |
$form. {@link #getFields fields}.usernameFieldWhenever including your own Form markup in a page template or Velocity macro always specify:
$form.startTag() <table style="margin: 1em;"> #if ($form.error) <tr> <td colspan="2" style="color: red;"> $form.error </td> </tr> #end #if ($form.fields.usernameField.error) <tr> <td colspan="2" style="color: red;"> $form.fields.usernameField.error </td> </tr> #end #if ($form.fields.passwordField.error) <tr> <td colspan="2" style="color: red;"> $form.fields.passwordField.error </td> </tr> #end <tr> <td> Username: </td> <td> $form.fields.usernameField </td> </tr> <tr> <td> Password: </td> <td> $form.fields.passwordField </td> </tr> <tr> <td> $form.fields.okSubmit $form.fields.cancelSubmit </td> </tr> </table> $form.endTag()As you can see in this example most of the code and markup is generic and could be reused. This is where Velocity Macros come in.
#* Custom Form Macro Code *# #macro( writeForm[$form] ) $form.startTag() <table width="100%"> #if ($form.error) <tr> <td colspan="2" style="color: red;"> $form.error </td> </tr> #end #foreach ($field in $form.fieldList) #if (!$field.hidden) #if (!$field.valid) <tr> <td colspan="2"> $field.error </td> </tr> #end <tr> <td> $field.label: </td><td> $field </td> </tr> #end #end <tr> <td colspan="2"> #foreach ($button in $form.buttonList) $button #end </td> </tr> </table> $form.endTag() #endYou would then call this macro in your Page template passing it your form object:
#writeForm($form)At render time Velocity will execute the macro using the given form and render the results to the response output stream.
public class Purchase extends Page { .. public boolean onSecurityCheck() { return form.onSubmitCheck(this, "/invalid-submit.html"); } }The form submit check methods store a special token in the users session and in a hidden field in the form to ensure a form post isn't replayed.
See also the W3C HTML reference: FORM @see Field @see Submit
Encapsulates a form bean and the validation result in a single class. It is created automatically by the FormValidatingAction
NOTE: This class is NOT thread safe @author Ivelin Ivanov, ivelin@apache.org @author michael_hampel@sonynetservices.com @version CVS $Id: Form.java,v 1.1 2003/04/27 08:28:51 coliver Exp $Encapsulates a form bean and the validation result in a single class. It is created automatically by the FormValidatingAction
NOTE: This class is NOT thread safe @author Ivelin Ivanov, ivelin@apache.org @author michael_hampel@sonynetservices.com @version CVS $Id: Form.java,v 1.2 2003/04/26 12:10:44 stephan Exp $Encapsulates a form bean and the validation result in a single class. It is created automatically by the FormValidatingAction
@author Ivelin Ivanov, ivelin@apache.org @version $Revision: 1.1.2.1 $ $Date: 2002/05/24 09:06:55 $ This contains a set of validation rules for a form/JavaBean. The information is contained in a list of Field
objects. Instances of this class are configured with a <form> xml element.
The use of FastHashMap is deprecated and will be replaced in a future release.
@version $Revision: 478334 $ $Date: 2006-11-22 21:31:54 +0000 (Wed, 22 Nov 2006) $<s:form ... />
As a {@link IFormSubmitListener} the form gets notified of listener requests in{@link #onFormSubmitted()}. By default, the processing of this submit works like this:
In case of an upload error two resource keys are available to specify error messages: {@code uploadTooLarge} and {@code uploadFailed}, i.e. for a form with id {@code myform} in{@code MyPage.properties}:
myform.uploadTooLarge=You have uploaded a file that is over the allowed limit of 2MbForms can be nested. You can put a form in another form. Since HTML doesn't allow nested <form> tags, the inner forms will be rendered using the <div> tag. You have to submit the inner forms using explicit components (like {@link Button} or {@link SubmitLink}), you can't rely on implicit submit behavior (by using just <input type="submit"> that is not attached to a component).
When a nested form is submitted, the user entered values in outer (parent) forms are preserved and only the fields in the submitted form are validated. @author Jonathan Locke @author Juergen Donnerstag @author Eelco Hillenius @author Cameron Braid @author Johan Compagner @author Igor Vaynberg (ivaynberg) @author David Leangen @param < T> The model object type
ScrolledForm
instead because it has an instance of Form
and adds scrolling capability. Form can have a title if set. If not set, title area will not be left empty - form body will be resized to fill the entire form. In addition, an optional title image can be set and is rendered to the left of the title (since 3.2).
Form can have a title drop down menu if the menu bar manager is not empty (since 3.3).
Form title can support drag and drop if drag and drop support methods are invoked. When used, additional decoration is rendered behind the title to reinforce the drag and drop ability (since 3.3).
The form supports status messages. These messages can have various severity (error, warning, info or none). If status hyperlink handler is specified, the messages with the specified severity other than none will be rendered as hyperlinks.
Form can have a background image behind the title text. The image is tiled as many times as needed to fill the title area. Alternatively, gradient background can be painted vertically or horizontally.
Form can be put in a 'busy' state. While in this state, title image is replaced with an animation that lasts as long as the 'busy' state is active.
It is possible to create an optional head client control. When created, this control is placed in the form heading as a second row.
Form has a custom layout manager that is wrap-enabled. If a form is placed in a composite whose layout manager implements ILayoutExtension, the body of the form will participate in wrapping as long as its layout manager implements ILayoutExtension as well.
Children of the form should typically be created using FormToolkit to match the appearance and behaviour. When creating children, use the form body as a parent by calling 'getBody()' on the form instance. Example:
FormToolkit toolkit = new FormToolkit(parent.getDisplay()); Form form = toolkit.createForm(parent); form.setText("Sample form"); form.getBody().setLayout(new GridLayout()); toolkit.createButton(form.getBody(), "Checkbox", SWT.CHECK);
No layout manager has been set on the body. Clients are required to set the desired layout manager explicitly.
Although the class is not final, it should not be subclassed. @since 3.0
Utility class to help creating and handling forms. A form has multiple FormField
s, a Validator
and some utilities that almost every form needs. Rendering the form is a seperate concern from doing validation and form submission.
Most important interactions with the form are described below
FormField
items.SubmissionHandler
to determine what to do when the submission is valid or not. The handler receives the Record
containing the fields and their values.This class also specifies the FormValidationResult
as an inner class. This interface defines the interaction with the validation result. Of course you can ask if the form is valid. You can also ask the error messages. These are split up in generic error messages as well as field specific error messages.
During form submission, a Record
is filled with the data of the form fields. The record makes it easier to get to the data without the specifics of the widgets. Custom records can be provided using the contructor. By default the {@see MapRecord} is used.
This Form is the Component which gets dispatched by the framework. It then dispatches further to the really clicked FormComponent. The Form implements the following phases:
FormComponent and FormContainer form the same composite pattern as already used for the core.Component and core.Container, and take notice that the FormComponent itself is also a core.Component!
As a consequence of this, each element which want to live inside of a form must be a FormComponent but has also a Component side to the rendering framework.
The goals of the new form infrastructure are
Therefore it is important to always use the form.getParameter() methods and not the getParameter() methods from the user request directly. Normally you don't have to deal with this because the implemented form elements already take care of this issue.
All submitted files are saved to a temporary location in the userdata/tmp/ directory. During the dispatch phase in evalFormRequest() this files can be access using the getMultipartFilesSet() and getMultipartFile() methods. The files must be moved to another location within the execution of the evalFormRequest() because at the end of the method call, the temporary files will be removed. The temporary files have a random file name, use the getMultipartFileName() to retrieve the original file name.
When using the FileElement this is all already encapsulated, see the documentation there.
Initial Date: 27.11.2006
@author patrickb
Form
interface is used to represent the details submitted with a request. Typically this will be parameters given by a HTML form, however a form can also contain parts. Each part can represent either a file or a parameter. All parts can be acquired as Part
objects from this Form
.
@author Niall Gallagher
TODO Add a label alignment attribute (vertical). @author gbrown
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|