The JFC Swing Tutorial: A Guide to Constructing GUIs (2nd Edition)
< Day Day Up > |
How Swing Components Are Displayed
If you plan to create custom painting code for a component, this section is required reading. Understanding the concepts in this section might also help you troubleshoot if Swing components don't seem to be displayed correctly. How Painting Happens
When a Swing GUI needs to paint itself ”whether for the first time, or in response to being uncovered, 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 automatically repaints itself and, if appropriate, resizes itself. Behind the scenes, when a visible property changes the repaint method is invoked on the component to request that it be scheduled for painting. If the component's size or position also needs to change, a call to revalidate precedes the one to repaint . The repaint and revalidate methods are thread safe ”they can be invoked from any thread.
Note: 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. You can improve painting performance by making components opaque when possible, so that the Swing painting system doesn't waste time trying to paint behind these components. To make a Swing component opaque , invoke setOpaque(true) on the component. Although the painting area available to Swing components 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 its corners. The Swing Painting Methods
The painting method you're most likely to override is paintComponent . It's one of three methods that JComponent objects use to paint themselves. The three methods are invoked in this order:
Note: We recommend that you don't override or invoke the paint method, which is the method that calls the paint Xxx methods. Although overriding paint is legitimate in non-Swing components, it's generally not a good thing to do in components that descend from JComponent . Overriding paint can confuse the painting system, which relies on the JComponent implementation of the paint method for correct painting, performance enhancements, and features such as double buffering.
Figure 1 illustrates the order in which each component that inherits from JComponent paints itself. Steps 1 and 2 ”painting the background and performing custom painting ”are performed by the paintComponent method. Step 3 is performed by paintBorder , and step 4 is performed by paintChildren . Figure 1. The order in which each component is painted.
The standard Swing components delegate their look-and-feel-specific painting to an object called a UI delegate . When such a component's paintComponent method is called, the method asks the UI delegate to paint the component. Generally, the UI delegate first checks whether the component is opaque and, if so, paints the entire background of the component. Then the UI delegate performs any look-and-feel-specific painting. The JComponent class doesn't set up a UI delegate ”only its subclasses do. This means that if you extend JComponent , your component needs to paint its own background if it's opaque. If you need more information about painting, see The Swing Connection article "Painting in AWT and Swing." It discusses in depth the intricacies of painting, and you can find it online at http://java.sun.com/products/jfc/tsc/articles/painting/index.html. An Example of Painting
To illustrate painting, we'll use the SwingApplication program. Figure 2 shows its GUI. Figure 2. SwingApplication 's GUI.
Figure 3 shows its containment hierarchy: Figure 3. The JFrame hierarchy.
When the GUI for SwingApplication is painted, here's what happens:
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 its contained components. Repainting Transparent Components
When a transparent (nonopaque) component gets a request to repaint itself, one or more components underneath the transparent component must also repaint themselves. For example, assume you set the text on an ordinary label that's already visible. In most look and feels, the opaque property of labels is false , so that labels are transparent. When a transparent label's text changes, the label must not only paint itself, but all components that can be seen behind the label must also paint themselves. This painting frenzy is kicked off when the label's setText method invokes repaint . Here's the sequence of painting when repaint is invoked on a JComponent such as a label that is both visible and nonopaque.
You can see from this sequence that painting transparent components is more costly than painting opaque components. That's why we encourage you to set components' opaque property to true whenever practical. |
< Day Day Up > |