Title: layout
Course: CPS 161: An Intro to Programming with Java - DL MM MASTER

Layout Managers

In general, Container classes have default layout managers. The Frame class uses a BorderLayout manager and the Panel class (Applet is derived from Panel) uses a FlowLayout manager.

When you want to create a different layout manager, you use the setLayout method from the Container class. If you pass a null to setLayout, you are basically saying you want to take complete control of positioning your Components within the Container.

In order to position your Components, you call setBounds with the desired coordinates for each Component that needs to be positioned. You can call setBounds in the paint method or in some initialization routine such as init in the case of an Applet.

When you do, you have to specify the locations for each of your components. Normally, this is not recommended because of the different platforms that you may want to be running on. If you take this approach, you have to figure out the pixel locations for each of your components. Keep in mind these Components can have different sizes on different platforms.

None.java

None.java


//None : No Layout manager used
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class None extends JApplet {
    private JButton b1, b2, b3;
    int count = 0;

    public void init() {
        Container container = getContentPane();
        container.setLayout(null);

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

        b1.setBounds(50,  5,  100, 30);
        b2.setBounds(70,  45, 100, 30);
       // b3.setBounds(130, 100, 80, 100);
    }

    public void paint(Graphics g) {
         b3.setBounds(130, 100, 80, 100);
         System.out.println("paint called, count = " + count++);
    }

}


Calculator Logic

We are going to create the beginning of a calculator. Most of the calculator code will stay the same, but we will demonstrate how it looks under different Layout Managers.

Note that for each button that we want to respond to, we need to call the addActionListener routine.

Also in the actionPerformed routine, we need to find out which button was clicked. To do this, we need to investigate the ActionEvent class passed into this routine.

The ActionEvent has 2 useful routines:
getSource - returns the instance of the Object that made the actionPerformed call. We will use this for determining if the clear, plus or equals buttons where clicked.

getActionCommand() - return the text on the button that was clicked. We are using this for the 10 digits.

FlowLayout Manager

The FlowLayout Manager places components into your container from left to right and when it gets the the right hand side, it will start a new "row" and repeat the process.

To get a feel for how this process works, take this code and run it from the command line. Resize your container and see how the FlowLayout manager reacts to each of your containers sizes.

Like many Layout Mangers, you can alter the strategy a little by using the different constructors. For example, modify the following example by using constructors such as:

new FlowLayout(FlowLayout.CENTER /* alignment */);

new FlowLayout(FlowLayout.RIGHT);

//30 is the horizontal gap in pixels
//20 is the vertical gap in pixels
new FlowLayout(FlowLayout.CENTER, 30, 20);

CalcFlow.java

CalcFlow.java


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



public class CalcFlow extends JApplet
        implements ActionListener {
    JButton bdigit[] = new JButton[10];
    JButton clear = new JButton("clear");
    JButton plus = new JButton("   +   ");
    JButton equals = new JButton("   =   ");

    JTextField display = new JTextField(30);

    public void init() {
    // FlowLayout is what you get by default for the
    // Panel class or the Applet which is derived form Panel

        Container container = getContentPane();
        container.setLayout(new FlowLayout());

        //For Fun, see what GridLayout does --- we will
        // look at this in more detail later.
        //setLayout(new GridLayout(4,0));

        container.add(display);
        for (int i=0; i < bdigit.length; i++)
        {
            bdigit[i] = new JButton("" + i);
            container.add(bdigit[i]);
            bdigit[i].addActionListener(this);
        }
        container.add(clear);
        clear.addActionListener(this);
        container.add(plus);
        plus.addActionListener(this);
        container.add(equals);
        equals.addActionListener(this);

    }
    public void actionPerformed(ActionEvent e) {
       if (e.getSource() == clear)
       {
            display.setText("");
       }
       else if (e.getSource() == plus)
       {
         // logic needs to be filled in
       }
       else if (e.getSource() == equals)
       {
         // logic needs to be filled in
       }

       else
       {    // Must be a digit
            String str = e.getActionCommand();
            String str_display = display.getText();
            display.setText( str_display + str);
       }

    }


  public static void main(String[] args) {
    CalcFlow applet = new CalcFlow();
    JFrame aFrame = new JFrame("CalcFlow");

    aFrame.add(applet);
    aFrame.setSize(600,250);
    // Normally the following call comes from the Browser
    applet.init();

    aFrame.setVisible(true);
  } // end of main
}


BorderLayout

The BorderLayout can take upto 5 components. There is a slightly different add routine with 2 parameters where you specify where you want each of your components: North, South, East, West, and Center.

This may seem quite unusual, but the BorderLayout is especially useful in combination with other layout managers as you will see next.

In the following example we throw 5 buttons into a BorderLayout Container. Try running this from the command line and resize the window. Notice that the outer boundaries (North, South, East and West) will try to take just enough space to print out their components. The Center on the hand grows to fill in whatever space is left over.

You might want to try out the other constructor:
// 20 is the horizontal gap in pixes, 30 is the vertical gap in pixels
new BorderLayout (20, 30);

Normally BorderLayouts are used to have the Center be the main activity area, and the borders contain toolbar activity. By the way, you don't have to have any of the outer border components. You can choose to have 0, 1,2,3 or 4 outer border areas.

SimpleBorder.java

SimpleBorder.java


import java.awt.*;

import javax.swing.*;


public class SimpleBorder extends JApplet {
    public void init() {
        Container container = getContentPane();
        container.setLayout(new BorderLayout());
        container.add("North",
            new JButton("North"));
        container.add("South",
            new JButton("South"));
        container.add("East",
            new JButton("East"));
        container.add("West",
            new JButton("West"));
        container.add("Center",
            new JButton("Center"));
    }

  public static void main(String[] args) {
    SimpleBorder applet = new SimpleBorder();
    JFrame aFrame = new JFrame("SimpleBorder");

    aFrame.add(applet);
    aFrame.setSize(600,250);
    // Normally the following call comes from the Browser
    applet.init();

    aFrame.setVisible(true);
  } // end of main
}


Panel Class - More structure

Remember that a Panel is derived from Container, and a Container is derived from Component. This implies that a Panel is a Component. So I can add a Panel any place where I could have added a Component.

But a Panel can also Contain other Components. Hence we can use the Panel as a way to create more sophisticated Layout heirarchies. In the following example, we will create a BorderLayout with just a North and a Center Component. The Center Component will be a simple TextArea Component that fills the bulk of the Screen area.

In the North Component, we will add a Panel called controlPanel. We will also add 3 buttons to the controlPanel. Take a look at the end result below and click on the buttons in the North controlPanel.

MyPanel.java

MyPanel.java



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


public class MyPanel extends JApplet
                        implements ActionListener {

   JPanel controlPanel = new JPanel();
   JTextArea text = new JTextArea("Initial Text", 25, 80);
   JButton red = new JButton("red");
   JButton blue = new JButton("blue");
   JButton green = new JButton("green");
   final int whiteness = 150;
   Color light_red = new Color(255, whiteness, whiteness);
   Color light_blue = new Color(whiteness, whiteness, 255);
   Color light_green = new Color(whiteness, 255, whiteness);

    public void init( ) {
       Container container = getContentPane();
       container.setLayout(new BorderLayout());

       red.setBackground(light_red);
       blue.setBackground(light_blue);
       green.setBackground(light_green);

       red.addActionListener(this);
       blue.addActionListener(this);
       green.addActionListener(this);

       // default text to red
       text.setBackground(Color.green);

       // Buttons added to the extra Panel
       controlPanel.add(red);
       controlPanel.add(green);
       controlPanel.add(blue);

       container.add("North", controlPanel);
       container.add("Center", text);
    }

    public void actionPerformed(ActionEvent evt) {
       if (evt.getSource() == red)
           text.setBackground(light_red);
       if (evt.getSource() == green)
           text.setBackground(light_green);
       if (evt.getSource() == blue)
           text.setBackground(light_blue);

    }

}


GridLayout

A GridLayout allows you to create a grid for your components. In the Grid, all Components will get the same width and height. If you look at the example, below you can see that sometimes this constraint can be a problem --- note the button with the long string and the TextArea that seems somewhat squeezed.

The parameters to a GridLayout normally include the number of rows, followed by the number of columns. If you are too lazy to count the number of components, you can specify one of the parameters as zero. In the example below, we are specifying that we want 3 columns. The number of rows will be determined by the number of components that we add to the Grid.

Of course, there is also another constructor for Grid which allows you to specify the horizontal gap and vertical gap:
new Grid(0, 3, 20, 30);// Try it out

SimpleGrid.java

SimpleGrid.java


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


public class SimpleGrid extends JApplet {
    public void init() {
        Container container = getContentPane();
        container.setLayout(new GridLayout(0,3));
        container.add( new JButton("1"));
        container.add( new JButton("2"));
        container.add( new JButton("As far as the East is from the West"));
        container.add( new JButton("3"));
        container.add( new JButton("4"));
        container.add( new JButton("5"));
        container.add( new JTextArea(10, 10));
    }

  public static void main(String[] args) {
    SimpleGrid applet = new SimpleGrid();
    JFrame aFrame = new JFrame("SimpleGrid");

    aFrame.add(applet);
    aFrame.setSize(600,250);
    // Normally the following call comes from the Browser
    applet.init();

    aFrame.setVisible(true);
  } // end of main
}


GridLayout - BorderLayout Combination

As promised earlier, the BorderLayout works well in combinations with other Layout Managers using the Panel class. The following example uses a BorderLayout with a Center and a North section. The TextField goes in the North for our Calculator. The Center becomes another Panel that is laid out with a GridLayout for all of the buttons.

CalcGrid.java (GridLayout + BorderLayout)

CalcGrid.java


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



public class CalcGrid extends  JApplet
        implements ActionListener {
    JButton bdigit[] = new JButton[10];
    JButton clear = new JButton("clear");
    JButton plus = new JButton("   +   ");
    JButton equals = new JButton("   =   ");

    JTextField display = new JTextField(30);

    public void init() {
        Container container = getContentPane();
        container.setLayout(new BorderLayout());
        setBackground(Color.green);
        container.add("North", display);

        // All the buttons go into a Panel
        JPanel bPanel = new JPanel();

        // Panel will use a GridLayout Manager.

        // There are a couple of different GridLayout constructors
        // available --- see them in online help
        // bPanel.setLayout(new GridLayout(0,4));
        bPanel.setLayout(new GridLayout(0,4,5,5));
        bPanel.setBackground(Color.yellow);

        Color buttonColor = new Color(180,180,255);
        for (int i=0; i < bdigit.length; i++)
        {
            bdigit[i] = new JButton("" + i);
            bPanel.add(bdigit[i]);
            bdigit[i].addActionListener(this);
            bdigit[i].setBackground(buttonColor);
        }
        bPanel.add(clear);
        clear.addActionListener(this);
        bPanel.add(plus);
        plus.addActionListener(this);
        bPanel.add(equals);
        equals.addActionListener(this);

        container.add("Center", bPanel);

    }
    public void actionPerformed(ActionEvent e) {
       if (e.getSource() == clear)
       {
            display.setText("");
       }
       else if (e.getSource() == plus)
       {

       }
       else if (e.getSource() == equals)
       {

       }

       else
       {    // Must be a digit
            String str = e.getActionCommand();
            String str_display = display.getText();
            display.setText( str_display + str);
       }

    }


  public static void main(String[] args) {
    CalcGrid applet = new CalcGrid();
    JFrame aFrame = new JFrame("CalcGrid");

    aFrame.add(applet);
    aFrame.setSize(600,250);
    // Normally the following call comes from the Browser
    applet.init();

    aFrame.setVisible(true);
  } // end of main
}


GridBagLayout Manager

So the GridLayout is simple but very constraining --- each component is displayed with the same width and height. You need something more flexible. Well you got it, but flexibility is usually associated with complexity, and that is the biggest problem with the GridBagLayout manager.

For those of you who understand how to use all of the flexibility in HTML tables to control how your HTML page is laid out, you might appreciate GridBagLayout, because it has many of the same features as you find in HTML table commands.

How does it work?

1. The first step is to create an instance of GridBagLayout and call setLayout just like we did with all of the other Layout managers above.
2. The next step is to recognize that each component added can have its own unique constraints specified. So to do this we need an instance of a new class called the GridBagConstraints class.
3. The GridBagConstraints class has many constraints that can be specified. See the following table:
GridBagConstraints Table . We will only use a few of these features here.
4. Once you have the constraints class setup (note that anything not specified has a default) and you have created your component, you tell the GridBagLayout manager with a call that looks like:
gblay.setConstraints(c, gbc);
where gblay is the instance of the GridBagLayout manager, c is the component of interest and gbc is the GridBagConstraints class containing the values of all the applicable constraints.
5. Then you just add the component to the Container just like any of the previous Layout Managers.

Note that because of the flexibility, the GridBagLayout allows each column to have its own width, and each row can have its own height.

To hide most of the complexity below we create a method called gbadd that takes care of all of the constraint stuff. Also note that we are mostly using the width constraint (there are many other constraints). The gbadd routine takes a parameter to specify the width. A 1 implies one column width, while a 2 indicates that component spans two columns. A -1 on the other hand indicates that this component marks the end of a row.

We do set a few constraints for all components added to the GridBagLayout.

CalcGridBag.java

CalcGridBag.java



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



public class CalcGridBag extends  JApplet
        implements ActionListener {
    JButton bdigit[] = new JButton[10];
    JButton clear = new JButton("clear");
    JButton minus = new JButton("   -   ");
    JButton plus =  new JButton("   +   ");

    JButton equals = new JButton("   =   ");

    JTextField display = new JTextField(30);
    GridBagLayout gblay = new GridBagLayout();
    GridBagConstraints gbc = new GridBagConstraints();
    final int numCols = 4;
    int colCount = 0;

    // GridBag add routine to take care
    // of some of the ugly details.

    void gbAdd(Component c, int width)
    {
        if (width < 0)
        {
            // Make this component the end of the row
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            colCount = 0;
        }
        else
        {
            colCount += width;
            if (colCount >= numCols)
            {
                // Make this component the end of the row
                gbc.gridwidth =  GridBagConstraints.REMAINDER;
                colCount = 0;
            }
            else
            {
                // Provide the requested Width
                gbc.gridwidth = width;
            }
        }

        // Finally tell Gridbaglayout about the constraints
        // associated with this Component
        gblay.setConstraints(c, gbc);

        add(c); // add to the container
    }


    public void init() {
        // Fill in a few constraints
        gbc.weightx = gbc.weighty =1.0;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets(3,3,3,3);

        Container container = getContentPane();
        container.setLayout(gblay);
        setBackground(Color.yellow);

        gbAdd(display, -1); // Line by itself

        Color buttonColor = new Color(180,180,255);
        for (int i=0; i < bdigit.length; i++)
        {
            bdigit[i] = new JButton("" + i);
            bdigit[i].addActionListener(this);
            bdigit[i].setBackground(buttonColor);
            gbAdd(bdigit[i], 1);
        }

        clear.addActionListener(this);
        gbAdd(clear, 1);

        minus.addActionListener(this);
        gbAdd(minus, 1);

        gbAdd(plus, 2);
        plus.addActionListener(this);

        gbAdd(equals, 2);
        equals.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
       if (e.getSource() == clear)
       {
            display.setText("");
       }
       else if (e.getSource() == plus)
       {

       }
       else if (e.getSource() == minus)
       {

       }

       else if (e.getSource() == equals)
       {

       }

       else
       {    // Must be a digit
            String str = e.getActionCommand();
            String str_display = display.getText();
            display.setText( str_display + str);
       }

    }


  public static void main(String[] args) {
    CalcGridBag applet = new CalcGridBag();
    JFrame aFrame = new JFrame("CalcGridBag");

    aFrame.add(applet);
    aFrame.setSize(300,250);
    // Normally the following call comes from the Browser
    applet.init();

    aFrame.setVisible(true);
  } // end of main
}


CardLayout Manager

The CardLayout manager lets you have different views of your screen that are like independant Cards that can be displayed. For example, in the following example, we have 3 Cards (or Panels of Gui stuff). At any point in time, we only display one Card at a time.

A Card is defined to be a Component, but it is more likely to be a Panel (remember a Panel is derived from Component).

In the example below we create 3 cards with names. The cards are added to the container along with their associated names. The 3 cards contain:

- Panel panelFor3Buttons - contains 3 buttons
- Panel panelForText - contains a TextField and a button
- Single Button Component

When we want to show a specific card, we call the show method. The first parameter to show is a pointer to the container, which is our Applet itself. The second parameter is the name of the card to show.

Wizard.java - A Card Layout

Wizard.java



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


public class Wizard extends JApplet
                        implements ActionListener {

   CardLayout cardLayoutMgr = new CardLayout();
   Container container;
   JPanel panelForText = new JPanel();
   JPanel panelFor3Buttons = new JPanel();
   String BUTTONPANEL="ButtonPanel";
   String TEXTPANEL="TextPanel";
   String SINGLE_BUTTON="ButtonComponent";

   JButton next1 = new JButton("Next 1");
   JButton next2 = new JButton("Next 2");
   JButton next3 = new JButton("Next 3");

  public void init( ) {
       container = getContentPane();
       container.setLayout(cardLayoutMgr);
       setBackground(Color.yellow);

       next1.setBackground(Color.red);
       next2.setBackground(Color.red);
       next3.setBackground(Color.red);

       next1.addActionListener(this);
       next2.addActionListener(this);
       next3.addActionListener(this);

   // Build up Panel : panelFor3Buttons
       panelFor3Buttons.add(new Button("Button 1"));
       panelFor3Buttons.add(new Button("Button 2"));
       panelFor3Buttons.add(next1);
       panelFor3Buttons.setBackground(Color.green);

   // Build up Panel : panelForText
       panelForText.add(new TextField("TextField", 20));
       panelForText.add(next2);
       panelForText.setBackground(Color.orange);

     // Finally add the 3 "Cards" to the CardLayout Manager
     // Note that each card only needs to be a Component.
     // A Button is OK, and a Panel is OK too.

       container.add(BUTTONPANEL, panelFor3Buttons);
       container.add(TEXTPANEL, panelForText);
       container.add(SINGLE_BUTTON, next3);
       setBackground(Color.pink);

       // Tell the cardLayout Manager to start with the 3 button panel
       cardLayoutMgr.show(container, BUTTONPANEL);

    }

  public void actionPerformed(ActionEvent evt) {
       if (evt.getSource() == next1)
           cardLayoutMgr.show(container, TEXTPANEL);
        if (evt.getSource() == next2)
                cardLayoutMgr.show(container, SINGLE_BUTTON);
        if (evt.getSource() == next3)
                cardLayoutMgr.show(container, BUTTONPANEL);

    }

  public static void main(String[] args) {
    Wizard applet = new Wizard();
    JFrame aFrame = new JFrame("Wizard");

    aFrame.add(applet);
    aFrame.setSize(300,150);
    // Normally the following call comes from the Browser
    applet.init();

    aFrame.setVisible(true);
  } // end of main


}


Exercises

1. Create a calculator that can switch between a Hex calculator and a regular calculator. The overall applet should be a border layout. The south should be 2 radio buttons to determine hex or regular calculator. In the Center, have a CardLayout where you have 2 Panels. One for the Hex calculator, and the other for the regular calculator. Each of the 2 Panels should similar to one of the above calculators above. In fact, it might be good to create a class similar to the above derived from JPanel instead of JApplet. Maybe add a method called
void configure(boolean hexMode)
2. Create a Drawing program as a JPanel in the Center of a Border layout. On the North create a JPanel with radio buttons to choose the shape. On the south create a JPanel with radio buttons to choose the color. Initially, just have the center panel do something simple, later plug in the previous drawing program that we created as a class derived from JPanel.

Last Updated: April 13, 2008 3:01 PM