Introduction to Layout Management

   


Before we go on to discussing individual Swing components, such as text fields and radio buttons, we briefly cover how to arrange these components inside a frame. Unlike Visual Basic, the JDK has no form designer. You need to write code to position (lay out) the user interface components where you want them to be.

Of course, if you have a Java-enabled development environment, it will probably have a layout tool that automates some or all of these tasks. Nevertheless, it is important to know exactly what goes on "under the hood" because even the best of these tools will usually require hand-tweaking.

Let's start by reviewing the program from the last chapter that used buttons to change the background color of a frame (see Figure 9-5).

Figure 9-5. A panel with three buttons


Let us quickly recall how we built this program:

  1. We defined the appearance of each button by setting the label string in the constructor, for example:

     JButton yellowButton = new JButton("Yellow") 

  2. We then added the individual buttons to a panel, for example, with

     panel.add(yellowButton); 

  3. We then added the needed event handlers, for example:

     yellowButton.addActionListener(listener); 

What happens if we add more buttons? Figure 9-6 shows what happens when you add six buttons to the panel. As you can see, they are centered in a row, and when there is no more room, a new row is started.

Figure 9-6. A panel with six buttons managed by a flow layout


Moreover, the buttons stay centered in the panel, even when the user resizes the frame (see Figure 9-7).

Figure 9-7. Changing the panel size rearranges the buttons automatically


An elegant concept enables this dynamic layout: all components in a container are positioned by a layout manager. In our example, the buttons are managed by the flow layout manager, the default layout manager for a panel.

The flow layout manager lines the components horizontally until there is no more room and then starts a new row of components.

When the user resizes the container, the layout manager automatically reflows the components to fill the available space.

You can choose how you want to arrange the components in each row. The default is to center them in the container. The other choices are to align them to the left or to the right of the container. To use one of these alignments, specify LEFT or RIGHT in the constructor of the FlowLayout object.

 panel.setLayout(new FlowLayout(FlowLayout.LEFT)); 

NOTE

Normally, you just let the flow layout manager control the vertical and horizontal gaps between the components. You can, however, force a specific horizontal or vertical gap by using another version of the flow layout constructor. (See the API notes.)



 java.awt.Container 1.0 

  • setLayout(LayoutManager m)

    sets the layout manager for this container.


 java.awt.FlowLayout 1.0 

  • FlowLayout(int align)

    constructs a new FlowLayout with the specified alignment.

    Parameters:

    align

    One of LEFT, CENTER, or RIGHT


  • FlowLayout(int align, int hgap, int vgap)

    constructs a new FlowLayout with the specified alignment and the specified horizontal and vertical gaps between components.

    Parameters:

    align

    One of LEFT, CENTER, or RIGHT

     

    hgap

    The horizontal gap to use in pixels (negative values force an overlap)

     

    vgap

    The vertical gap to use in pixels (negative values force an overlap)


Border Layout

Java comes with several layout managers, and you can also make your own layout managers. We cover all of them later in this chapter. However, to enable us to give you more interesting examples right away, we briefly describe another layout manager called the border layout manager. This is the default layout manager of the content pane of every JFrame. Unlike the flow layout manager, which completely controls the position of each component, the border layout manager lets you choose where you want to place each component. You can choose to place the component in the center, north, south, east, or west of the content pane (see Figure 9-8).

Figure 9-8. Border layout


For example:

 panel.setLayout(new BorderLayout()); panel.add(yellowButton, BorderLayout.SOUTH); 

The edge components are laid out first, and the remaining available space is occupied by the center. When the container is resized, the dimensions of the edge components are unchanged, but the center component changes its size. You add components by specifying a constant CENTER, NORTH, SOUTH, EAST, or WEST of the BorderLayout class. Not all of the positions need to be occupied. If you don't supply any value, CENTER is assumed.

NOTE

The BorderLayout constants are defined as strings. For example, BorderLayout.SOUTH is defined as the string "South". Many programmers prefer to use the strings directly because they are shorter, for example, frame.add(component, "South"). However, if you accidentally misspell a string, the compiler won't catch that error.


Unlike the flow layout, the border layout grows all components to fill the available space. (The flow layout leaves each component at its preferred size.)

As with flow layouts, if you want to specify a gap between the regions, you can do so in the constructor of the BorderLayout.

As previously noted, the content pane of a JFrame uses a border layout. Up to now, we never took advantage of this we simply added panels into the default (center) area. But you can add components into the other areas as well:

 frame.add(yellowButton, BorderLayout.SOUTH); 

However, this code fragment has a problem, which we take up in the next section.


 java.awt.Container 1.0 

  • void add(Component c, Object constraints) 1.1

    adds a component to this container.

    Parameters:

    c

    The component to add

     

    constraints

    An identifier understood by the layout manager



 java.awt.Borderlayout 1.0 

  • BorderLayout(int hgap, int vgap)

    constructs a new BorderLayout with the specified horizontal and vertical gaps between components.

    Parameters:

    hgap

    The horizontal gap to use in pixels (negative values force an overlap)

     

    vgap

    The vertical gap to use in pixels (negative values force an overlap)


Panels

A BorderLayout is not very useful by itself. Figure 9-9 shows what happens when you use the code fragment above. The button has grown to fill the entire southern region of the frame. And, if you were to add another button to the southern region, it would just displace the first button.

Figure 9-9. A single button managed by a border layout


One common method to overcome this problem is to use additional panels. Panels act as (smaller) containers for interface elements and can themselves be arranged inside a larger panel under the control of a layout manager. For example, you can have one panel in the southern area for the buttons and another in the center for text. By nesting panels and using a mixture of border layouts and flow layouts, you can achieve fairly precise positioning of components. This approach to layout is certainly enough for prototyping, and it is the approach that we use for the example programs in the first part of this chapter. See the section on the GridBagLayout later in this chapter for the most precise way to position components.

For example, look at Figure 9-10. The three buttons at the bottom of the screen are all contained in a panel. The panel is put into the southern region of the content pane.

Figure 9-10. Panel placed at the southern region of the frame


So, suppose you want to add a panel with three buttons as in Figure 9-10. First create a new JPanel object, then add the individual buttons to the panel. The default layout manager for a panel is a FlowLayout, which is a good choice for this situation. Finally, you add the individual buttons, using the add method you have seen before. Because you are adding buttons to a panel and haven't changed the default layout manager, the position and size of the buttons is under the control of the FlowLayout manager. This means the buttons stay centered within the panel, and they do not expand to fill the entire panel area.

Here's a code fragment that adds a panel containing three buttons in the southern region of a frame.

 JPanel panel = new JPanel(); panel.add(yellowButton); panel.add(blueButton); panel.add(redButton); frame.add(panel, BorderLayout.SOUTH); 

NOTE

The panel boundaries are not visible to the user. Panels are just an organizing mechanism for the user interface designer.


As you just saw, the JPanel class uses a FlowLayout as the default layout manager. For a JPanel, you can supply a different layout manager object in the constructor. However, most other containers do not have such a constructor. But all containers have a setLayout method to set the layout manager to something other than the default for the container.


 javax.swing.JPanel 1.2 

  • JPanel(LayoutManager m)

    sets the layout manager for the panel.

Grid Layout

The grid layout arranges all components in rows and columns like a spreadsheet. However, for a grid layout, cells are always the same size. The calculator program in Figure 9-11 uses a grid layout to arrange the calculator buttons. When you resize the window, the buttons grow and shrink, but all buttons have identical sizes.

Figure 9-11. A calculator


In the constructor of the grid layout object, you specify how many rows and columns you need.

 panel.setLayout(new GridLayout(5, 4)); 

As with the border layout and flow layout managers, you can also specify the vertical and horizontal gaps you want.

 panel.setLayout(new GridLayout(5, 4, 3, 3)); 

The last two parameters of this constructor specify the size of the horizontal and vertical gaps (in pixels) between the components.

You add the components, starting with the first entry in the first row, then the second entry in the first row, and so on.

 panel.add(new JButton("1")); panel.add(new JButton("2")); 

Example 9-1 is the source listing for the calculator program. This is a regular calculator, not the "reverse Polish" variety that is so oddly popular in Java tutorials. In this program, we call the pack method after adding the component to the frame. This method uses the preferred sizes of all components to compute the width and height of the frame.

Of course, few applications have as rigid a layout as the face of a calculator. In practice, small grids (usually with just one row or one column) can be useful to organize partial areas of a window. For example, if you want to have a row of buttons with identical size, then you can put the buttons inside a panel that is governed by a grid layout with a single row.

Example 9-1. Calculator.java
   1. import java.awt.*;   2. import java.awt.event.*;   3. import javax.swing.*;   4.   5. public class Calculator   6. {   7.    public static void main(String[] args)   8.    {   9.       CalculatorFrame frame = new CalculatorFrame();  10.      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  11.      frame.setVisible(true);  12.   }  13. }  14.  15. /**  16.    A frame with a calculator panel.  17. */  18. class CalculatorFrame extends JFrame  19. {  20.    public CalculatorFrame()  21.    {  22.       setTitle("Calculator");  23.       CalculatorPanel panel = new CalculatorPanel();  24.       add(panel);  25.       pack();  26.    }  27. }  28.  29. /**  30.    A panel with calculator buttons and a result display.  31. */  32. class CalculatorPanel extends JPanel  33. {  34.    public CalculatorPanel()  35.    {  36.       setLayout(new BorderLayout());  37.  38.       result = 0;  39.       lastCommand = "=";  40.       start = true;  41.  42.       // add the display  43.  44.       display = new JButton("0");  45.       display.setEnabled(false);  46.       add(display, BorderLayout.NORTH);  47.  48.       ActionListener insert = new InsertAction();  49.       ActionListener command = new CommandAction();  50.  51.       // add the buttons in a 4 x 4 grid  52.  53.       panel = new JPanel();  54.       panel.setLayout(new GridLayout(4, 4));  55.  56.       addButton("7", insert);  57.       addButton("8", insert);  58.       addButton("9", insert);  59.       addButton("/", command);  60.  61.       addButton("4", insert);  62.       addButton("5", insert);  63.       addButton("6", insert);  64.       addButton("*", command);  65.  66.       addButton("1", insert);  67.       addButton("2", insert);  68.       addButton("3", insert);  69.       addButton("-", command);  70.  71.       addButton("0", insert);  72.       addButton(".", insert);  73.       addButton("=", command);  74.       addButton("+", command);  75.  76.       add(panel, BorderLayout.CENTER);  77.    }  78.  79.    /**  80.       Adds a button to the center panel.  81.       @param label the button label  82.       @param listener the button listener  83.    */  84.    private void addButton(String label, ActionListener listener)  85.    {  86.       JButton button = new JButton(label);  87.       button.addActionListener(listener);  88.       panel.add(button);  89.    }  90.  91.    /**  92.       This action inserts the button action string to the  93.       end of the display text.  94.    */  95.    private class InsertAction implements ActionListener  96.    {  97.       public void actionPerformed(ActionEvent event)  98.       {  99.          String input = event.getActionCommand(); 100.          if (start) 101.          { 102.             display.setText(""); 103.             start = false; 104.          } 105.          display.setText(display.getText() + input); 106.       } 107.    } 108. 109.    /** 110.       This action executes the command that the button 111.       action string denotes. 112.    */ 113.    private class CommandAction implements ActionListener 114.    { 115.       public void actionPerformed(ActionEvent event) 116.       { 117.         String command = event.getActionCommand(); 118. 119.         if (start) 120.         { 121.            if (command.equals("-")) 122.            { 123.               display.setText(command); 124.               start = false; 125.            } 126.            else 127.               lastCommand = command; 128.         } 129.         else 130.         { 131.            calculate(Double.parseDouble(display.getText())); 132.            lastCommand = command; 133.            start = true; 134.          } 135.       } 136.    } 137. 138.    /** 139.       Carries out the pending calculation. 140.       @param x the value to be accumulated with the prior result. 141.    */ 142.    public void calculate(double x) 143.    { 144.       if (lastCommand.equals("+")) result += x; 145.       else if (lastCommand.equals("-")) result -= x; 146.       else if (lastCommand.equals("*")) result *= x; 147.       else if (lastCommand.equals("/")) result /= x; 148.       else if (lastCommand.equals("=")) result = x; 149.       display.setText("" + result); 150.    } 151. 152.    private JButton display; 153.    private JPanel panel; 154.    private double result; 155.    private String lastCommand; 156.    private boolean start; 157. } 


 java.awt.GridLayout 1.0 

  • GridLayout(int rows, int cols)

    constructs a new GridLayout.

    Parameters:

    rows

    The number of rows in the grid

     

    columns

    The number of columns in the grid


  • GridLayout(int rows, int columns, int hgap, int vgap)

    constructs a new GridLayout with horizontal and vertical gaps between components.

    Parameters:

    rows

    The number of rows in the grid

     

    columns

    The number of columns in the grid

     

    hgap

    The horizontal gap to use in pixels (negative values force an overlap)

     

    vgap

    The vertical gap to use in pixels (negative values force an overlap)



 java.awt.Window 1.0 

  • void pack()

    resizes this window, taking into account the preferred sizes of its components.


       
    top



    Core Java 2 Volume I - Fundamentals
    Core Java(TM) 2, Volume I--Fundamentals (7th Edition) (Core Series) (Core Series)
    ISBN: 0131482025
    EAN: 2147483647
    Year: 2003
    Pages: 132

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net