The JavaTM Tutorial
Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search

Trail: Creating a GUI with JFC/Swing
Lesson: Swing Features and Concepts

Painting

You might not need the information in this section at all. However, if your components don't seem to be painting themselves correctly, understanding the concepts in this section might help you figure out what's wrong. If you plan to create custom painting code for a component, this section is required reading.

How Painting Works

When a Swing GUI needs to paint itself -- whether for the first time, in response to becoming unhidden, or because it needs to reflect a change in the program's state -- it starts with the highest component that needs to be repainted and works its way down the containment hierarchy. This process is orchestrated by the AWT painting system, and made more efficient and smooth by the Swing repaint manager and double-buffering code.

Swing components generally repaint themselves whenever necessary. When you invoke the setText method on a component, for example, the component should automatically repaint itself and, if appropriate, resize itself. If it doesn't, it's a bug. The workaround is to invoke the repaint method on the component to request that the component be scheduled for painting. If the component's size or position needs to change but doesn't do so automatically, you should invoke revalidate upon the component before invoking repaint.

Like event-handling code, painting code executes on the event-dispatching thread. While an event is being handled, no painting will occur. Similarly, if a painting operation takes a long time, no events will be handled during that time.

Programs should paint only when the painting system tells them to because each occurrence of a component painting itself must execute without interruption. Otherwise, unpredictable results could occur, such as a button being painted as half pressed and half unpressed.

For smoothness, Swing painting is double-buffered by default -- performed to an offscreen buffer and then flushed to the screen once finished. It might slightly help performance if you make a Swing component opaque, so that the Swing painting system can know not to paint anything behind the component. To make a Swing component opaque, invoke setOpaque(true) on the component.

Although their available painting area is always rectangular, non-opaque Swing components can appear to be any shape. A button, for instance, might display itself by painting a filled octagon. The component behind the button (its container, most likely) would then be visible, showing through at the corners of the button's bounds. The button would have to include special hit detection code to avoid acting pressed if the user happens to click on its corners.

An Example of Painting

To illustrate painting, we'll use the SwingApplication program, which is explained in A Quick Tour Through a Swing Application's Code(in the Creating a User Interface trail). Here is SwingApplication's GUI:

SwingApplication's GUI

Here, again, is its containment hierarchy:

JFrame Hierarchy

When the GUI for SwingApplication is painted, here's what happens:

  1. The top-level container, JFrame, paints itself.
  2. The content pane first paints its background, which is a solid gray rectangle. It then tells the JPanel to paint itself. The content pane's background rectangle doesn't actually appear in the finished GUI because the content pane is completely obscured by the JPanel.
    Note: It's important that the content pane be opaque. Otherwise, messy repaints will result. Because the JPanel is opaque, we could make it the content pane (by subsituting setContentPane for the existing code getContentPane().add). This would slightly simplify the containment hierarchy and painting by removing an unnecessary container.
  3. The JPanel first paints its background, a solid gray rectangle. Next, it paints its border. The border is an EmptyBorder, which has no effect except for increasing the JPanel's size by reserving some space at the edge of the panel. Finally, the panel asks its children to paint themselves.
  4. To paint itself, the JButton paints its background rectangle, if necessary, and then paints the text that it contains. If the button has the keyboard focus, meaning that any typing goes directly to the button for processing, then the button does some look-and-feel-specific painting to make clear that it has the focus.
  5. To paint itself, the JLabel paints its text.
In this way, each component paints itself before any of the components it contains. This ensures that the background of a JPanel, for example, is visible only where it isn't covered by painting performed by one of the components it contains. The following figure illustrates the order in which each component that inherits from JComponent paints itself:
1. background
(if opaque)
2. custom
painting
(if any)
3. border
(if any)
4. children
(if any)

background

custom painting

border

children

For more information on how to paint, see the Working with Graphics(in the Creating a User Interface trail) lesson.

Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search