Developer

Just a-swingin': Getting started with Java's Swing library

Are you ready to get started using Java's powerful Swing library? In this article, we take a look at its basic architecture and fill you in on those annoying layout managers.


One of the many challenges in creating a cross-platform development language like Java lies in the implementation of a GUI. Not only do various platforms internally implement GUIs in different ways, but the same basic widget can also look remarkably different on disparate platforms. Java’s solution to this particular set of problems is the Swing library, which is the graphical portion of the Java Foundation Classes (JFC). Swing is elegant and powerful but not exactly simple to learn, especially for developers used to a language with a more tightly coupled GUI library.

Swing hasn’t always been around. Sun’s first attempt at building a GUI toolkit for Java was the Abstract Window Toolkit (AWT). Although it provided a workable cross-platform GUI toolkit for Java developers, AWT was inelegant, non-object-oriented, difficult to work with, and almost universally despised by developers. That’s why Sun introduced the Swing library, which lives in the javax.swing and java.awt packages. Although reusing parts of AWT and its event library, Swing (along with reusable JavaBeans) represents a vast improvement over AWT, which it has quickly replaced.

Tupperware party, anyone?
Swing is built around the concepts of components and containers. Components represent the various GUI elements a user interacts with and cannot themselves contain other components. Swing components descend from the Component class and usually have names beginning with the letter J. JButton, for example, is the command button component. There are quite a few components in Swing, more than I could cover in a single article. For a graphical index of all of them, see this reference on Sun’s Web site.

A container’s main job is to hold components and other containers. There are two main types of containers:
  • ·        Top-level containers represent windows (or forms, if you’d rather call them that) and are able to exist without being in a container themselves. There are three top-level containers: JFrame, JDialog, and JApplet. These three represent a normal application window, a dialog window, and an applet’s main window, respectively.
  • ·        Intermediate containers must be contained by another container. There are many different types of intermediate containers: JPanel, JScrollPane, and JTabPane are just three examples. JPanels are nongraphical—they exist simply to hold and organize other components; JScrollPanes are scrollable widgets, and JTabPanes represent the familiar tabbed controls like those found in many option dialogs in Windows.

Swing applications either descend from, or implement privately, one of the three top-level containers. Let’s take a look at a simple, unexciting Swing application, with the import statements left out for brevity:
 
public class DoNothingApp extends JFrame {
  public DoNothingApp() {
    this.setVisible(true);
  }
}

Take a look at Figure A. That’s pretty simple. In fact, DoNothingApp can’t even shut down by itself—closing its window doesn’t end the program! In a minute, we’ll make it a little more interesting.

Figure A: DoNothingApp
Not much to see, huh?


Content panes
Like all containers, JFrames hold their widgets in a content pane, which is just a Container object exposed by the getContentPane() method. Components and other containers can be added to the content pane by passing an instance to the container’s add() method. After adding components, it’s always a good idea to call the top-level container’s pack() method, which ensures that the window and all components in it are visible and displayed at the correct sizes. Let’s make DoNothingApp a little more interesting by giving it a couple of JButtons with descriptive captions:
 
class DoNothingApp extends JFrame {
  public DoNothingApp() {
    this.getContentPane().add(new JButton("button1"));
    this.getContentPane().add(new JButton("button2"));
    this.pack();
    this.setVisible(true);
  }
}

As you can see from Figure B, only the second button we added is visible in the window. The first button is still there; it’s just hidden behind the second. The reason for this brings me to Swing’s layout managers.

Figure B: DoNothingApp with two JButtons
Hey, where’s the other button?


Laying out in the sun
Swing’s layout managers control where components appear in a container and how large the components will be, and they handle resizing controls as needed should their container be resized. When you first start programming Swing, layout managers will probably annoy the heck out of you. But once you get used to them, you’ll understand how much easier they can make building a GUI and managing it at runtime.

There are five basic layout managers (six if you count “none”), varying in flexibility and sophistication. Table A lists the five managers in order from simplest to most complex.
Table A
Swing Layout Managers
FlowLayout

Default manager for JPanels.
Components are arranged from left to right, in the order they are added to the container.
Simplest to use but least capable.

BorderLayout

Default manager for JFrames, JDialog, and JApplet.
Defines five areas where components can be positioned: North (top), South (bottom), East (right), West (left) and Center (middle of container). The default area is Center.
Only the last component added to an area will be visible.
Components that are placed in Center are made as large as possible for the current window size.
Components in the other four areas are made proportionally smaller to give more room for the Center area.
Specify which area a component is added into by passing a second argument to the container's add() method.

BoxLayout Components are arranged in either a vertical or horizontal row, in the order they were added to the container.
Each component can request a certain preferred and maximum size.
Glue and strut objects can be used to further control a component's position in the container.
The orientation of the row is specified by a constructor parameter.
GridLayout Components are made the same size and placed in a grid configuration, one per cell, top to bottom, and left to right in the order they were added to the container.·
The size of the grid is specified by two constructor parameters.
GridBagLayout Most flexible layout manager, also most complicated to use. Intended for use by GUI builders.
Defines a grid similar to that used by GridLayout, but rows and columns need not be the same size, and controls can span multiple cells.
Component sizes are defined via a GridBagConstraints object and set by a call to GridBagLayout's setConstraints() method before the component is added to the container.
null No layout manager.
Components must be positioned and sized manually by the programmer.

As you can see, BorderLayout is the default layout manager for JFrame containers, and the default positioning for components added to a BorderLayout-managed container is Center. Since DoNothingApp’s two buttons were added without specifying a position, they both were added to the center, and only the second button wound up visible. To specify a position for the button, we pass a second argument to the content pane’s add() method, like so:
 
this.getContentPane().add(new JButton("button1"), BorderLayout.NORTH);
 

Placing the first button in North (and resizing the window a bit) makes DoNothingApp look like Figure C.

Figure C: DoNothingApp with two buttons
Ah, there it is.


To specify a different layout manager for a container, call the container’s setLayout method at any point before the call to pack() and pass it an instance of the layout manager object you want to use. For example, suppose we wanted to use FlowLayout in DoNothingApp:
 
this.getContentPane().setLayout(new FlowLayout());
 

You aren’t required to use a layout manager; you can pass null to setLayout() and manage the position and size of your components manually, if you want. Of course, this is tedious, and you’ll also have to handle resizing components any time their container is resized.

So now you know all about Swing layout managers and containers. Not quite? Well, I’ve prepared a sample JFrame application that illustrates the effect that different layout managers have on the arrangement of components in a container. It also demonstrates how to handle several different events.

 

Editor's Picks