6. Layout Managers

6.1. Definition

A layout manager is an object that controls the size and the position of components in a container. Every Container object has a LayoutManager object that controls its layout.

6.2. AWT has 5 Layout Managers classes

  1. FlowLayout

  2. GridLayout

  3. BorderLayout

  4. CardLayout

  5. GridBagLayout

6.3. General Rules for Using Layout Managers

6.3.1. Default Managers

  • For JPanel objects, the default layout manager is an instance of the FlowLayout class.

  • For JFrame objects, the default layout manager is an instance of the BorderLayout class.

This layout manager is automatically consulted every time the Container might need to change its appearance.

6.3.2. How to Create a Layout Manager and Associate It with a Container

  • To use the default layout manager: Don't do anything. The constructor for each Container creates a layout manager instance and initializes the Container to use it.

  • To use a non-default layout manager: Create an instance of the desired layout manager class and tell the Container to use it:

    aContainer.setLayout(new CardLayout());

6.3.3. Methods that result in calls to the Container's layout manager

  1. add(), remove(), removeAll() - They add and remove Components from a Container; you can call them at any time.

  2. doLayout() - Is called as the result of any paint request to a Container. It requests that the Container place and size itself and the Components it contains.

  3. getPreferredSize(), getMinimumSize(), getMaximumSize() - They return the Container's ideal size, minimum size and maximum size, respectively. The values returned are just hints; they have no effect unless your program enforces these sizes.

Figure 10.20. BorderLayout

BorderLayout

Figure 10.21. BorderLayout Expanded

BorderLayout Expanded

6.4.1. Behavior

A BorderLayout has five areas: north, south, east, west, and center.

If you enlarge the window, you'll see that the center area gets as much of the newly available space as possible. The other areas expand only as much as necessary to keep all available space filled.

6.4.2. Code Example

setLayout(new BorderLayout());
setFont(new Font("Helvetica", Font.PLAIN, 14));
             
add(new JButton("North"), BorderLayout.NORTH);
add(new JButton("South"), BorderLayout.SOUTH);
add(new JButton("East"), BorderLayout.EAST);
add(new JButton("West"), BorderLayout.WEST);
add(new JButton("Center"), BorderLayout.CENTER);
[Note]Note

When adding a component to a container that uses BorderLayout, you must use the two-argument version of the add() method, and the second argument must be any of the constants showed in the code example. If you use the one-argument version of add(), or if you specify an invalid first argument, your component might not be visible.

To add a gap between the components you can use the constructor:

public BorderLayout(int horizontalGap, int verticalGap)

Figure 10.22. CardLayout: Buttons

CardLayout: Buttons

Figure 10.23. CardLayout: TextField

CardLayout: TextField

6.5.1. Behavior

The CardLayout class manages two or more components that share the same display space. Conceptually, each component is like a playing card in a stack, where only the top card is visible at any time.

6.5.2. Code Example

    private final static String BUTTON_PANEL = "Panel with Buttons";
    private final static String TEXT_PANEL = "Panel with TextField";
    
    private JPanel cards;
    private JComboBox cbox;

    ...

    // Create the panels
    JPanel p1 = new JPanel();
    p1.add(new JButton("Button 1"));
    p1.add(new JButton("Button 2"));
    p1.add(new JButton("Button 3"));
    
    JPanel p2 = new JPanel();
    p2.add(new JTextField("TextField", 20));
    
    // Where the container is initialized
    cards = new JPanel();
    cards.setLayout(new CardLayout());
    cards.add(BUTTON_PANEL, p1);
    cards.add(TEXT_PANEL, p2);
    
    // Create a combobox to choose between the cards
    cbox = new JComboBox();
    cbox.addItem(BUTTON_PANEL);
    cbox.addItem(TEXT_PANEL);
    cbox.addActionListener(this);
    
    // Put the combo box in a panel to get a nicer look
    JPanel panel = new JPanel();
    panel.add(cbox);
    
    // Put it all together
    setLayout(new BorderLayout());
    add(panel, BorderLayout.NORTH);
    add(cards, BorderLayout.CENTER);

    ...

    // The code for the ActionListener implementation
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == cbox) {
            String option = (String) cbox.getSelectedItem();
            CardLayout layout = (CardLayout) cards.getLayout(); 
            layout.show(cards, option);
        }    
    }

6.5.3. Methods to chose a component

public void first(Container parent)
public void next(Container parent)
public void previous(Container parent)
public void last(Container parent)
public void show(Container parent, String name)

Figure 10.24. FlowLayout

FlowLayout

Figure 10.25. FlowLayout: Expanded

FlowLayout: Expanded

6.6.1. Behaviour

FlowLayout puts components in a row, sized at their preferred size. If the horizontal space in the container is too small to put all the components in one row, FlowLayout uses multiple rows.

6.6.2. Code Example

setLayout(new FlowLayout());
setFont(new Font("Helvetica", Font.PLAIN, 14));
             
add(new JButton("Button 1"));
add(new JButton("2"));
add(new JButton("Button 3"));
add(new JButton("Long-Named Button 4"));
add(new JButton("Button 5"));

6.6.3. FlowLayout constructors

public FlowLayout()
public FlowLayout(int alignment)
public FlowLayout(int alignment, int horizontalGap, int verticalGap)

Alignment argument must have the value:

FlowLayout.LEFT, FlowLayout.CENTER, or FlowLayout.RIGHT

Figure 10.26. GridLayout

GridLayout

Figure 10.27. GridLayout: Expanded

GridLayout: Expanded

6.7.1. Behaviour

GridLayout places components in a grid of cells. Each component takes all the available space within its cell, and each cell has exactly the same size. If the GridLayout window is resized, the GridLayout changes the cell size so that the cells are as large as possible.

6.7.2. Code Example

// Construct a GridLayout with 2 columns and an unspecified number of rows
setLayout(new GridLayout(0, 2));
setFont(new Font("Helvetica", Font.PLAIN, 14));
             
add(new JButton("Button 1"));
add(new JButton("2"));
add(new JButton("Button 3"));
add(new JButton("Long-Named Button 4"));
add(new JButton("Button 5"));

6.7.3. GridLayout constructors

public GridLayout(int rows, int columns)
public GridLayout(int rows, int columns, int horizontalGap, int verticalGap)

Figure 10.28. GridBagLayout

GridBagLayout

Figure 10.29. GridBagLayout: Expanded

GridBagLayout: Expanded

6.8.1. Behaviour

GridBagLayout places components in a grid of rows and columns, allowing specified components to span multiple rows or columns. Not all rows or columns have to have the same height or width.

6.8.2. Specifying Constraints

GridBagLayout specifies the size and position characteristics of its components by specifying constraints for each component:

GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
setLayout(gridbag);

// For each component to be added to this container:

// Create the component
JButton button = new JButton("Button");

// Set instance variables in the GridBagConstraints instance
constraints.fill = GridBagConstraints.BOTH;
constraints.gridheight = 2;
constraints.weighty = 1.0;

// Add the component with the constraints
add(button, constraints);

GridBagConstraints instance variables:

gridx, gridy, gridwidth, gridheight, fill, ipadx, ipady,
insets, anchor, weightx, weighty.

6.8.3. Code Example

    // Set the layout and create the constraints object
    setLayout(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();
    
    // Define the common constraints
    c.fill = GridBagConstraints.BOTH;
    c.weightx = 1.0;
    c.weighty = 1.0;
                    
    // Create the components
    JButton b1 = new JButton("Button1"); // Row 0, Col 0
    add(b1, c);
    
    JButton b2 = new JButton("Button2"); // Row 0, Col 1
    c.gridx = 1;  
    add(b2, c);
    
    JButton b3 = new JButton("Button3"); // Row 0, Col 2 
    c.gridx = 2;        
    add(b3, c);
    
    JButton b4 = new JButton("Button4"); // Row 0, Col 3
    c.gridx = 3;          
    add(b4, c);
    
    JButton b5 = new JButton("Button5"); // Row 1, Col 0, Width 4 
    c.gridy = 1;
    c.gridx = 0;
    c.gridwidth = 4;
    add(b5, c);
    
    JButton b6 = new JButton("Button6"); // Row 2, Col 0, Width 3
    c.gridy = 2;
    c.gridx = 0;
    c.gridwidth = 3;        
    add(b6, c);
    
    JButton b7 = new JButton("Button7"); // Row 2, Col 3, Width 1
    c.gridx = 3;
    c.gridwidth = 1;
    add(b7, c);
    
    JButton b8 = new JButton("Button8"); // Row 3, Col 0, Height 2
    c.ipady = 20; // Make the component taller
    c.gridy = 3;
    c.gridx = 0;
    c.gridheight = 2;
    add(b8, c);
    
    JButton b9 = new JButton("Button9"); // Row 3, Col 1, Height 1
    c.ipady = 0; // Reset the default value
    c.gridy = 3;
    c.gridx = 1;
    c.gridwidth = 3;
    c.gridheight = 1;
    add(b9, c);
    
    JButton b10 = new JButton("Button10"); // Row 4, Col 1
    c.ipady = 40; // Make the component taller
    c.gridy = 4; 
    add(b10, c);

Figure 10.30. Custom Layout

Custom Layout

Figure 10.31. Custom Layout: Expanded

Custom Layout: Expanded

6.9.1. To create a new Layout Manager

A layout manager has just to implement the LayoutManager Interface.

6.9.2. The LayoutManager interface

  • public void addLayoutComponent(String name, Component comp)

    Called only by the Container add(name, component) method. Layout managers that don't require that their components have names generally do nothing in this method.

  • public void removeLayoutComponent(Component comp) 

    Called by the Container remove() and removeAll() methods. Layout managers that don't require that their components have names generally do nothing in this method, since they can query the container for its components using the Container getComponents() method.

  • public Dimension preferredLayoutSize(Container parent)

    Called by the Container getPreferredSize() method. This method should calculate the ideal size of the parent, assuming that the components it contains will be at or above their preferred sizes.

  • public Dimension minimumLayoutSize(Container parent)

    Called by the Container minimumSize() method. This method should calculate the minimum size of the parent, assuming that the components it contains will be at or above their minimum sizes.

  • public void layoutContainer(Container parent)

    Called when the container is first displayed, and every time its size changes. A layout manager's layoutContainer() method doesn't actually draw Components. It simply invokes each Component's resize(), move(), and reshape() methods to set the Component's size and position.

Figure 10.32. No Layout Manager

No Layout Manager

Figure 10.33. No Layout Manager: Expanded

No Layout Manager: Expanded

6.10.1. If possible use a Layout Manager

Layout managers make it easy to resize a container and adjust to platform-dependent component appearance and to different font sizes. They also can be reused easily by other containers and other programs.

6.10.2. Absolute Positioning Code Example

public class NoneWindow extends Frame {
    private boolean laidOut = false;
    private JButton b1, b2, b3;

    public NoneWindow() {
        super();
        setLayout(null);

        b1 = new JButton("one");
        b2 = new JButton("two");
        b3 = new JButton("three");

        add(b1);
        add(b2);
        add(b3);
    }

    public void paint(Graphics g) {
        if (!laidOut) {
            Insets insets = insets();
            b1.reshape(50 + insets.left, 5 + insets.top, 50, 20);
            b2.reshape(70 + insets.left, 35 + insets.top, 50, 20);
            b3.reshape(130 + insets.left, 15 + insets.top, 50, 30);
            laidOut = true;
        }
    }
 
    . . .
}