Dashboard > Spring Rich Client Project (Spring Rich) > User Documentation > Forms Support
  Spring Rich Client Project (Spring Rich) Log In View a printable version of the current page.  
  Forms Support
Added by Peter De Bruycker, last edited by David Wroton on Apr 20, 2007  (view change)
Labels: 
(None)

Forms Support

Forms are used to accept input from the user.

Creating a Form

Subclass AbstractForm.

public class CustomerForm extends AbstractForm {

    public CustomerForm(FormModel formModel) {
        super(formModel, "customerForm");
    }

    protected JComponent createFormControl() {
        FormLayout layout = new FormLayout("left:pref, 5dlu, pref:grow");
        BeanFormBuilder formBuilder = new JGoodiesBeanFormBuilder(
                getFormModel(), layout);
        formBuilder.add("number");
        formBuilder.add("name");
        return formBuilder.getForm();
    }
}

Compound Forms

The CompoundForm class is used to combine several "formpages" into one logical form. For example when you have a wizard with multiple pages, and each page contains one form, you can bind them together using CompoundForm.

FormBuilders

To create an advanced layout, you can use a FormBuilder. There are several implementations.

TableFormBuilder

Example:

TableFormBuilder formBuilder = new TableFormBuilder(formModel);

formBuilder.addSeparator("Name");
formBuilder.row();
formBuilder.add("title");
formBuilder.add("firstName");
formBuilder.add("lastName");
formBuilder.row();
formBuilder.addSeparator("Address");
formBuilder.row();
formBuilder.add("address1");
formBuilder.row();
formBuilder.add("address2");
formBuilder.row();
formBuilder.add("city");
formBuilder.add("postcode", "colSpec=2cm");
formBuilder.row();
formBuilder.add("state");
formBuilder.row();
formBuilder.add("country");

return formBuilder.getForm();

GridBagLayoutFormBuilder

Uses GridBagLayout.

Using the Form

In a Wizard

Create a FormBackedWizardPage and add it to the wizard.

In a Dialog

Customer customer = ...;
FormModel formModel = SwingFormModel.createFormModel(customer);
CustomerForm form = new CustomerForm(formModel);
FormBackedDialogPage page = new FormBackedDialogPage(form);

TitledPageApplicationDialog dialog = new TitledPageApplicationDialog(page, getParentWindowControl()) {
    protected void onAboutToShow() {
        setEnabled(compositePage.isPageComplete());
    }

    protected boolean onFinish() {
        ownerFormModel.commit();
        clinic.storeOwner(owner);
        ownersTreeModel.nodeChanged(getSelectedOwnerNode());
        return true;
    }
};
dialog.showDialog();

Validation

Currently there are two ways: you can register validation rules by configuring a RulesSource instance, like Petclinic's "ValidationRulesSource" class, or your form object can implement the RulesProvider PropertyConstraintProvider interface, like the Login SessionDetails class does.

Approach 1
You need to have a RulesSource implementation (see the PetClinicValidationRulesSource class for an example).

Here are the rules for the Owner class defined (firstName and lastName attributes are required, max 25 long and must be alphabetic, and the address attribute is required)

PetClinicValidationRulesSource.java
public class PetClinicValidationRulesSource extends DefaultRulesSource {

    public PetClinicValidationRulesSource() {
        addRules(createOwnerRules());
    }

    private Rules createOwnerRules() {
        Rules rules = Rules.createRules(Owner.class);
        rules.add("firstName", getNamePropertyConstraint());
        rules.add("lastName", getNamePropertyConstraint());
        rules.add("address", required());
        return rules;
    }

    private Constraint getNamePropertyConstraint() {
        return all(new Constraint[] { required(), maxLength(25),
                regexp("[a-zA-Z]*", "alphabetic") });
    }
}

The RulesSource is registered in the rich-clientappication-context.xml file:

<bean id="rulesSource" class="org.springframework.richclient.samples.petclinic.domain.PetClinicValidationRulesSource"/>

This will cause all forms that use the Owner class use these validation rules.

Approach 2
TODO - update to show use of PropertyConstraintProvider since RulesProvider is no longer used.

Make your form model object implement the RulesProvider interface. The RulesProvider defines one method: public PropertyConstraint getRules(String property). This example uses the DefaultRulesSource to implement this method.

Form model object:

TestFormBean.java
public class TestFormBean implements RulesProvider {

    RulesSource rulesSource = new DefaultRulesSource();
    private String inputString;

    public TestFormBean() {
      rulesSource.addRules(getRules());
    }

    private Rules getRules() {
        Rules rules = Rules.createRules(getClass());
        Constraints c = Constraints.instance();
        rules.add("inputString", c.required());

        return rules;
    }

    // implementation of RulesProvider interface
    public PropertyConstraint getRules(String property) {
        return rulesSource.getRules(getClass(), property);
    }
}

Form instance

TestForm.java
public class TestForm extends AbstractForm {

    private TestFormBean testFormBean = new TestFormBean();

    public LoginForm() {
        super("general");
        setFormModel(SwingFormModel.createFormModel(this.testFormBean));
    }

    protected JComponent createFormControl() {
        FormLayout layout = new FormLayout("left:pref, 5dlu, pref:grow");
        BeanFormBuilder formBuilder = new JGoodiesBeanFormBuilder(
                getFormModel(), layout);
        formBuilder.add("inputString");

        return formBuilder.getForm();
    }

    public void commit() throws AuthenticationException {
        // do your stuff here
    }
}

Constraints

How to implement your own Constraint.

I18n the error message

Make your constraint implement TypeResolvable. There is a TypeResolvableConstraint helper class you can subclass. TypeResolvables automatically get resolved in Spring message sources.

public class MyCustomConstraint extends TypeResolvableConstraint {
    public MyCustomConstraint() {
        super("customConstraint");
    }

    public boolean test(Object argument) {
        // implementation of constraint
    }
}

Binding

Binding the value in the control with the backing domain object is done by way of a Binding object, which is typically created by a Binder. For example, when you ask the framework to create a control for you for the "bar" property of Foo, where "bar" is a String, a TextComponentBinder returns back a TextComponentBinding, which handles keeping everything in sync.

If you did all of this explicitly, it would look like:

BindingFactory bindingFactory = new SwingBindingFactory(formModel);
Binding fooBinding = bindingFactory.createBoundTextField("bar");
JComponent fooControl = fooBinding.getControl();

That may look like a lot of work just to create a text field, but there's an enormous amount of work that's happening there automaticly, including registering both the object's property and the control for validation support, automaticly keeping in sync, and much more. It also means that the kind of control to use is automaticly determined and created for you, so you can make uniform changes across your application in one place. (For example, changing from a standard JTextArea to a component that supports full rich text capabilities across the entire application.) The scope of which Binder to use can be determined by the property class, associated with just a specific property, and more.

Binder

An example of a Binder:

/**
 * This provides a {@link Binder} for {@link Long} that only allows
 *   valid "Long" values to be entered into the control.
 */
public class LongBinder extends AbstractBinder {
  public LongBinder() {
    super(Long.class);
  }

  protected JComponent createControl(Map context) {
    return new LongTextField();
  }

  protected Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context) {
    return new TextComponentBinding((JTextComponent)control, formModel, formPropertyPath);
  }

  private static class LongTextField extends JFormattedTextField {
    public boolean isEditValid() {
      final String text = getText();
      if (text == null) return true;
      try {
        Long.parseLong(text);
        return true;
      }
      catch (NumberFormatException e) {
        return false;
      }
    }
  }
}

BinderSelectionStrategy

If you want to change or add to the standard set of automatic bindings, simply implement BinderSelectionStrategy. An example BinderSelectionStrategy would be:

public class MyBinderSelectionStrategy extends SwingBinderSelectionStrategy {
  protected void registerDefaultBinders() {
    super.registerDefaultBinders();
    registerBinderForPropertyType(Long.class, new LongBinder());
    registerBinderForPropertyType(Date.class, new DateBinder());
    registerBinderForPropertyType(Foo[].class, new FooArrayBinder());
  }
}

To get the Application object to automaticly use your custom BinderSelectionStrategy, add this line to your application-context.xml:

<bean id="binderSelectionStrategy" class="bar.foo.MyBinderSelectionStrategy"/>
DateChooser Integration (Spring Rich Client Project (Spring Rich))

From the forum - http://forum.springframework.org/viewtopic.php?t=2482

When building components with a BeanFormBuilder (at least; likely others), a Label is automatically applied. The framework searches for labels in this order:
1. label.property
2. property
3. formId.label.property
So, if you have two pojos (foo, bar), each with the same property (id), then the following entries in your <messages>.properties:
label.id=FooBar
bar.label.id=Bar

would result in 'Bar' as the label for bar.id and 'FooBar' as the label for foo.id.

Posted by Anonymous at Dec 18, 2004 08:44

Forms make use of FormModels which make use of ValueModels. Spring-rich's ValueModel is based on ideas presented here: http://c2.com/ppr/vmodels.html

Posted by Anonymous at Dec 29, 2004 13:31
Site running on a free Atlassian Confluence Open Source Project License granted to Spring Framework. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.5 Build:#811 Jul 25, 2007) - Bug/feature request - Contact Administrators