JavaFX Forms Framework Part 4


Introduction

(Updated)** Added JavaFX Script code to represent a display panel mapping instead of the XML format example in the ‘User of the API (Application Developer)’ section.

(Thanks! Andres Almiray)


This is the forth installment of a series of blog entries relating to a proof of concept for a JavaFX Forms Framework.

Chairman and Co-Founder, Sun Microsystems. (person on the left)

Chairman and Co-Founder, Sun Microsystems. (person on the left)

If you missed the beginning of the series you may go to Part 1, Part 2 and Part 3. Before we discuss this section I want to recap for those who have been following along. Part 1 explains “What is a Form based framework?” and a demo application. Part 2 describes the requirements and design. Part 3 are the implementation details. As we near the end of the series in Part 4 we will discuss enhancements that could be added to improve the FXForms framework. Below is a summary of the features from two user perspectives, first being the ‘User of the API’ and secondly the ‘User of the application’. I will only explain in detail the ‘User of the API‘ perspective.

Features

User of the API (Application Developer)

  • Mapping files (forms to beans)
  • GUI Component factory – make use of other controls

User of the application (User experience)

  • Icon error, warn, info indicators overlay
  1. Override images to load and position when validation occurs.
  2. Error / Exceptions / Global errors
  3. Tooltips
  • Transitions to forms (fading, sliding, etc)
  • Focus Policy
  • User feedback (block gui visually) busy, indeterminate state.
  • Skinning and Themes for Forms
  • Context sensitive help
  • Sound effects

User of the API (Application Developer)

The goal here is to make life easier for the Application developer developing JavaFX Forms.

The features are as follows:

  • Mapping Files – This provides custom bindings to field elements and bean properties. Also provides mappings for actions and controls.
  • GUI Component factories – Display panel managers (form manager) to assemble and wrap components to provide presentation model pattern behavior.

1) Mapping files (forms to beans) – Display panels (forms) will be mapped to a particular Java Bean class. Each field will be mapped based on the bean property ‘name’ and the GUI widget’s ‘id’ attribute. When defining a display panel in XML it is a good idea to create a DTD or Schema, but for brevity I will not create them, and I will describe each XML element in detail such as default values, enumerated types, etc. an object representing fields and their corresponding bindings and actions will be called a ‘Display Panel Metadata’ object.

When mapping fields and controls here are situations you will encounter:

  • Nested properties – Nested objects ie: Person references an object Address with a property called city. (use  ‘address.city‘)
  • Mapping bean properties with different GUI component ids. ie: Person bean property is ‘fName‘ and the TextBox’s id is ‘firstName
  • Custom bindings (list models single select, multi-select and contains all). ie: ListBox containing all objects in a collection owned by Person.
  • Action mappings to events and controls. ie: Buttons are mapped to functions in modules (script level functions).

Below is an example of an XML mapping file might look like:

Please skip this mapping file and go to JavaFX script code right after it. XML mapping file is replaced by JavaFX script code.


<displayPanels>
  <!--
  *************************************************************************
  **** NO LONGER IN USE, DEPRECATED,                                  *****
  **** Please DISREGARD.
  **** REPLACED WITH JavaFX DisplayPanelMetadata class                *****
  *************************************************************************
  --------------------------------
  - Full Name Form Display Panel -
  --------------------------------
  This describes all gui widgets and actions.
    * Text control bound to a different named bean property 'fName'
    * Radio buttons bound to bean property 'likesFood'
    * Spinner control bound to bean property 'dateOfBirth'
    * Spinner control bound to bean property 'shoeSize'
    * List or combo control bound to nested bean property 'address.state'
    * List box control bound to nested bean property 'contacts' (collection)
    * List box control bound to nested bean property 'relatives' (collection)
    * Button control bound to action handler 
  -->
  <displayPanel id="FullNameForm" 
    className="com.company.forms.FullNameForm" 
    beanClass="com.company.domain.model.PersonBean" 
    presentationModel="com.company.domain.model.personpresentationmodel.EditPersonPM" 
    reuseForm=”true”>

    <!--First Name Field -->
    <textControl id="firstName" name="fName"/>

    <!-- Likes Food (yes or no)-->
    <radioButton id=”no”
      name=”likesFood”
      selectedValue=”true”
      bindingType=”BOOLEAN_TYPE”/>
    <radioButton id=”yes”
      name=”likesFood”
      selectedValue=”false”
      bindingType=”BOOLEAN_TYPE”/>

    <!--Date of Birth Spinner control-->
    <spinner id=”dob”
      name=”dateOfBirth”
      defaultValue=”null”
      bindingType=”DATE_TYPE”/>

    <!--Shoe Size Spinner control-->
    <spinner id=”shoeSize”
      name=”shoeSize”
      defaultValue=”5”
      minimumValue=”2”
      maxValue=”18”
      stepValue=”1”
      bindingType=”NUMBER” />

    <!--US State Drop Down List control-->
    <listModel id="address.state" 
      uniqueElementProperty="code" 
      displayName="${name}" />

    <!--Contacts List Box control-->
    <listModel id="contacts" 
      uniqueElementProperty="id" 
      displayName="${firstName} ${lastName} – (${id})" 
      bindingType="MULTIPLE_SELECT" />

    <!--Relatives List Box control-->
    <listModel id="relatives"
      name="relatives" 
      uniqueElementProperty="id"
      displayName="${firstName} ${lastName} – (${id})" 
      bindingType="CONTAINS_ALL" />

    <!--Save Button control-->
    <action id=”saveAction” 
      name="saveAction" 
      module="com.company.domain.forms.personactions" 
      function="updatePerson" 
      listener="java.awt.event.ActionListener"/>

  </displayPanel>
</displayPanels>

Line 15-19 Defines a form or display panel.

Line 22 Maps a text field when a bean property and GUI control are named differently. Framework should assume if the name and id are the same and at text control developer doesn’t need to map. This keeps the XML mapping file smaller.

Line 24-32 Custom binding for radio controls. Other scenarios exist, but for a simple boolean value selection the ‘BOOLEAN_TYPE’

Line 34-38 Custom binding for a JSpinner. The bean property is a java.util.Date.

Line 41-47 Custom binding for a JSpinner. The bean property is an int.

Line 49-52 Custom binding for a dropdown list. The bean property is a java.lang.String. Notice the nested properties. When a form displays a nested property on the same form.

Line 54-58 Custom binding for a List box. This is not bound to a bean property but a populated list allowing the user to select multiple items.

Line 60-65 Custom binding for a List box. This is bound to a bean property referencing a collection of objects. Notice the “CONTAINS_ALL” which means all items in the list box are synchronized inside the collection.

Line 67-72 Action mapping for a button on the form. They are named so actions can be reused such as menu or toolbar.

Disregard the XML mapping file above. The same representation is below in JavaFX script code defining a display panel.

**IMPORTANT NOTE: Since JavaFX is a declarative language which can achieve the same thing as a mapping file, I have re done the XML in JavaFX below:

var displayPanelMetadata:DisplayPanelMetadata =  DisplayPanelMetadata {
  id: "FullNameForm"
  className: "com.company.forms.FullNameForm"
  reuseForm: true

  // Custom bindings to field elements
  customBindings: [
    // First Name Field 
    TextControlMetadata{
        id: "firstName"
        name: "fName"
    },

    // Likes Food (yes or no)
    RadioButtonMetadata {
        id: "no"
        name: "likesFood"
        selectedValue: "false"
        bindingType:"BOOLEAN_TYPE"
    },

    RadioButtonMetadata {
        id: "yes"
        name: "likesFood"
        selectedValue: "true"
        bindingType:"BOOLEAN_TYPE"
    },

    // Date of Birth Spinner control
    SpinnerMetadata {
        id: "dob"
        name: "dateOfBirth"
        defaultValue:"null"
        bindingType: "DATE_TYPE"
    },

    // shoe size
    SpinnerMetadata {
        id: "shoeSize"
        name: "shoeSize"
        defaultValue: "5"
        minimumValue: "2"
        maxValue: "18"
        stepValue: "1"
        bindingType: "NUMBER_TYPE"
    },

    // state selection
    ListModelMetadata {
        id: "address.state"
        uniqueElementProperty:"code"
        displayName:"${name}"
    },

    // contacts List Box control (not bound to bean)
    ListModelMetadata {
        id: "contacts"
        uniqueElementProperty:"id"
        displayName: "${firstName} ${lastName} – (${id})"
        bindingType: "MULTIPLE_SELECT"
    },

    // relatives(family) List Box control
    ListModelMetadata {
        id: "relatives"
        name: "relatives"
        uniqueElementProperty:"id"
        displayName: "${firstName} ${lastName} – (${id})"
        bindingType: "CONTAINS_ALL"
    }
  ] // custom bindings sequence

  // Save Button control
  actions:[
      ActionMetaData {
      name: "saveAction"
      module: "com.company.domain.forms.personactions"
      functionReference: "updatePerson"
    }

    ] // actions

} //displayPanel

Line 0-3 Defines a form or display panel.

Line 8-11 Maps a text field when a bean property and GUI control are named differently. Framework should assume if the name and id are the same and at text control developer doesn’t need to map. This keeps the metadata mapping info smaller.

Line 14-19 Custom binding for radio controls. Other scenarios exist, but for a simple boolean value selection the ‘BOOLEAN_TYPE’

Line 29-34 Custom binding for a JSpinner. The bean property is a java.util.Date.

Line 37-45 Custom binding for a JSpinner. The bean property is an int.

Line 48-52 Custom binding for a dropdown list. The bean property is a java.lang.String. Notice the nested properties. When a form displays a nested property on the same form.

Line 55-60 Custom binding for a List box. This is not bound to a bean property but a populated list allowing the user to select multiple items.

Line 63-69 Custom binding for a List box. This is bound to a bean property referencing a collection of objects. Notice the “CONTAINS_ALL” which means all items in the list box are synchronized inside the collection.

Line 74-77 Action mapping for a button on the form. They are named so actions can be reused such as menu or toolbar.

2) GUI Component factory – make use of other controls

Forms can be retrieved and populated using convenient factory functions. When assembling a form and mapping properties the underlying implementation may have a configuration file to have modular ways to specify what controls will be used for binding controls.

var personForm = FormManager.retrieveForm(personBean, 'FullNameForm');

Conclusion

While some features of the ‘User of the Application‘ perspective may seem debatable, I believe a forms framework should at least have all the features described in the ‘User of the APIs‘ perspective. As a framework implementer one should design a plug-able architecture for custom components. Components should be wrapped and registered when assembling a form. I’m sure there are many features I have not mentioned.  As JavaFX matures I believe GUI builders providing WYSIWYG development will eventually allow third party GUI controls to be added to their control palette. Next, I will discuss Part 5 Concluding thoughts.

Like always, any comments are welcome!

Advertisements

10 thoughts on “JavaFX Forms Framework Part 4

  1. Pingback: JavaFX Forms Framework Part 3 « Carl’s FX Blog

  2. Pingback: JavaFX Forms Framework Part 1 « Carl’s FX Blog

  3. Pingback: JavaFX Forms Framework Part 2 « Carl’s FX Blog

  4. Andres Almiray

    Carl, what’s the benefit of choosing XML to define a form? you already have a declarative language (JavaFX Script) that can take are of that job.

  5. carldea Post author

    Andres,

    Very interesting… , I guess I could have done it with JavaFX Script. Yeah, parsing things would be a pain.
    My brain didn’t want to take me there for some reason.

    I hope people read the comments? (cause I may not create a JavaFX Script version.. [need time]).

    Thanks!

    -Carl

  6. Jean-Francois Poilpret

    From the viewpoint of the application user, I think that you should ensure that the dialog is always “good-looking”, in particular, with regards to baseline alignment of components (labels, fields…)
    Having forms without baseline alignment doesn’t look very professional nowadays.

  7. carldea Post author

    Jean-Francois,

    Yep, it’s pretty ugly. Others have commented about it too :(. Any form building from an application user’s viewpoint, I will plan to use JFXtras Gridlayout or Miglayout. Since the goal was MVC, I just whipped up that GUI (like a bad gum wrapper -throw away code-). That’s what is so great about the forms framework is that I could get someone else who can build awesome looking forms (designer role) or (when one gui builder tool exists [wannabe GUI role (me)]) mean while the FXForms Framework can just wire up the domain specific stuff (developer role).

    Thanks! for explaining the little details on aesthetics, cause I’m still learning the Web 2.0-ish look, (I’m still an Enterprise-y look menus, swingx, etc. thinking person).

    The only way I learn it to hear criticisms. It seems to be a good thing!

    Carl

  8. Pingback: Java desktop links of the week, September 7 | Jonathan Giles

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s