Java Platform, Standard Edition Troubleshooting Guide
Contents    Previous    Next

13.2 Specific Debug Tips for Swing

This topic discusses some specific debugging tips for Swing and provides illustration examples for possible issues and workarounds. The following topics describe problems in Swing and troubleshooting techniques:

13.2.1 Incorrect Threading

Random exceptions and painting problems are usually the result of incorrect threading usage of Swing. All access to Swing components, unless specifically noted in the javadoc, must be done on the event dispatch thread. This includes any models (TableModel, ListModel, and others) that are attached to Swing components.

The best way to check for bad usage of Swing is by way of an instrumented RepaintManager, as illustrated in Example 13-1.

13.2.2 JComponent Children Overlap

Another possible source of painting problems can occur if you allow children of a JComponent to overlap. In this case the parent must override isOptimizedDrawingEnabled to return false. If you do not override isOptimizedDrawingEnabled, components can randomly appear on top of others, depending upon which one repaint was invoked on.

13.2.3 Display Update

Another source of painting problems can occur if you do not invoke repaint correctly when you need to update the display. Changing a visible property of a Swing component, such as the font, will trigger a repaint or revalidate. If you are writing a custom component, you must invoke repaint and possibly revalidate whenever the display or sizing information has been updated. If you do not, the display will only update the next time someone triggers a repaint.

A good way to diagnose this is to resize the window. If the content appears after a resize, it implies that the component did not invoke repaint or revalidate correctly.

13.2.4 Model Change

Just as you do not need to invoke repaint when you change a visible property of a Swing component, you also need not invoke repaint when your model changes. If your model sends out the correct change notification, the JComponent will invoke repaint or revalidate as appropriate.

However, if you change your model but do not send out a notification, a repaint event may not even work. In particular this will not work with JTree. The correct thing to do is to send out the appropriate model notification. This can usually be diagnosed by again resizing the window and noticing that the display has not updated correctly.

13.2.5 Add or Remove Components

When you add or remove components, you need to invoke repaint or revalidate. Swing and AWT will not invoke repaint or revalidate in these situations, and therefore you must invoke them yourself.

13.2.6 Opaque Override

Another possible area of painting problems is if a component does not override opaque.

Further, if you do not invoker super's implementation you must honor the opaque property, that is if this component is opaque, you must completely fill in the background in a non-opaque color. If you do not honor the opaque property you will likely see visual artifacts.

The only way to check for this is to look for consistent visual artifacts when the component invokes repaint.

13.2.7 Permanent Changes to Graphics

Do not make any permanent changes to a Graphics passed to paint, paintComponent, or paintChildren. Here is the documentation warning on this:

If you override this in a subclass you should not make permanent changes to the passed in Graphics. For example, you should not alter the clip Rectangle or modify the transform. If you need to do these operations you may find it easier to create a new Graphics from the passed in Graphics and manipulate it.

Not honoring this restriction will result in clipping or other weird visual artifacts.

13.2.8 Custom Painting and Double Buffering

Although you can override paint and do custom painting in the override, you should instead override paintComponent. The JComponent.paint method ensures that painting happens to the double buffer. If you override paint directly, you may lose double buffering.

13.2.9 Opaque Content Pane

Swing's painting architecture requires an opaque content pane. Here is the documentation:

The painting architecture of Swing requires an opaque JComponent to exist in the containment hierarchy above all other components. This is typically provided by way of the content pane. If you replace the content pane, it is recommended that you make the content pane opaque by way of setOpaque(true). Additionally, if the content pane overrides paintComponent, it will need to completely fill in the background in an opaque color in paintComponent.

13.2.10 Renderer Call for Each Cell Performance

Renderers are painted for each cell, so ensure that the renderer does as little as possible. Any slowdown in the renderer is magnified across all cells. For example, if you repaint the visible region of a table with 50x20 visible cells, there will be 1000 calls to the renderer.

13.2.12 Mix Heavywight and Lightweight Components

Mixing heavyweight and lightweight components can work in certain scenarios, primarily as long as the heavyweight component does not overlap with any existing Swing components. For example, a heavyweight will not work in an internal frame, because when the user drags around the internal frame it will overlap with other internal frames. If you do use heavyweights, invoke the following methods:

  • JPopupMenu.setDefaultLightWeightPopupEnabled(false)

  • ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false)

13.2.13 Use Synth

Synth is an empty canvas. To use Synth you must either provide a complete XML file that configures the look and feel, or extend SynthLookAndFeel and provide your own SynthStyleFactory.

13.2.14 Track Activity on Event Dispatch Thread

If a Swing application tries to do too much on the event dispatch thread, the application will appear sluggish and unresponsive.

One way to detect this situation is to push a new EventQueue that can output logging information if an event takes too long to process. This approach is not perfect in that it has problems with focus events and modality, but it is good for ad-hoc testing.

13.2.15 Specify Default Layout Manager

Problems can be caused by differing default layout manager classes on a Swing component. For example, the default for the JPanel class is FlowLayout, but the default for the JFrame class is BorderLayout. This situation is easily fixed by specifying a LayoutManager.

13.2.16 Listener Object Dispatched to Incorrect Component

MouseListener objects are dispatched to the deepest component that has MouseListener objects (or has enabled MouseEvent objects). A ramification of this is that if you attach a MouseListener to a component whose descendants have MouseListener objects, your MouseListener object will never get called.

This is easily reproduced with a composite component, like an editable JComboBox. Because a JComboBox has child components that have a MouseListener, a MouseListener attached to an editable JComboBox will never get notified.

If your MouseListener suddenly stops getting events, it could be the result of a change in the application whereby a descendant component now has a MouseListener. A good way to check for this is to iterate over the descendants asking if they have any mouse listeners.

A similar scenario occurs with the KeyListener class. A KeyListener object is dispatched only to the focused component.

The JComboBox case is another example of this situation. In the editable JComboBox case the editor gets focus, not the JComboBox. As a result, a KeyListener attached to an editable JComboBox will never get notified.

13.2.17 Add a Component to Content Pane

Prior to J2SE 1.5 you could not add a component to a JFrame, JWindow, JDialog or JApplet. Instead, you needed to add the component to the content pane. As of J2SE 1.5 it is still the case that a component added to a top-level Swing component must go to the content pane, but the add method (and a couple of other methods) on these classes redirect to the content pane. In other words, doing frame.getContentPane().add(component) is the same as frame.add(component).

The following methods redirect to the content pane for you: add (and its variants), remove (and its variants), and setLayout.

This is purely a convenience, but can cause confusion. In particular, getChildren, getLayout, and various others do not redirect to the content pane.

This change impacts LayoutManagers that only work with one component, such as GroupLayout and BoxLayout. For example, new GroupLayout(frame) will not work; instead, you need to do new GroupLayout(frame.getContentPane()).

13.2.18 Drag and Drop Support

When using Swing you should use Swing's drag-and-drop support as provided by TransferHandler. Otherwise, you will have to manage the selection and various other issues.

13.2.19 One Parent for a Component

Remember that a component can only exist in one parent at a time. Problems occur when you attempt to share menu items between menus. For example, JMenuItem is a component, and therefore can exist in only one menu at a time.

Contents    Previous    Next

Copyright © 1993, 2017, Oracle and/or its affiliates. All rights reserved.