Tag Archives: object oriented

JavaFX Forms Framework Part 3

Introduction

Matthew 7:13-14

Matthew 7:13-14

This is the third installment of a series of blog entries relating to a proof of concept for a JavaFX Forms Framework. If you missed the beginning of the series you may go to Part 1 and Part 2. We will take a look at code snippets relating to how the FXForms Framework was implemented. If you want to jump right into the code you may download it here or browse the source code here from the JFXtras Samples area. To those who are following the series will notice similarities to JGoodies Bindings and Validation libraries, it is because of those libraries and presentations which basically inspired me to create this MVC forms framework in JavaFX.

Disclaimer: Most of the code snippets will deal with the user of the API’s perspective as opposed to the implementer of the API’s perspective in order to keep the blog entry short. I will try my best to touch on areas regarding the framework’s underlying implementation. I advise people to check the code project out, review it and run it.

A thing I’d like to bring to your attention is that I decided to refactor the code a little and add a new feature to the FXForms Framework. I refactored the form to reference an instance of a presentation model instead of inheriting from it. As I mentioned in Part 2 the form will be independent of the presentation model. This provides different validation contexts while reusing the same form. An example of this situation is when a user uses a form to ‘Add’ information versus an ‘Edit’ of the form information. The new feature added is the ability to validate a field as the user is typing into the text box and positions an icon to indicate an error, warning or information to the user. Another feature might be to add tool tips when the mouse hovers over the icon similar to JGoodies’ IconFeedbackPanel behavior in Java Swing. Before going further into the implementation details you may want to launch the demo to get a feel for the behavior of the entry form with validation and icon indicators.

Demo

Demo

Instructions:

  • Enter numbers or symbols into the first, last and middle name field.
  • Click on the check box to swap the JavaBean for the form.
  • Observe the underlying bean values changing.

Next are the steps on how to develop the demo using the FXForms Framework.

Developer Steps

  1. Create a JavaBean representing a domain object.
  2. Create a Presentation Model with validation for a Form.
  3. Create a Form
  4. Associate a Presentation Model to Form
  5. Use the Form in an application

Detailed Steps

Step 1. Create a JavaBean representing a domain object.

// Java
public class PersonBean extends DomainModel{
    public static final String FIRST_NAME_PROPERTY = "firstName";
    public static final String MIDDLE_NAME_PROPERTY = "middleName";
... // more strings naming properties
    private String firstName;
    private String middleName;
... // more attributes

    /**
     * Returns first name of the person.
     * @return
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * Sets the first name of the person.
     * @param firstName
     */
    public void setFirstName(String firstName) {
        String old = this.firstName;
        this.firstName = firstName;
        firePropertyChange(FIRST_NAME_PROPERTY, old, firstName);
    }
... // the rest of the methods.
}

PersonBean.java – A domain object containing property change support.

DomainModel.java – Abstract base class containing property change support.

Step 2. Create a Presentation Model with validation for a Form

As I mentioned earlier about reusing the same form with different presentation models. Below you will see an ‘Add Form’ with validation on the Last Name field. The error icon indicates that the last name may not contain symbols and numbers, but allowing letters, apostrophe or hyphen in the name. You will notice the red error icon beside the ‘last name’ text field.

Add Form validation on last name field.

Add Form validation on last name field.

    // JavaFX
    var personForm:NameForm = NameForm{
        presentationModel:domain.model.personpresentationmodel.AddPersonPM{}
    };
    personForm.presentationModel.jBean = new PersonBean();

Next, you will see an ‘Edit Form’ with no validation on the ‘Last Name’ field. But, there is validation on the ‘First Name’ field. The warning icon indicates that the first name can contain symbols and numbers, letters, apostrophe or hyphen, but isn’t recommended. You will notice the yellow warning icon beside the ‘first name‘ field.

Edit Form no validation for Last Name field

Edit Form no validation for Last Name field

    // JavaFX
    personForm.presentationModel = domain.model.personpresentationmodel.EditPersonPM{}
    personForm.presentationModel.jBean = personBean2;

*Note: The examples above are two hypothetical use cases, I mocked up those forms to help illustrate different validation contexts. The demo app uses an edit presentation model that does validate on the ‘last name‘ field.

Edit Person Presentation Model w/Validation

// JavaFX
public class EditPersonPM extends fxforms.model.model.PresentationModel {

   /** Validate the first name field */
   var validateFirstName =  Validator{
       id:PersonBean.FIRST_NAME_PROPERTY
       public override function validate(value:Object){
           return validateName(value, PersonBean.FIRST_NAME_PROPERTY, "Warning");
       }
   };
... // more validators
   postinit {
       addValidator(validateLastName);
       addValidator(validateFirstName);
       addValidator(validateMiddleName);
   }
}
// Script level function
/**
 * Using regular expression allow letters, apostrophe, hyphen
 */
function validateName(value:Object, propName:String, messageType:String){ // use friendly names, short names, etc.
    var results = ValidationResult{};
    var strValue:String = value as String;
    var found:Boolean = Pattern.matches("^[a-zA-Z,'.\\-\\s]*$", strValue);
    if (not found) {
        var message:FieldMessage = FieldMessage{
            id:propName
            messageType:messageType
            errorId:"123"
            errorMessage:"No symbols in names except - or ' (apostrophe)"
        }
        results.addMessage(message);
    }
    return results;
}

Line 01: Class EditPersonPM extends fxforms.model.model.PresentationModel
Line 04: var validateFirstName is an instance of a Validator
Line 12: Adds all Validators to the presentation model
Line 21: Script level function to be used in each validator
Line 24: Regular expression to allow letters, apostrophe and hyphen characters only.
Line 26: Creation of the message when Validator validates.

personpresentationmodel.fx – The edit presentation model for a person name form.

model.fx – Contains presentation model and value model implementation.

validation.fx – Contains the validator, message, result classes.

Step 3. Create a Form

Edit Person Form (Screen mockup)

0 full name panel
+-1------------------------+ // VBox with 3 things
! +-2--------------------+ ! // HBox with 2 things
! ! [ 3 ] [ 4           ]! ! // Label(section) and Label(title)
! +----------------------+ !
! +-5--------------------+ ! // HBox with 2 things
! ! [ 6 ] [ 7  ]         ! ! // Label(spacer} and Text(instructions)
! !                      ! ! // wrapping text abilities
! +----------------------+ !
! +-8--------------------+ ! // HBox with 2 things
! ! +-9---+ +-10-------+ ! ! // VBox_9(labels) Vbox_10(textbox)
! ! ![11] ! ! [15]     ! ! ! // Label(lastname) TextBox()
! ! ![12] ! ! [16]     ! ! ! // Label(firstName) TextBox()
! ! ![13] ! ! [17]     ! ! ! // Label(mi)  TextBox()
! ! ![14] ! ! [18]     ! ! ! // Label(suffix)  TextBox()
! ! +-----+ +----------+ ! !
! +----------------------+ !
+--------------------------+

NameForm inherits from Form
Form inherits from CustomNode

// JavaFX
public class NameForm extends fxforms.ui.form.Form {
   public override function create():Node{
        // 0 main panel
        var mainPanel:Panel = Panel{
            content:[]
        }
        ... // more layouts and widgets

        var firstLabel:Label = Label {
            text: "First Name"
            hpos:HPos.RIGHT
            font : Font {
                size: 18
            }
            layoutInfo: LayoutInfo { minWidth: 100 width: 150 maxWidth: 200 }
        };
        ... // more code
        var lastNameTextBox:TextBox = fxforms.ui.controls.MyTextBox {
            id:"lastName"
            columns:20
        };
        var miNameTextBox:TextBox = fxforms.ui.controls.MyTextBox {
            id:"middleName"
            columns:20
        };
        ... // more fields

        // *** NOTE: This is for easy lookup. And relating to Scene.lookup(id) bug in 1.2.
        guiFields = [lastNameTextBox, firstNameTextBox, miNameTextBox, suffixNameTextBox];
        presentationModel.addGuiFields(guiFields);
        return mainPanel;
    } // create()
} // NameForm

NameForm.fx – This represents a Form containing a person’s name information.

form.fx – This is the base class which contains the presentation model for forms binding behavior.

controls.fx – This contains all registered GUI controls for observing value model value changes. Currently only one control exists the TextBox control.

*Note: The ideal way to build forms is using the JFXtras MigLayout library. To learn more take a look at Dean Iverson’s blog entry called “MigLayout for JavaFX Reloaded“.

Step 4. Associate a Presentation Model to Form

// JavaFX
var personForm:NameForm = NameForm{
    presentationModel:domain.model.personpresentationmodel.EditPersonPM{}
    translateX: bind slideFormX
};
var personBean2:domain.model.PersonBean = new domain.model.PersonBean();
personBean2.setFirstName("Squidward");
personBean2.setLastName("Tentacles");
personBean2.setMiddleName("Nickelodeon");
personBean2.setSuffixName("Sr.");

// set presentation model with domain object
personForm.presentationModel.jBean = personBean2;

Line 02: Associate presentation model to form
Line 05: Create an instance of a JavaBean
Line 12: Bind bean to presentation model and form

Once the presentation model and form are assembled binding an existing Java object is a snap. In part 4 on enhancing this process would be to create a factory to obtain meta information of the form to retrieve nested properties within a POJO/JavaBean off of the JavaFX main thread (desktop profile is the EDT). This effort will help alleviate from the dreaded Hibernate lazy init exception when using detached objects. So, making sure you don’t block the GUI thread is a big deal when it comes to user experience.

Step 5. Use the Form in an application

    var switchPersonButton:CheckBox = CheckBox {
            text: bind personToSwitchText
            width: 100
            translateX: 5
            translateY: bind mainScene.height - switchPersonButton.height - 5
            allowTriState: false
            selected: false
            override var onMouseReleased = function(e:MouseEvent):Void {
                if (selected){
                   personToSwitchText = "Sponge Bob";
                   personForm.presentationModel.jBean = personBean1;
                } else {
                   personToSwitchText = "Squidward";
                   personForm.presentationModel.jBean = personBean2;
                }
            }
        };

    var mainScene:Scene = Scene {
        fill: LinearGradient {
                    startX: 0
                    startY: 0
                    endX: 0
                    endY: 1
                    stops: [
                        Stop { offset: 0.1 color: Color.ORANGE },
                        Stop { offset: 1.0 color: Color.YELLOW },
                    ]
                }
        content: [personForm, switchPersonButton, backButton, nextButton]
    };

Main.fx – The main application file to launch the application

Value Model

The ‘Value Model‘ is probably the most important aspect of how the Forms binding works. The value model is a model that holds a single value that notifies registered listeners that a value has changed. Registered listeners will likely be GUI controls and JavaBean properties. Bidirectional binding occurs when a bean property value changes, which notifies the value model which updates the  GUI control value. This holds true when going in the other direction too, such as the user changes the value of the GUI control which notifies the value model which updates the JavaBean property value.

model.fx – Contains presentation model and value model implementations.

Conclusion

I feel the implementation of the fxforms framework using JavaFX was extremely easy and is a lot less code compared to a Java equivalent of a Swing/SWT forms framework, also carrying additional overhead using 3rd party libraries for binding and validation. As JavaFX matures with more controls the forms framework would need to be flexible enough to add any controls to handle custom bindings such as list models.  Next we will look at Part 4 Enhancements . As always any feedback is welcome!

References

Validation presentation by Karsten Lentzsch – http://www.jgoodies.com/articles/validation.pdf

JGoodies: http://www.jgoodies.com/

JGoodies Support: http://www.jgoodies.com/products/purchase.html

The Unknown JavaBean by Richard Bair – http://weblogs.java.net/blog/rbair/archive/2006/05/the_unknown_jav.html

JavaFX – JMS Unexpected Null Pointer Exception http://blogs.sun.com/clarkeman/entry/javafx_jms_unexpected_null_pointer

JFXtras Community Site – http://jfxtras.org/portal/home

Does JavaFX have Multiple Inheritance?

CatDog cartoon from Nickodean

CatDog cartoon from Nickelodeon

Introduction

Often when we learn about object oriented programming we try to find out if a particular language contains a dirty little phrase called multiple inheritance. Of course there are good reasons to try to avoid it (Diamond Problem) but sometimes you can’t.  I believe that it can be used in certain contexts which can be done safely (fearing and trembling from angry purists). In Java when asked if multiple inheritance is supported the answer is “Well, Sort of” or “Yes, but…“. Java has interfaces which follows the Design by Contract concept which forces the developer to implement the interface methods. Fundamentally when we think of abstraction we think of what behavior is common across classes. Abstract classes help but tend to get bloated and some folks resort to creating NOP (No operation performed) methods. One of the major principles of object oriented programming is re-use not un-re-use while rendering an object very coupled-ygoop. It would be wonderful if you could have method re-use from an abstract data type. Well, JavaFX has this ability to do this very thing! So, to ask the question again “Does JavaFX have multiple inheritance?“. I would answer it like this: “Yes, its similar to Java’s Interfaces but with implementation details“. JavaFX uses a concept called Mixin classes which allows the developer to inherit multiple classes. Sweet!

Example

I couldn’t help but think about all kinds of cats when thinking about multiple inheritance (not to be confused with these types of cats I Can Has Cheezburger ). In a nutshell there are Big cats and Small cats.

Requirements:

  • Some Big cats can roar, but all big cats can’t meow.
  • Similarly small cats can meow, but all small cats can’t roar.
  • All cats can purr.

In this example we will model reusable behavior as Mixins and we will also create the standard abstract classes such as “Animal” and “Cat“.

Step 1: Create Abstract Classes

abstract class Animal {
    public var name:String;
    public function eat(food:String){
        println("munchin on {food}");
    }
}

abstract public class Cat extends Animal {
    public function purr(volume:Integer){
        println("Purrrr...level({volume})");
    }
    public function scratch(){
        println("Scratching...")
    }

}

Step 2: Create Mixin Classes

public mixin class Roarer {
    public var bass:Integer = 20;
    public function roar(){
        println("Roar...");
    }
}

public mixin class Meower {
    public var pitch:Integer = 5;
    public function meow(){
        println("Meow...");
    }
}

Step 3: Create Derived Classes Inheriting Mixin Classes

// Cheetah's can't roar and can't meow
class Cheetah extends Cat {
}

class Lion extends Cat, Roarer{
    public override var bass = 50;
    public override function roar() {
        println("(ROAR) I'm King of the land!!!");
    }
}

class HouseCat extends Cat, Meower {
    public override var pitch = 10;
    public override function meow(){
        println("Meow...");
    }
}

Step 4: Create instances of the types of Cats

var fluffy:Cat = HouseCat{name:'fluffy'}; // regular house cat
var simba:Cat = Lion{name:'Simba'};      // Lion King cat
var chester:Cat = Cheetah{name:'Chester'}; // Cheetos' Chester

var cats:Cat[] = [fluffy, simba, chester]; // cat bus

Step 5: Create a script level function

Cat will ask to come into your house. Notice the down cast to Meower and Roarer type cats.

function letMeIntoHouse(cat:Cat){
        print("LET ME IN! ");
        if (cat instanceof Meower){
            var meower = (cat as Meower);
            meower.meow();
        }
        if (cat instanceof Roarer){
            var roarer = (cat as Roarer);
            roarer.roar();
        }
        cat.scratch();
}

Step 6: run() function like Java’s main()

This will loop through a sequence of cats by:

  • Cat asking in your house
  • Introduces cat
  • Feeds cat
  • Cat will purr
  • function run(){
        def food:String = "tender vittles";
        for (cat:Cat in cats){
            letMeIntoHouse(cat);
            print("The cat named {cat.name} is ");
            cat.eat(food);
            cat.purr(5);
        }
    }

    Output

    LET ME IN! Meow...
    Scratching...
    The cat named fluffy is munchin on tender vittles
    Purrrr...level(5)
    LET ME IN! (ROAR) I'm King of the land!!!
    Scratching...
    The cat named Simba is munchin on tender vittles
    Purrrr...level(5)
    LET ME IN! Scratching...
    The cat named Chester is munchin on tender vittles
    Purrrr...level(5)

    Conclusion

    Although this example doesn’t use Mixins in an RIA context, instead its used with simple domain objects to show multiple inheritance. Hopefully we can now answer the question when asked, “Does JavaFX have multiple inheritance?“. Is it ever a quick answer?

    References: