We use GroupLayout to assemble simple subpanels. For complicated forms, programming layout becomes (very) difficult, and so it's saner to use a GUI designer such as Netbeans.

http://weblogs.java.net/blog/evanx/archive/kcoloredit.png

Click here to read "Group Layout Therapy, a psychological drama"
A part of "Gooey Beans, a trilogy in 42 parts"


     


Demo

Our Address Form is in play again.

Launch   (AddressForm, 150k/400k, unsandboxed, Java6)

 

addressFormLayout600.png -->

http://weblogs.java.net/blog/evanx/archive/addressFormGroupLayout700.png


Code glance

We configure our component properties inAddressFormPanelProperties so thatAddressFormLayoutPanel below is relatively neat.

public class AddressFormLayoutPanel extends JPanel {
    AddressFormPanelProperties properties = 
        dependencyContainer.getInstance(AddressFormPanelProperties.class);
        
    public AddressFormGroupLayoutPanel() {
        initComponents();
    }
    
    private void initComponents() {
        addVerticalPanel(
                createHorizontalPanel(
                createInputComponentPanel(properties.firstName, firstName),
                createInputComponentPanel(properties.lastName, lastName),
                createInputComponentPanel(properties.email, email, true),
                createInputComponentPanel(properties.phone, phone)
                ),
                createHorizontalPanel(
                createInputComponentPanel(properties.address1, address1, true),
                createInputComponentPanel(properties.address2, address2, true)
                ),
                createHorizontalPanel(
                createInputComponentPanel(properties.postalCode, postalCode),
                createInputComponentPanel(properties.city, city),
                createInputComponentPanel(properties.state, state, true),
                createInputComponentPanel(properties.country, country),
                createInputComponentPanel(properties.postable, postable)
                )
                );
    }
    ...
    private JTextField firstName = new JTextField();
    private JTextField lastName = new JTextField();
    private JTextField phone = new JTextField();
    private JTextField email = new JTextField();
    private JTextField address1 = new JTextField();
    private JTextField address2 = new JTextField();
    private JTextField city = new JTextField();
    private JTextField state = new JTextField();
    private JTextField postalCode = new JTextField();
    private JComboBox country = new JComboBox(new Object[] {"South Africa", "Zimbabwe"});
    private JCheckBox postable = new JCheckBox();
}

where createInputComponentPanel() creates a subpanel with an input component and it's label above it.


Punchline

Our AddressFormLayoutPanel and itsAddressFormLayoutPanelProperties is delibrately interchangeable with a form produced using Netbeans' GUI designer so that we can choose to program our form view as above, or otherwise design our form using Netbeans.


Sneak Preview

The next step is beans binding for our form, woohoo!

Our Presentation Model class is a separate testable class which we bind to our form. Our controller is also implemented as a separate class, which interacts with the components in our forms, and of course our presentation model beans.

So to summarise, our MVC architecture consists of the following.

  • View classes eg. produced using Netbeans GUI designer.
  • Presentation Model classes which can be developed using TDD.
  • Controller class which implements event listeners and manipulates the view and model.

We provide beans binding support, so that the controller can conveniently invoke a single method to update a presentation model from a form, and visa versa.

The controller needs to manipulate the components in the view eg. setEnabled(), requestFocusInWindow() et cetera. Since Netbeans makes our components private to the form, we provide proxies that are bound to the actual components using reflection. We call them "adapters" because they give JTextField, JComboBox et al, a unified interface eg. QInputComponent. These adapters support the binding of the components to the presentation model.

Separating the view and controller in this fashion is fairly tedious, but hopefully enables separation of concerns, and improves testability eg. where we can mock up our view to facilitate the test-driven development of our controller. This is something i know nothing about, but i suspect is well important!?

Anyway, here is a sneak preview.

Launch   (PersonInfo, 150k/400k, unsandboxed, Java6)

http://weblogs.java.net/blog/evanx/archive/personalInfoForm700.png

You can refresh the "BeanInfo" tab (and also the "Console" tab) to see that the values entered into our form are written to our Presentation Model.

http://weblogs.java.net/blog/evanx/archive/personalInfoBean.png

In this demo, we use QLayout which isGroupLayout therapy for simple subpanels.