James Elliott
Device 0: X11GraphicsDevice[screen=0]
3.5 The JComponent Class
3.5.5 Invalidating and Repainting
Swing uses a repaint manager to repaint lightweight components. The repaint manager maintains a queue of rectangular areas that need to be repainted; it calls these areas " dirty regions." Sometimes the rectangles are the size of entire components; at other times they are smaller. The repaint manager processes repaint requests as they are added to the queue, updating dirty regions as quickly as possible while preserving the visual order of the components. In AWT, the
Component
class contains an overloadedrepaint( )
method that allows you to repaint only a subrectangle of the component. The same is true withJComponent
. If only part of a component needs to be repainted, the repaint manager invokes an overloaded version of therepaint( )
method that takes aRectangle
parameter.JComponent
contains tworepaint( )
methods that add specified rectangles directly to the dirty region. Like AWT, you should call these methods instead of invoking thepaint( )
method directly, which bypasses theRepaintManager
. TheRepaintManager
class is discussed in more detail in Chapter 28.3.5.5.1 The paint( ) method and opaqueness
Because
JComponent
is the direct subclass of the AWTContainer
class, it is the official recipient of repaint requests through itspaint( )
method. As you might guess,JComponent
must delegate this request by passing it to thepaint( )
method of the UI-delegate object. The responsibility, however, does not end there.JComponent
is actually responsible for painting three items: the component itself, any borders associated with the component, and any children that it contains.The order is intentional. Components drawn last are always on top; hence, child components always paint over their parents.
JComponent
contains three protected methods that it uses to complete this functionality:protected void paintComponent(Graphics g)
protected void paintBorder(Graphics g) protected void paintChildren(Graphics g)
Because of the complexity involved in painting and repainting Swing components, you should always try to override these three methods while creating your own components. Also, do not try to override
paint( )
unless you callsuper.paint( )
.SDK 1.4 introduced a series of methods relating to printing rather than painting. Calling the
print( )
orprintAll( )
methods (both public and available since 1.2) now results in calls toprintComponent( )
,printBorder( )
, andprintChildren( )
in that order.When painting or printing
JComponent
subclasses, theGraphics
object passed to these methods is actually aGraphics2D
object. You can cast it as such if you want to take advantage of the increased functionality available in the 2D packages. Check out Jonathan Knudsen's Java 2D Graphics (O'Reilly) for more detailed information.The boolean property
opaque
dictates the transparency of each Swing object.[1]If this property is set to
false
, the component's background color is transparent. This means that any areas left untouched by the component's rendering allow graphics in the background to show through. If the property is set totrue
, the rectangular painting region is completely filled with the component's background color before it is rendered. Incidentally, transparency was not possible before lightweight components. Native peer objects in Java 1.0 always drew their component on a solid rectangle; anything that was behind the component was erased. Figure 3-5 shows the difference between an opaque and a transparent (nonopaque) label, both with a dark background color. The label on the left is transparent, so its background color is ignored; the label's text appears on top of the container's relatively light background.[1] In JDK 1.2, the
isOpaque( )
method is defined injava.awt.Component
.Figure 3-5. Transparency and opaqueness
JComponent
can optimize its repainting time if none of its children overlap; this is because the repaint manager does not have to compute the hidden and visible areas for each child component before rendering them. Some containers, such asJSplitPane
, are designed so that overlap between child components is impossible, so this optimization works nicely. Other containers, such asJLayeredPane
, have support for child components that can overlap.JComponent
contains a property that Swing frequently calls upon to see if it can optimize component drawing:optimizedDrawingEnabled
. InJComponent
, this property is set totrue
by default. If overlap occurs in a subclass ofJComponent
, the subclass should override theisOptimizedDrawingEnabled( )
accessor and returnfalse
. This prevents the repaint manager from using the optimized drawing process when rendering the container's children.JComponent
contains a boolean read-only property (paintingTile
) that indicates whether the component is currently in the process of painting a tile , which is a child component that does not overlap any other children. TheisPaintingTile( )
method returnstrue
until all tiles have been painted.The
visibleRect
property is aRectangle
that indicates the intersection of the component's visible rectangles with the visible rectangles of all of its ancestors. Why the intersection? Remember that you can have a contained object that is clipped by its parent. For example, you can move an internal frame so that a portion of it falls outside the parent window's clipping region. Therefore, the visible portion (the portion that is actually drawn to the screen) consists only of the intersection of the parent's visible portion and the child's visible portion. You typically do not need to access this property.The
validateRoot
property isfalse
by default. If it is set totrue
, it designates this component as the root component in a validation tree. Recall that each time a component in a container is invalidated, its container is invalidated as well, along with all of its children. This causes an invalidation to move all the way up the component hierarchy, stopping only when it reaches a component for whichisValidateRoot( )
returnstrue
. Currently, the only components that set this property totrue
areJRootPane
(which is used by all the Swing top-level components),JScrollPane
, andJTextField
.The
topLevelAncestor
property contains a reference to the top-level window that contains this component, usually aJWindow
orJApplet
. TherootPane
property contains the low-levelJRootPane
for this component;JRootPane
is covered in more detail in Chapter 8.Finally,