Is this your first time here? SwingWiki is a Java Swing Developer community site with an big archive of Swing-related usenet groups and mailing lists, but also tips, tricks and articles and book reviews written by your colleagues from around the world. If you came here through a search engine and did not find what you were looking for, make sure to check the wiki table of contents.

Building screen elements

Swing component model allows you to build complex components by combining and embedding simpler ones. This chapter will show you how to combine components effectively.

Introduction to Containers

In the component terminology, Container is a component that can hold other components. All containers are subclasses of java.awt.Container class. Swing provides several containers that you will use to embed and combine components. Keep in mind that Container is also a Component (an example of a Composite pattern), so you can nest simple components into containers, and then nest those containers in even more complex containers.

Components are embedded into containers using the add(component) method. Another version of this method exists, which enables you to specify positioning hints or additional parameters as a third parameter. Type of valid hints depends on the layout manager and container used (described later in this chapter).

JPanel

JPanel (javax.swing.JPanel) is a general-purpose container that just serves as a grouping mechanism for other components – it does not add any functionality to them. This is the container you will normally use to manage groups of components – if you have no special requirements, use JPanel.

JPanel just groups components

package com.neuri.handsonswing.ch2;
import javax.swing.*;
import java.awt.*;
 
public class JPanelDemo {
  
  public static void main(String[] args) {
    JFrame fr=new JFrame("JPanel Demo");
    fr.setDefaultCloseOperation(fr.EXIT_ON_CLOSE);
    fr.setSize(500,100);
    
    Container content=new JPanel();    
    content.add(new JButton("Button "));
    content.add(new JButton("Larger Button"));
    content.add(new JButton("Even Larger Button"));
    
    fr.getContentPane().add(content);
    
    fr.show();
    
  }
}

JTabbedPane

JTabbedPane (javax.swing.JTabbedPane) puts each component into it’s own tab. It’s also simple to use as JPanel – you can define the name of the tab as the second parameter of add method.

JTabbedPane creates a tab for each component

package com.neuri.handsonswing.ch2;
import javax.swing.*;
import java.awt.*;
 
public class JTabbedPaneDemo {
  
  public static void main(String[] args) {
    JFrame fr=new JFrame("JTabbedPane Demo");
    fr.setDefaultCloseOperation(fr.EXIT_ON_CLOSE);
    fr.setSize(500,100);
    
    Container content=new JTabbedPane();    
    content.add(
      new JButton("Button "),"first tab");
    content.add(
      new JButton("Larger Button"),"second tab");
    content.add(
      new JButton("Even Larger Button"),"third tab");
    
    fr.getContentPane().add(content);
    
    fr.show();
    
  }
}
 

This container will also allow you to place tabs vertically, but this usage is rare (and will confuse the users).

JSplitPane

This container splits available space into two areas, either vertically or horizontally. Between those two spaces is a movable border line – users can drag it with mouse pointer. This container will allow you to put inside just two components, and you need to give it a hint where to put them. For hints, use constants JSplitPane.LEFT and JSplitPane.RIGHT or use an alternative syntax with setXXXComponent methods (commented below). If you plan to use the alternative syntax, then the variable for the container must be declared as JSplitPane, because the Container superclass does not have those methods.

JSplitPane displays two components and a movable border line between

package com.neuri.handsonswing.ch2;
import javax.swing.*;
 
public class JSplitPaneDemo {
  
  public static void main(String[] args) {
    JFrame fr=new JFrame("JSplitPane Demo");
    fr.setDefaultCloseOperation(fr.EXIT_ON_CLOSE);
    fr.setSize(500,100);
    
    JSplitPane content=new JSplitPane();    
    content.add(
        new JButton("Button "),JSplitPane.LEFT);
    content.add(
        new JButton("Button2"),JSplitPane.RIGHT);
    
//alternatively, use this syntax:
//content.setLeftComponent(new JButton("Button"));
//content.setRightComponent(new JButton("Button2"));
        
    fr.getContentPane().add(content);
    
    fr.show();
    
  }
}

The divisor can be moved and positioned in the code using various setDividerLocation methods – see the jsplitpane_divider_location workaround for details.

Automatic Layout Management

Automatic layout management is one of the best things in Swing – most of the GUI builders and toolkits require the programmer to manage the size and position of components himself – Swing can do this cumbersome and error-prone job for you. Each container can have a layout manager – object that is responsible for sizing and positioning elements of the container. As a Swing developer, your job will be to specify the layout manager and just add components (optionally with hints for positioning) – layout managers will take care of the rest. When a window is resized, or elements in the window are replaced, layout managers automatically adjust the screen display.

You can mix-and-match layout managers. For example, the top container can use BorderLayout, and it’s sub-elements can be containers with FlowLayout and GridBagLayout managers (in fact, this is the preferred way to design windows in business applications, and will be explained later).

You can specify the layout manager as a constructor parameter in most of the containers. However, constructors of some layout managers require reference to the container – in that case, you would normally create the container with a default layout manager, then create the layout manager, and switch layout managers with setLayout method of the container.

Note: to modify the layout inside the frame, you must replace the contentPane container of JFrame (since the Container class does not provide a method to change the layout manager). So, create a new panel with the preferred layout and use it as frame’s content pane (like in the following examples)

Common layout managers

FlowLayout

This is the simplest Layout manager, used as the default manager in many container components. It is most useful for tool-bars and button bars, and as a generic container to store similar or related elements in a row, and when you don’t know in advance how many elements there will be. FlowLayout is simple to use, and does not require any parameters – it just adds components from left to right, until no more elements can fit in the same line and then stores them into the next line. You can optionally align components to the left, right or center them, and define the horizontal and vertical gap between them, but not much else.

FlowLayout is pretty straightforward to use:

Flow layout in action

package com.neuri.handsonswing.ch2;
import javax.swing.*;
import java.awt.*;
 
public class FlowLayoutDemo {
  
  public static void main(String[] args) {
    JFrame fr=new JFrame("Flow Layout Demo");
    fr.setDefaultCloseOperation(fr.EXIT_ON_CLOSE);
    fr.setSize(500,80);
    Container content=
       new JPanel(new FlowLayout());
    fr.setContentPane(content);
    for (int i=0; i<4; i++) 
        content.add(new JButton("Button #"+i));
    fr.show();    
  }
}

Flow layout may hide some elementsBeware – it will not resize the container to allow all elements to fit – if there is not enough space for everything, some elements will be hidden. Just modify the previous example to add 30 buttons and you will see the effect on the second picture. To prevent this, use GridLayout instead of FlowLayout, as described in flowlayout_hides_content workaround.

GridLayout

GridLayout is a simple table with a fixed number of cells, with all columns and rows equally sized. It is fairly straightforward to use – just add elements without any constraints, they are populated line by line, from top to bottom. Each line is populated left to right.

Grid layout in action

 
package com.neuri.handsonswing.ch2;
import javax.swing.*;
import java.awt.*;
 
public class GridLayoutDemo {
  public static void main(String[] args) {
    JFrame fr=new JFrame("Grid  Layout Demo");
    fr.setDefaultCloseOperation(fr.EXIT_ON_CLOSE);
    fr.setSize(500,200);
    Container content=
        new JPanel(new GridLayout(0,4,5,5));
    fr.setContentPane(content);
    for (int i=0; i<10; i++) 
        content.add(new JButton("Button #"+i));
    fr.show();    
  }
}
 

Grid layout will fill up all available space and resize elements in the container to fit to the allocated space on the screen. This basically means that it will reduce the size of components if they cannot fit, or enlarge them if there is more space available. It’s best used for toolboxes and graphical buttons, that are of the same size. It should not be used to design forms or hold a list of buttons, unless you want to have make them all the same size. In that case, be sure to limit the height of the container, because buttons with a lot of vertical spacing look bad.

BoxLayout

BoxLayout is somewhere in between FlowLayout and GridLayout. It represents a single-column or a single-row table - does not wrap elements, so it will guarantee that they sit on a single line. Difference between BoxLayout and GridLayout is that all cells in the GridLayout are of the same size, but BoxLayout allows elements to differ in size. Difference between BoxLayout and FlowLayout is that it can align elements vertically. Similar to FlowLayout, BoxLayout does not re-size elements in order to fit all of them into the available space. However, it will resize them in order to make all components more consistent – for example, a horizontal BoxLayout will try to make all the elements the same height.

This layout manager has two major usages: as a vertical replacement for FlowLayout, and as a simplified replacement for complex tables. Nesting containers with horizontal box layout in a container with vertical box layout will allow you to create usual forms, similar to what you would do with GridBagLayout, but with code that is easier to read and maintain.

BorderLayout

This manager splits the area of the container into five sections: one central and one for each edge. The central component is stretched so that it takes all available space, but four edge components are not resized. Users don’t have any divisor lines or elements to drag in order to resize or modify the layout of the contained components. This manager is mostly used to add a tool-bar above a large central component or a button bar below it. It is usually the main layout of windows and dialogs.

You can specify the section with the second parameter of the add method. Valid values are BorderLayout.EAST, BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.WEST and BorderLayout.CENTER.If you don’t specify the section with the second parameter of add method, component will be placed in the center. However, this layout manager displays only one component in each section, so be careful not to call add method for any section twice (or call remove method before the second call, and remove the old component before adding a new one).

Border Layout splits the container into five sections

package com.neuri.handsonswing.ch2;
import javax.swing.*;
import java.awt.*;
 
public class BorderLayoutDemo {
  
  public static void main(String[] args) {
    JFrame fr=new JFrame("Border Layout Demo");
    fr.setDefaultCloseOperation(fr.EXIT_ON_CLOSE);
    fr.setSize(500,200);
    Container content=
      new JPanel(new BorderLayout());
    fr.setContentPane(content);  
    content.add(
      new JButton("North"),BorderLayout.NORTH);
    content.add(
      new JButton("East"),BorderLayout.EAST);
    content.add(
      new JButton("West"),BorderLayout.WEST);
    content.add(
      new JButton("South"),BorderLayout.SOUTH);
    content.add(
      new JButton("Center"),BorderLayout.CENTER);
    fr.show();
    
  }
}

GridBagLayout

GridBagLayout is the most complex, and equally but most flexible layout manager. Imagine it as a table which automatically expands and shrinks to fit all components as best as it can. Rows and columns get expanded to fit the largest element, but different rows and columns can have different width/height. After that, smaller elements can be aligned or expanded in the available space – and you can specify alignment and re-sizing for each individual element. You can even have elements that span across multiple cells.

As a difference from GridLayout, you don’t specify the number of columns and rows in advance. GridBagLayout automatically calculates table dimensions. When a component is added to a container with GridBagLayout, you need to specify it’s properties with a GridBagConstraints object as a second parameter of the add method.

GridBag is the most flexible layout

package com.neuri.handsonswing.ch2;
import javax.swing.*;
import java.awt.*;
 
public class GridBagLayoutDemo {
  
  public static void main(String[] args) {
    JFrame fr=new JFrame("GridBag Layout Demo");
    fr.setDefaultCloseOperation(fr.EXIT_ON_CLOSE);
    fr.setSize(500,200);
    Container content=
      new JPanel(new GridBagLayout());
    GridBagConstraints gc=
        new GridBagConstraints();
    fr.setContentPane(content);
    gc.gridx=0;gc.gridy=0; gc.anchor=gc.EAST;    
    content.add(new JButton("Left"),gc);
    gc.gridx=1;gc.gridy=0; gc.gridwidth=2; 
    gc.anchor=gc.EAST; gc.fill=gc.HORIZONTAL;
    content.add(
        new JButton("Spanning two columns"),gc);
    gc.gridx=0;gc.gridy=1; gc.gridwidth=1;
    gc.gridheight=2; 
    gc.anchor=gc.EAST; gc.fill=gc.BOTH;
    content.add(new JButton(
             "Spanning two rows, expanded"),gc);
    gc.gridx=1;gc.gridy=1; gc.gridheight=1;
    gc.gridheight=1; gc.anchor=gc.CENTER; 
    gc.fill=gc.NONE;
    content.add(new JButton
             ("Center, no fill"),gc);
    gc.gridx=1;gc.gridy=2;gc.gridheight=1;
    gc.gridheight=1;gc.anchor=gc.CENTER; 
    gc.fill=gc.HORIZONTAL;
    content.add(
       new JButton("down, fill horizontal"),gc);
    gc.gridx=2;gc.gridy=2;       
    content.add(new JButton("corner"),gc);
    fr.show();
    
  }
}

You can even specify proportional dimensions for each component, by giving them weights. For more information, see GridBagConstrains API documentation. Here is a short explanation GridBagConstraint properties used in the example:

Property What it specifies
gridx column of the table where element is positioned
gridy column of the table where element is positioned
gridheight number of rows spanned by the element
gridwidth number of columns spanned by the element
anchor were to place the element inside available space
fill should the element be expanded to fill up available space.

Remember that GridBagConstraints objects are copied after adding the component, so you can re-use the same object and just modify properties that are different from the previous component.

PageLayout

PageLayout is a simple and versatile layout manager that encapsulates, in a single API, the functionality of the other layout managers distributed with Java (up to JDK1.5). You can use it to lay out components in rows, columns or grids of cells with specified horizontal and vertical alignments. At its simplest, a cell, which is just a rectangle, may contain a single component or a gap. However, a cell may recursively contain other cells which are themselves rows, columns or grids of cells containing components or gaps. As a result, components may be arranged in relatively complex layouts with comparatively little programming effort.

In principle, it is possible to duplicate the functionality of PageLayout by using objects of the class javax.swing.JPanel together with one of the many other existing layout managers, but only at the cost of substantially increased complexity. Conversely, the functionality of the various layout managers that are a part of the standard Java distribution can be very simply duplicated by using just a single layout manager, the PageLayout.

Here is a simple example for a dialog box.

 
	public static void createGUI()
        {
 
 
                // Main frame and its container
                JFrame frame=new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                Container container=frame.getContentPane();
 
                // Create the components
                JLabel findWhat=new JLabel("Find What:");
                JTextField textInput=new JTextField();
                JButton find=new JButton("Find");
                JCheckBox matchCase=new JCheckBox("Match Case");
                JCheckBox wrapAround= new JCheckBox("Wrap Around");
                JButton cancel=new JButton("Cancel");
                JCheckBox wholeWords=new JCheckBox("Whole Words");
                JCheckBox searchBackwards=new JCheckBox("Search Backwards");
 
                // First column
                Column col1=new Column(findWhat);
 
                // Second column
                Column col2=new Column(
                        new Row(textInput),
                        new Row(matchCase,wrapAround),
                        new Row(wholeWords,searchBackwards)
                        );
 
                // Third column
                Column col3=new Column(find,cancel);
 
                // Create page from columns
                Row row=new Row(col1,col2,col3);
                // Add size constraints
                row.linkHeight(find,new Component[]{textInput},
                                new double[]{1});
                row.linkWidth(cancel,new Component[]{find},
                                new double[]{1});
                row.linkWidth(wholeWords,new Component[]{matchCase},
                        new double[]{1});
 
                // Construct the layout
                row.createLayout(container);
 
                frame.pack();
                frame.setSize(frame.getPreferredSize());
                frame.setResizable(false);
                frame.show();
        }

Here, for the purposes of comparison, is the code for the GridBagLayoutDemo example given above.

        public static void createGUI()
	{
 
		JFrame frame=new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container container=frame.getContentPane();
		
		// Create components
		JButton left=new JButton("Left");
		JButton spantwocolumns=new JButton("Spanning Two Columns");
		JButton spantworows=new JButton("Spanning two rows, exapnded");
		JButton centernofill=new JButton("Center, no fill");
		JButton downfillhoriz=new JButton("down, fill horizontal");
		JButton corner=new JButton("corner");
 
               // Create the rows of the grid.
		GridRows rows = new GridRows();
 
		// First Row
		rows.newRow().add(RIGHT,NO_ALIGNMENT,left).add(spantwocolumns);
		
		// Second Row
		rows.newRow().add(spantworows);
		rows.getCurrentRow().add(CENTER,NO_ALIGNMENT,centernofill);
 
		// Third Row. 
		rows.newRow().spanVertical().add(new Row(downfillhoriz,corner));
 
		// Create the cell grid
		CellGrid grid=rows.createCellGrid();
 
		// Make the required component sizes to be flexible.
		grid.setFixedWidth(new Component[]{downfillhoriz,spantwocolumns},false);
		grid.setFixedHeight(new Component[]{spantworows},false);
 
		// Set the component gaps to be zero
		grid.setComponentGaps(0,0);
 
		// Center the grid in the container
		Column col=new Column(CENTER,CENTER,grid);
		// Set the size of the grid to be fixed.
		col.setFixedWidth(new Cell[]{grid},true);
		col.setFixedHeight(new Cell[]{grid},true);
 
		// Create the layout
		col.createLayout(container);
 
		// pack and show
		frame.pack();
		frame.show();
			
	}

Layout manager summary

Layout manager Pros Cons Use for
FlowLayout Simple to use, does not require number of components to be specified in advance Does not resize elements automatically, so it might hide components Tool-bars, button bars and multi-component fields in complex containers with other layout managers
GridLayout Simple to use, resizes elements automatically so does not hide components if it cannot show them Requires all cells to be the same size Toolboxes, and as a replacement for FlowLayout when there is a possibility that elements won’t fit
BoxLayout Tries to make components consistent, allows vertical placement Does not guarantee that all elements will fit, so it might hide components Forms, vertical bars
BorderLayout Main area of windows and dialogs
GridBagLayout Very flexible, it will allow you to do anything you want Complex and hard to use Forms and central parts of windows and dialogs that cannot be defined with simpler layouts
PageLayout Very flexible. Allows you to do anything you want. Not a part of JDK (but available under LGPL) Any type of layout, from simple to complex, with uniform API

Usual windows

For most business applications, BorderLayout is a good choice for the entire window, where top and bottom part are panels managed by FlowLayout, and the middle part can be either a panel with a GridBagLayout (forms and similar), or a JScrollPane containing some large display element (HTML displayer, image editor and similar). This combination allows you also to put a toolbox on the left side (or an utility controller). If you want to use a single API for laying out components in a window but are willing to use a layout manager which is not a part of the standard JDK distribution, you may consider using PageLayout, which is free. A comprehensive Tutorial and a number of nontrival examples with code are also available for PageLayout.

Other Swing managers

Swing contains several specific-purpose layout managers, such as CardLayout and OverlayLayout, that are used mostly to support some complex containers (such as JTabbedPane and JScrollPane). At this point, you don’t need to worry about them, but if you want to find more information on other layout managers, look at the LayoutManager interface documentation, with links to all implementations in the standard API.

Proprietary managers

Some wizard-like GUI generators in IDEs will allow you to draw elements on the screen and then save the resulting Swing code – beware of proprietary layout managers like Borland’s XYLayout Manager. Wizards may generate code that locks you in with custom/proprietary libraries that must be licensed separately to deploy the application. If you can, avoid using wizards that require you to use proprietary layout managers – Swing’s default layout managers can solve most of the tasks.

When not to use a Layout Manager?

Short answer: almost never. In 99% of applications we have seen, Layout managers are quite appropriate and are used – in a very specific case when you want to position elements precisely on some place (exact pixel), you must do manual layout and not use the layout manager. This is mostly useful in games. However, you cannot mix and match – unexpected results are shown on the screen (at least in J2SE 1.4) if a sub-container of an automatically managed container does not have a layout manager. To avoid messing up the layout management of parent containers, but enable absolute positioning of some components, create a dummy layout manager that positions components on absolute coordinates. This is described in the fixed_position_layout workaround.

External Links


Previous: Introduction to Swing | Next: Interacting With Users | Hands on Swing Table of Contents | Other Swing Books

 

Comments? Corrections? Contact us or Login to edit pages directly (registration is free and takes less than displaying a JLabel)
  handson/building_screen_elements.txt · Last modified: 2006/10/13 14:15 by 66.63.147.21 (varan)
 
Recent changes | RSS changes | Table of contents | News Archive | Terms And Conditions | Register | The Quest For Software++| Ruby Resources

Sedo - Buy and Sell Domain Names and Websites project info: swingwiki.org Statistics for project swingwiki.org etracker� web controlling instead of log file analysis