Using KappaLayout and LambdaLayout in Conjunction with the Java Look and Feel Design Guidelines

Explanation of perfect and stretchable layouts.

User interfaces constructed with Java components can be classified into two varieties: perfect and stretchable.

Perfect layouts are those in which each component is always displayed at its preferred size, the containing window is sized precisely to be just the size to hold the components, and the containing window does not allow (or does not need) resizing. There are one or two exceptions to displaying the components at the preferred size. One is command buttons, in that groups of command buttons look best when the buttons are aligned and all are the same size. A perfect layout compensates for this desired layout by choosing the button with the largest preferred size and making all other buttons in the group the same size as that button. The other exception is text components, which tend to have a preferred size that is inadequate for human users to perform text entry. Text components should be stretched to align visually with other components and to present a large enough area for the user to enter text.

Stretchable layouts are those in which it is desirable for some or all of the components in the container to be able to resize as the container resizes. An example is a window that contains a text area. It may be desirable for the text area to grow larger to display more text as the window is made larger. Other examples of components that might want to stretch to allow the user to see more of its contents are lists and trees. Usually a stretchable layout has some components that do not want to be stretched, such as command buttons, so a stretchable layout needs to be able to accomodate these kinds of components as well.

KappaLayout is the best choice for a perfect layout as it pays close attention to the preferred sizes of components. It can cause a component to be stretched for particular purposes, as in the example of command buttons that should be the same size. KappaLayout only allows components to be stretched once during initial layout, thereafter, the component does not change size regardless of size changes in the parent container.

LambdaLayout is the best choice for a stretchable layout as it allows components to stretch or shrink as the parent container is resized. LambdaLayout also pays close attention to the preferred sizes of components and will not allow components to be shrunk to less than the preferred size.

Often there are parts of a layout that should be stretchable and parts that should not. In these cases, a combination of the two layout managers should be used along with the nested panels technique.

A Practical Example.

The following code example shows how to construct the "Find" dialog as shown in Figure 30 of the Java Look and Feel Design Guidelines. This is a 'perfect' layout. The dialog is designed using the design grid method. This figure shows what the dialog will look like when displayed and the design parameters for laying out the components. The red lines are KappaLayout struts and are invisible in the displayed dialog. These struts are rigid, that is, they set the width or height of the column or row to a fixed size. Four of the columns from the design grid are not necessary so are not used. Columns and rows are numbered and are used to set the constraints for each component.

find_design

 

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

/*
This displays a "find" dialog as is shown in Figure 30 in the Java Look
and Feel Design Guidelines.  This class shows how to use KappaLayout to create
this layout while conforming exactly to the guidelines.
*/

public class Figure30 {

   public Figure30() {
      // set up a JFrame
      JFrame f = new JFrame("Figure30");
      f.addWindowListener(new WindowAdapter() {
                             public void windowClosing(WindowEvent we) {
                                f.dispose();
                             }
                          });

      /*
      create the content pane and its layout manager. Use our own JPanel rather 
      than the default container so we can set a javax.swing.border and use a 
      KappaLayout rather than the default BorderLayout (the default content pane
      for a JFrame uses a BorderLayout. In fact, the default content pane is a 
      JPanel, but would need to be cast as such to be useable as a JPanel.)
      */
      KappaLayout kl = new KappaLayout();
      JPanel contents = new JPanel(kl);
      f.setContentPane(contents);

      /*
      set an EmptyBorder on our content panel to create the desired blank
      space around the contained components. See text accompanying Figure 76
      in the Java Look and Feel Guidelines -- the guideline is 12 pixels spacing
      on top and left, 11 pixels on right and bottom.  The EmptyBorder does
      this nicely. An alternate method (suitable for AWT only layouts) is to
      override the getInsets method. 
      
          Panel contents = new Panel(kl) {
             Insets insets = new Insets(12, 12, 11, 11);
             public Insets getInsets() {
                return insets;
             }
          };
          
      KappaLayout is one of the few layout managers that respect the insets of 
      a container.    
      */
      contents.setBorder(new EmptyBorder(12, 11, 11, 12));

      /*
      add the components, following the design grid. Constraint string follows
      this pattern: "x, y, w, h, a, s, p" where 
         x is start column of component
         y is start row of component
         w is width of component in columns
         h is height of component in rows
         a is alignment in cell
         s is stretch parameter
         p is padding around component in pixels
      All parameters have defaults and all parameters are optional. See
      KappaLayout documentation for details of the constraint string.
      */
      // align label to right side of cell
      contents.add(new JLabel("Find:"),              "0, 0, 1, 1, 3");    
      // stretch text field to fit across 3 columns
      contents.add(new JTextField(),                 "2, 0, 3, 1, 0, w"); 
      // align check boxes and radio buttons to left side of cell
      contents.add(new JCheckBox("Match Case"),      "2, 2, 1, 1, 7");    
      contents.add(new JCheckBox("Whole Word"),      "2, 3, 1, 1, 7");    
      contents.add(new JRadioButton("Start at Top"), "4, 2, 1, 1, 7");    
      contents.add(new JRadioButton("Wrap Around"),  "4, 3, 1, 1, 7");    

      /*
      add some struts to ensure fixed separation between components follows
      the guidelines: 11 pixels between groups, 17 between bottom group and
      command buttons.
      */
      // strut to separate textfield and top checkbox             
      contents.add(KappaLayout.createVerticalStrut(11, true),   "0, 1");   
      // strut to separate "Find:" label and textfield            
      contents.add(KappaLayout.createHorizontalStrut(11, true), "1, 1");   
      // strut to separate checkbox column and radio button column
      contents.add(KappaLayout.createHorizontalStrut(11, true), "3, 1");                
      // strut to separate bottom checkbox and command buttons    
      contents.add(KappaLayout.createVerticalStrut(17, true),   "0, 4");   
      
      /*
      use a separate panel for the buttons to properly align the
      buttons across the correct grids. This panel can stretch to the full
      width of the dialog, so will fit regardless of the text on the buttons.
      */
      KappaLayout kl2 = new KappaLayout();
      JPanel btn_panel = new JPanel(kl2);
      // stretch button to fill full width of cell            
      btn_panel.add(new JButton("Find"),                  "0, 0, 1, 1, , w");  
      // guidelines say to use 5 pixels between buttons
      btn_panel.add(KappaLayout.createHorizontalStrut(5), "1, 0, 1, 1");       
      // stretch button to fill full width of cell            
      btn_panel.add(new JButton("Close"),                 "2, 0, 1, 1, , w");  

      /*
      make the 2 columns holding the buttons the same width. KappaLayout finds
      the button with the widest preferred width, and uses that width for both
      columns. The 'w' parameter used in laying out the buttons lets the button
      with the smaller width of the 2 stretch to be the same size. This is
      exactly the layout specified by the guidelines.
      */
      kl2.makeColumnsSameWidth(0, 2);                                     

      /*
      add the button panel, Allow the panel to fill the full width of
      the dialog if needed, but align it to the right side and bottom of the 
      dialog as required by the guidelines
      */
      contents.add(btn_panel, "0, 5, 5, 1, 4");

      /*
      pack and show -- this is a 'perfect' dialog, that is, all components
      are laid out at their preferred size (or, in the case of the buttons,
      at the same size as the largest preferred size in the button group),
      inter-component spacing is fixed, and there is no need to stretch any
      component when resizing the dialog, so set the dialog to disallow
      resizing.
      */
      f.setResizable(false);
      f.pack();
      f.show();
   }

   public static void main(String[] args) {
      new Figure30();
   }
}

References.

The full Java Look and Feel Design guidelines can be found at:

http://java.sun.com/products/jlf/guidelines.html

The full guidelines cover quite a lot of material that does not directly apply to laying out user interfaces, so I've compiled an abbreviated guideline containing just the rules for how a user interface should be constructed. The abbreviated guidelines can be found at:

http://ise.fdns.net/freestuff/layouts/docs/guidelines.html

Documentation for both KappaLayout and LambdaLayout can be found at:

http://ise/fdns.net/freestuff/layouts/docs/

An excellent reference for constructing usable interfaces is "Software for Use" by Larry Constantine and Lucy Lockwood. See http://www.foruse.com for details.