User Interface Problems
Swing Components
This section discusses problems that you might encounter while using Swing components.
Problem: I can't make HTML tags work in my labels, buttons, and so on.
- Make sure that your program is running in a release that supports HTML text in the desired component. (If you are using Java 2 SDK versions 1.2 or 1.3, you do not need to worry.)
- JCheckBox and JRadioButton don't support HTML yet. We don't know when that support will be added.
- If you can't guarantee that your program will be executed only with a release that supports HTML text in the desired component, don't use that feature!
Problem: Certain areas of the content pane look weird when they're repainted.
- If you set the content pane, make sure that it's opaque. JPanel and JDesktopPane make good content panes because they're opaque by default.
- If one or more of your components performs custom painting, make sure that you implemented it correctly. See The Java Tutorial online at http://java.sun.com/docs/books/tutorial/uiswing/painting/index.html for help.
- You might have a thread safety problem. See the next entry.
Problem: My program is exhibiting weird symptoms that sometimes seem to be related to timing.
- Make sure that your code is thread-safe. See Threads and Swing (page 378) for details.
Problem: The scroll bar policies don't seem to be working as advertised.
- Some Swing releases contain bugs in the implementations for the policies VERTICAL_SCROLLBAR_AS_NEEDED and HORIZONTAL_SCROLLBAR_AS_NEEDED. If feasible for your project, use the most recent release of Swing.
- If the scroll pane's client can change size dynamically, the program should set the client's preferred size and then call revalidate on the client.
- Make sure that you specified the policy you intended for the orientation you intended.
Problem: My scroll pane has no scroll bars.
- If you want a scroll bar to appear all the time, specify one of the following scroll bar policies: VERTICAL_SCROLLBAR_ALWAYS or HORIZONTAL_SCROLLBAR_ALWAYS.
- If you want the scroll bars to appear as needed and you want to force the scroll bars to be needed when the scroll pane is created, you have two choices: (1) either set the preferred size of the scroll pane or its container, or (2) implement a scroll-savvy class and return a value smaller than the component's standard preferred size from the getPreferredScrollableViewportSize method. Refer to the section "Sizing a Scroll Pane" in The Java Tutorial online at http://java.sun.com/docs/books/tutorial/uiswing/components/scrollpane.html#sizing
Problem: The divider in my split pane won't move!
- You need to set the minimum size of at least one of the components in the split pane. Refer to the section "Positioning the Divider and Restricting Its Range" in The Java Tutorial online at http://java.sun.com/docs/books/tutorial/uiswing/components/splitpane.html#divider.
Problem: The setDividerLocation method doesn't work.
- Some releases of Swing have a bug whereby a call to setDividerLocation doesn't work unless the split pane is already on screen. For information and possible workarounds, see bug #4101306 and bug #4182558 in the Bug Parade at the Java Developer's Connection at http://developer.java.sun.com/.
Problem: The borders on nested split panes look too wide.
- If you nest split panes, the borders accumulate. The border of the inner split panes display next to the border of the outer split pane, causing borders that look extra wide. The problem is particularly noticeable when nesting many split panes. The workaround is to set the border to null on any split pane that is placed within another split pane. For information, see bug #4131528 in the Bug Parade at the Java Developer's Connection online at http://developer.java.sun.com/.
Problem: The buttons in my tool bar are too big.
- Try reducing the margin for the buttons. For example:
button.setMargin(new Insets(0,0,0,0));
Problem: The components in my layered pane aren't layered correctly. In fact, the layers seem to be invertedthe lower the depth, the higher the component.
- This can happen if you use an int instead of an Integer when adding components to a layered pane. To see what happens, make the following change to LayeredPaneDemo.
Change this:
to this:
layeredPane.add(label, new Integer(i));
layeredPane.add(label, i);
Problem: The method call colorChooser.setPreviewPanel(null) does not remove the color chooser's preview panel as expected.
- A null argument specifies the default preview panel. To remove the preview panel, specify a standard panel with no size, like this:
colorChooser.setPreviewPanel(new JPanel());
Layout
Problem: How do I specify a component's exact size?
- First, make sure that you really need to set the component's exact size. Each Swing component has a different preferred size, depending on the font it uses and the look and feel. Therefore, it often doesn't make sense to specify a Swing component's exact size.
- If the component isn't controlled by a layout manager, you can set its size by invoking the setSize or the setBounds method on it. Otherwise, you need to provide size hints and then make sure that you're using a layout manager that respects the size hints.
- If you extend a Swing component class, you can give size hints by overriding the component's getMinimumSize, getPreferredSize, and getMaximumSize methods. What's nice about this approach is that each getXxxx Size method can get the component's default size hints by invoking super.getXxxx Size(). Then it can adjust the size, if necessary, before returning it.
- Another way to give size hints is to invoke the component's setMinimumSize, setPreferredSize, and setMaximumSize methods.
If you specify new size hints for a component that's already visible, you then need to invoke the revalidate method on it, to make sure that its containment hierarchy is laid out again. Then invoke the repaint method.
Note
No matter how you specify your component's size, be sure that your component's container uses a layout manager that respects the requested size of the component. The FlowLayout and GridBagLayout managers use the component's preferred size (the latter depending on the constraints that you set), but BorderLayout and GridLayout usually don't. The BoxLayout manager generally uses a component's preferred size (although components can be larger) and is the only layout manager that respects the component's maximum size.
Problem: My custom component is being sized too small.
- Does the component implement the getPreferredSize and the getMinimumSize methods? If so, do they return the correct values?
- Are you using a layout manager that can use as much space as is available? See the section Using Layout Managers (page 375) for some tips on choosing a layout manager and specifying that it use the maximum available space for a particular component.
Event Handling
This section discusses problems that you might encounter while handling events.
Problem: I'm trying to handle certain events from a component, but the component isn't generating the events it should.
- First, make sure that you registered the correct kind of listener to detect the events. See whether another kind of listener might detect the kind of events you need.
- Make sure that you registered the listener on the correct object.
- Did you implement the event handler correctly? For example, if you extended an adapter class, make sure that you used the correct method signature. Make sure that each event-handling method is public void, that the name is spelled correctly, and that the argument is of the correct type.
- If you still think that the component isn't generating the events it should, check the Java Developer Connection [1] to see whether this is a known bug.
[1] You can find the Java Developer Connection online at http://developer.java.sun.com
Problem: My combo box isn't generating low-level events, such as focus events.
- Combo boxes are compound componentscomponents implemented using multiple components. For this reason, combo boxes don't fire the low-level events that simple components fire.
Problem: The document for an editor pane (or text pane) isn't firing document events.
- The document instance for an editor pane or text pane might change when loading text from a URL. Thus, your listeners might be listening for events on an unused document. For example, if you load an editor pane or text pane with HTML that was previously loaded with plain text, the document will change to an HTMLDocument instance. If your program dynamically loads text into an editor pane or a text pane, make sure that the code adjusts for possible changes to the document (reregister document listeners on the new document, and so on).
Swing Graphics
Problem: I don't know where to put my painting code.
- Painting code belongs in the paintComponent method of any component descended from JComponent. See "Overview of Custom Painting" in The Java Tutorial online at: http://java.sun.com/docs/books/tutorial/uiswing/painting/overview.html.
Problem: The stuff I paint does not show up.
- Check whether your component is showing up at all. The section Swing Components (page 399) in this appendix should help you with this problem.
- Check whether your component is obscured by another component. For example, you shouldn't put painting code in a JFrame or a JDialog subclass, because it will be covered by the applet's frame or content pane.
Problem: The background of my applet shows up, but the stuff in the foreground does not show up.
- Did you make the mistake of performing painting directly in a JApplet subclass? If so, your contents will be covered by the content pane that is automatically created for every JApplet instance. Instead, create another class that performs the painting and then add that class to the JApplet's content pane. For more information on how painting in Swing works see The Java Tutorial online at http://java.sun.com/docs/books/tutorial/uiswing/overview/draw.html.
Problem: My component's foreground shows up, but its background is invisible. The result is that one or more components directly behind my component are unexpectedly visible.
- Make sure that your component is opaque. JPanels, for example, are opaque by default. To make other components, such as JLabels, opaque, you must invoke setOpaque(true) on them.
- If your custom component extends JPanel or a more specialized JComponent descendant, you can paint the background by invoking super.paintComponent before painting the contents of your component.
- You can paint the background yourself, using this code at the top of a custom component's paintComponent method:
g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(getForeground());
Problem: I used setBackground to set my component's background color, but it seemed to have no effect.
- Most likely, your component isn't painting its background either because it's not opaque or your custom painting code doesn't paint the background. If you set the background color for a JLabel, for example, you must also invoke setOpaque(true) on the label to make the label's background be painted. For more help, see the preceding problem.
Problem: I'm using the exact same code as a tutorial example, but it doesn't work. Why?
- Is the code executed in the exact same method as the tutorial example? For example, if the tutorial example has the code in the example's paintComponent method, this method might be the only place where the code is guaranteed to work.
Problem: How do I paint thick lines? Patterns?
- The Java 2D API provides extensive support for implementing line widths and styles, as well as patterns for use in filling and stroking shapes. See the "2D Graphics" trail for more information on using the Java 2D API. [1]
[1] The 2D trail is available in the book The Java Tutorial Continued and online at http://java.sun.com/docs/books/tutorial/2d/index.html.
Swing Conversion
For information on converting your programs to Swing, see the book The JFC/Swing Tutorial or the online tutorial at http://java/sun/com/docs/books/tutorial/uiswing/converting.
Problem: I'm seeing weird problems that are either intermittent or dependent on timing.
- Does your main thread modify the GUI after it's visible? If so, either move the code so that it executes before the GUI is shown, or execute the GUI-modifying code in the event-dispatching thread.
- Does your program have multiple threads or query/modify the GUI in response to messages from other programs? If so, you should ensure that all GUI-related code is executed in the event-dispatching thread.
- If your program is an applet that implements the stop and start methods, make sure that any GUI work performed by those methods is executed in the event-dispatching thread.
- The preceding suggestions assume that your problem is caused by code that isn't thread safe. See the section Threads and Swing (page 378) for information about thread safety for information about API you can use to help make your programs thread safe.
Problem: My applet/dialog/frame is blank.
- Does the applet/dialog/frame perform custom drawing? If so, you need to move the custom drawing code out of the JApplet/JDialog/JFrame subclass and into a custom component that you add to the content pane.
- Do you either set the applet/frame/dialog's content pane or add components to the existing content pane? See Your First Swing Program (page 353) for more information.
Problem: In the Swing version of my program, the list/text component is missing its scroll bars.
- Swing list and text components don't have automatic scroll bars. Instead, you need to add the list or text component to a scroll pane.
Problem: Although I'm using the same grid bag layout code as before, one scrollable component is tiny.
- Make sure that you set constraints on the scroll pane rather than on its client.
Problem: I'm not getting the kinds of events I expected for the Swing component I'm using.
- Read both the conversion tips and how-to section for the component you're using. Chances are, the relevant event details are covered in those sections.
- If you think that the problem might be a bug, search the bug database at the Java Developer Connection at http://developer.java.sun.com/.