[an error occurred while processing this directive]
The Morgue Commentary PLAF Papers Friends Tech Topics Swing Text The Web Tech Topics What's Swing?
Index Archive Call 911 PLAF Papers Friends Tech Topics Swing Text Swing & the Web IDE Roundup Special Report Databank Page 2 Page One What's Swing?
JDK Docs Download JDK Swing API Docs Download Swing Java Tutorial
The Swing Connection The Archive Tech Topics

Understanding Containers
-- And Content Panes, JRootPanes, et al
 


Window graphicIf you've started the big move from the Abstract Windowing Toolkit (AWT) to Swing, you've probably noticed by now that containers don't work the same way in Swing that they did back during the days of AWT.

    Because of the intricacies involved in making lightweight and heavyweight components work together in Swing, you can't just add() anything you like to a JFrame, JApplet, or JDialog object; first, you must get something called a "content pane," and then you can add Swing components to that.

    If you want to find out why that's true -- and if you'd like to learn more about adding components to containers in Swing -- this article is what you've been waiting for. It will tell you everything you need to know about content panes and JRootPanes, and will show you how to add components to Swing containers.

    To help you understand the points covered in the article, we've provided some source-code snippets that you can download, study, and incorporate into your own programs.

 

By Eric Armstrong

To understanding Swing's window, frame, and dialog containers, it's essential to have an understanding of a new Swing class named JRootPane. That's because every component container used in Swing contains an object called a content pane, which is the actual repository for components that are added to the container. This content pane is an object of the JRootPane class, which is the focus of this article.

The major topics covered in this article are:

 

 

    Source code graphicWe've provided some downloadable source-code snippets that illustrate the most important points covered in this article. To view or download the code, just follow this link.

    The code samples we've supplied will show you how to create:

    • A panel with a titled border.
    • A tabbed pane (with three tabs on the left).
    • A split pane (horizontally split with two panels).
    • Internal frames containing messages.
    • A ScrollPane that scrolls a panel.

 

Basic Swing container architecture 

Because a container's contents are actually stored in its content pane, you never add() a component to a Swing container directly. Instead, you add the component to the container's content pane. You do that by calling a method named getContentPane(), using a statement similar to this:

  aContainer.getContentPane().add(aComponent)

There five Swing container classes that delegate their contents to a JRootPane instance:

(For more information about lightweight and heavyweight components, see the article titled "Mixing Heavy and Light Components" in The Swing Connection archive.)

The following diagram shows the relationships that these five kinds of containers have with each other, and with four heavyweight parent container  classes that reside in the java.awt package: Window, Applet, Frame,  and Dialog.

Container hierarchy chart 

All the heavyweight components shown in the diagram appear inside the blue panel at the top of the picture, which is labeled java.awt. The  four heavyweight components in the Swing package (JFrame, JDialog, JWindow,  and JApplet) have pink interiors and appear in the center section of the  diagram. They extend the four heavyweight AWT classes -- Window, Applet,  Frame, and Dialog -- that appear in the java.awt panel.

Also shown in the diagram is one lightweight Swing component -- JInternalPane  -- which doesn't extend any AWT class.

All five of the Swing containers shown in the drawing implement the Swing  RootPaneContainerapi interface, which defines the JRootPaneapi class. Notice  that all five Swing containers delegate their operations to the JRootPane  class, with is shown at the bottom of the diagram with a little handle  on top.

 

 

    To obtain the JRootPane object that contains a particular component,  call the JComponent method

    getRootPane()

 

 

This section shows how the JRootPane and JLayeredPaneapi classes work together  to provide the architectural underpinnings of the Swing container hierarchy.


JRootPane

A JRootPane object is made up of a glassPane, a contentPane, and an optional  menu bar. The contentPane and the menu bar, if there is one, are managed by a JLayeredPane object. The following diagram shows this arrangement.

JRootPane hierarchy graphic 

Although a menu bar is optional in a JRootPane object, the layeredPane, contentPane, and glassPane shown in this diagram  always exist. Attempting to set them to null generates an  exception.

JRootPane's contentPane

It´s very important to remember that a JRootPane object cannot have children. So you cannot add a component directly to a JRootPane. That means you can´t do this:

      rootPane.add(child);  // NO!!

Instead, add your component to the contentPane of the JRootPane by calling a JRootPane method named getContentPane(), like this:

      rootPane.getContentPane().add(child);

The same principle holds true for setting layout managers, removing components, listing children, and so on. All these methods are invoked on a contentPane instead of on a JRootPane object.


 

    Note graphicThe default layout manager for a contentPane is the BorderLayout manager. But JRootPane uses a custom LayoutManager. So, when you want to change the layout manager for components you have added to a JRootPane, be sure to use code like this:

        rootPane.getContentPane().setLayout
           (new BoxLayout());


How getContentPane() methods are delegated

All the major frame and window containers (JFrame, JWindow, and so on) delegate their getContentPane() methods to the JRootPane object they contain. These JRootPane objects, in turn, delegate their getContentPane() methods to their JLayeredPane instances.

However, operations such as add(child)cannot be delegated down to the contentPane, because the contentPane could be an arbitrary component. For example, if the contentPane were a JScrollPaneapi, then add(child) would not be a valid method -- you would instead use setViewportView().

JRootPane's menuBar

If a JMenuBar component is set on the JRootPane, it is positioned along the upper edge of the frame. The contentPane is adjusted in location and size to fill the remaining area.

JRootPane's layeredPane

The layeredPane is the parent of all children in the JRootPane. It is an instance of JLayeredPane, which provides the ability to add components at several layers. This capability is very useful when working with popup menus, dialog boxes, and dragging -- situations in which you need to place a component on top of all other components in the pane.

JRootPane's glassPane

The glassPane sits on top of all other components in the JRootPane. This positioning makes it possible to intercept mouse events, which is useful for dragging one component across another. This positioning is also useful for drawing.

The glassPane can be set up for drawing because the glassPane, like the contentPane, can be an arbitrary component. Lines and images on the glassPane can then range over the frames underneath without being limited by their boundaries.

Developers can use setVisible() on the glassPane to control when the glassPane displays over the other children. By default, the glassPane is not visible. The default glassPane is an instance of JPanel.

The custom LayoutManager used by JRootPane ensures that:

  1. The glassPane, if present, fills the entire viewable area of the JRootPane (bounds - insets).
     
  2. The layeredPane also fills the entire viewable area of the JRootPane (bounds - insets).
     
  3. The menuBar is positioned at the upper edge of the layeredPane.
     
  4. The contentPane fills the entire viewable area, minus the MenuBar, if there is one.

If you replace the LayoutManager of the JRootPane, you are responsible for managing all these views. So, ordinarily, you will want to be sure that you change the layout manager for the contentPane rather than for the JRootPane itself!


JLayeredPane

Layered panes graphicJLayeredPane adds depth to a JFC/Swing container, allowing components to overlap each other when needed. An Integer object specifies each component's depth in the container, where higher-numbered components sit "on top" of other components.

For convenience, JLayeredPane divides the depth range into several different layers. Putting a component into one of those layers makes it easy to ensure that components overlap properly, without having to worry about specifying numbers for specific depths.

The depth-range layers used by JLayeredPane are:

  • DEFAULT_LAYER: The standard layer, where most components go. This the bottommost layer.
     
  • PALETTE_LAYER: The palette layer sits over the default layer. Useful for floating toolbars and palettes, so they can be positioned above other components.
     
  •  MODAL_LAYER: The layer used for modal dialogs. They will appear on top of any toolbars, palettes, or standard components in the container.
     
  • POPUP_LAYER: The popup layer displays above dialogs. That way, the popup windows associated with combo boxes, tooltips, and other help text will appear above the component, palette, or dialog that generated them.
     
  • DRAG_LAYER: When the user is dragging a component, reassigning it to the drag layer ensures that it is positioned over every other component in the container. When finished dragging, it can be reassigned to its normal layer.

The JLayeredPane methods moveToFront(Component), moveToBack(Component) and setPosition can be used to reposition a component within its layer. The setLayer() method can also be used to change the component's current layer.

 

 

Swing containers typically used in GUIs are JPanel, JSplitPane, JTabbedPane, JDesktopPane, JInternalFrame, JScrollPane, JViewport, JTextPane, and JEditorPane. You can add other containers and components to these containers, combining components and their containers in various ways to get the interface you want.


JPanel

A JPanel object is a simple container with no fancy additions. It's a "JComponent with real estate." (JComponent is itself an extension of Container.) JPanels are typically used with a layout manager to divide an area into discrete sections, each of which can then get its own layout manager.

The default layout for a JPanel is flow layout. The default glassPane for a JRootPane is a JPanel.


The Box container

The Box container uses BoxLayoutapi, a layout manager that lets you line up components added to the Box either horizontally or vertically. Nesting multiple Box components gives you an easy way to create sophisticated arrangements without the complexity of AWT's GridBagLayout manager.


JSplitPane

A JSplitPaneapi container manages two panes that are separated horizontally or vertically by a divider that can be repositioned by the user. You can choose which pane to add a component to. You can specify the components with setLeftComponent() and setRightComponent(), or setTopComponent() and setBottomComponent(). In these methods, "Left" is equivalent to "Top" and "Right" is equivalent to "Bottom" -- so if you change the arrangement, your existing code still works. Subsequent adds to the same pane replace its contents with the new object.


JTabbedPane

A JTabbedPaneapi object manages multiple panes that completely overlap each other. The user can select a pane to view by clicking on a "tab" attached to the pane (like the tab on a file folder). The tabs can be positioned to the top, bottom, left side, or right side of the container.


JDesktopPane and JInternalFrame

JDesktopPane is basically a container for one or more JInternalFrames used to create a multiple-document interface or virtual desktop.

JDesktopPane extends JLayeredPane to manage the potentially overlapping internal frames. It also maintains a reference to an instance of DesktopManager that is set by the UI class for the current Look and Feel (L&F). The internal frames delegate L&F-specific operations to the DesktopManager (for example, how an internal frame is iconized).


JScrollPane and JViewport

A JScrollPane consists of JScrollBars, a JViewport, and the wiring between them, as shown in the following diagram. The JViewPort provides a window, or "viewport" onto a data source -- for example, a text file. That data source is the "scrollable client" (or data model) displayed by the JViewport view. The scrollable client can be any component, but rather than "adding" it to the JScrollPane container, you specify it as part of the constructor or specify it using the setViewportView() method. (Subsequent calls to that method replace the original view.)

JScrollPane/JViewport graphic 

Along with its scroll bars and viewport, a JScrollPane can have a column header and a row header (see diagram). Each of these is a JViewport object that you specify with setRowHeaderView() and setColumnHeaderView(). The column header viewport automatically scrolls left and right, tracking the left-right scrolling of the main viewport. (It never scrolls vertically, however.) The row header acts in a similar fashion.

By default, the corners are empty. You can put a component into a corner using setCorner(), in case you there is some function or decoration you would like to add to the scroll pane. The size of corner components is entirely determined by the size of the headers and scroll bars that surround them.

To add a border around the main viewport, you can use setViewportBorder(). (Of course, you can also add a border around the whole scroll pane using setBorder().)


JTextPane and JEditorPane

JTextPane and JEditorPane sound like general containers (because they are named "pane"), but in reality these are highly specialized containers that can display text and provide basic editing capabilities.

JTextPane, as its name suggests, displays text. Unlike JTextArea, JTextPane can handle multiple fonts in the same display.

JEditorPane provides basic editing capabilities for mixed-font text. The html and rtf packages provide additional capabilities for text formatted using the HyperText Markup Language (HTML) and the Rich Text Format (RTF).

For much more information on Swing's text components, see the article titled "Using the Swing Text Package."

 

Containers and layout managers 

In Swing, as in pre-Swing versions of AWT, the recommended way to place components inside containers is to use a layout manager.

Box layout graphic 


BoxLayout

BoxLayout is a layout manager that allows multiple components to be laid out either vertically or horizontally. The components in a box layout do not wrap -- so, for example, a vertical arrangement of components stays vertically arranged when the frame is resized.

Nesting multiple panels with different combinations of horizontal and vertical gives an effect similar to the familiar AWT GridBagLayout, without the complexity. The prededing diagram shows two panels arranged horizontally, each of which contains three components arranged vertically.

The Box container uses BoxLayout (unlike JPanel, which defaults to flow layout). You can nest multiple boxes and add components to them to get the arrangement you want.

For more information about Swing´s box layout, see the Swing layout-manager chapter in The Java Tutorial.


OverlayLayout

OverlayLayout is a small-footprint layout manager that centers an object in its area. Used by JButton and its subclasses. Unlike BorderLayout's centering, OverlayLayout does not expand the component to fill the available space, but instead leaves it at is preferred size.


ScrollPaneLayout and ViewportLayout

ScrollPaneLayout/ViewportLayout are the layout managers used by JScrollPaneapi and JViewportapi.

 

Heavyweights and lightweights 

To understand the behavior of Swing containers, it helps to have an understanding of the differences between lightweight and heavyweight components.

Almost all Swing components are said to be lightweight because they don't rely on user-interface code that's native to whatever operating system they're running on. Consequently, they can usually be implemented using only about half the classes that earlier heavyweight components require.

Heavyweight components are used in programs that were written before Swing was introduced, the creators of Swing have made it possible to mix heavyweight and lightweight components in the same program. To learn how to do that, see the article titled "Mixing Heavy and Light Components" in The Swing Connection archive.

The only heavyweight components used in Swing are:

  • swing.JFrame
  • swing.JDialog
  • swing.JWindow
  • swing.JApplet
  • All AWT components (awt.*), except those noted below.

All other Swing components are lightweight. Swing's lightweight components are:

  • awt.Component
  • awt.Container
  • swing.JComponent
  • All other Swing classes (swing.*) and all packages under it, except for those noted above.

__________

Eric Armstrong is an author and magazine contributor who has recently been specializing in Swing and the JavaTM programming language. He is the author of a new book, "Java JBuilder Bible," which teaches object-oriented programming in the Java programming language using the Borland JBuilder IDE. The book is scheduled for summer publication by IDG.

[an error occurred while processing this directive]