United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4144505 : Compound components don't behave properly

Submit Date:
Updated Date:
Project Name:
Resolved Date:
Won't Fix
Affected Versions:
Fixed Versions:

Related Reports

Sub Tasks

Swing components that are composed of other components behave inconsistently compared to simple Swing components.  An example of a compound component is JComboBox.  JComboBox has an edit field and an arrow button contained within itself.  The edit field and the button are children of the JComboBox.

Compound components have the following problems:
1) They confuse event handling by having multiple sources.
2) They stop tool tips from working properly.
3) Setting cursors on them will cause strange behavior.
4) They are very difficult to initialize.

Problem #1: They confuse event handling by having multiple sources.
People have been registering mouse and keyboard listeners with JComboBoxes.  When the user clicks on the arrow button the events come from the arrow button, not the JComboBox.  This has been confusing developers.  They expect event handling to be the same for all Swing components regardless of how they were implemented.  In fact, whether or not a component is a compound component is totally dependent on the UI delegate.  If one L&F doesn't use children to create the component then a developer can't rely on the fact that it's compound or not when they decide to attach listeners to it.

Problem #2: They stop tool tips from working properly.
Tool tips suffer from a similar problem to event handling.  If a developer puts a tool tip on an editable JComboBox, the tool tip will only appear if the cursor is over the combo box but not over the arrow button or the edit field.

Problem #3: Setting cursors on them will cause strange behavior.
Trying to set a cursor on an editable combo box will result in behavior similar to tool tips.  The cursor will only appear if the cursor is over the combo box but not over the arrow button or the edit field.

Problem #4: They are very difficult to initialize
In order for a compound component to be properly initialized during a Look & Feel switch, an invokeLater() call must be used to initialize the child components.  The way that component-trees are updated during a L&F switch (using SwingUtilities.updateComponetTreeUI) causes this to be a problem.  I'll use JComboBox as an example:

1.  updateComponetTreeUI() tells the JComboBox to update its UI
2.  A ComboBoxUI subclass gets created
3.  The ComboBoxUI adds some child components to the JComboBox (like the editor)
4.  The ComboBoxUI initializes the child components with fonts and colors
5.  updateComponentTreeUI() asks the JComboBox's children to update their UIs
6.  JComboBox's children now make new UI delegates
7.  The new UI delegates re-initialize the child components with values from the defaults table.

The ComboBoxUI set values in the children but they were later wiped out because the children were asked to create new delegates who re-initialized the children.

tom.santos@eng 1998-06-01

Name: krT82822			Date: 06/28/99

setEnabled is inconsistant between JComponents.
For most components(All the ones I checked), Components will still generate events when setEnabled(false) is called
This does not occur for JComboBox though.

If you run this program as is, clicking will not generate a mouse event.
Change variable0 to any other component(eg: a JButton), and it will

(test case follows at end, but the next section summarizes additional comments from the user received 6/28/99 [6/29 in user's timezone]):

> Subject: Re: [Re: (Review ID: 53321) setEnabled does not work correctly with JComboBox]
> Date:  29 Jun 99 09:27:21 WST
> From:  Daniel Fletcher <###@###.###>

Basically I believe that when the JComboBox is disabled, it should begreyed
out, and clicking shouldnt change it in any way, but the mouseEvents should
still be generated and sent to any listeners.

My reason for wanting this?
I was making a GUI builder called
which allowed you to move and drag components around.

For all components except JCombobox, I was able to disable the Component, and
then let the user drag it around when they clicked in it etc.

For JCombobox once the component was disabled, clicking in it would not
generate mouse events, so I couldnt catch them, and thus it couldnt be

I think the correct behaviour would be the same as the other components.
Consistency is defintely the way to go, so if you do decide to continue not
generating mouse events, you should do it for all other components as
well(Even though it will totally break my application :)



import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

class Test extends JPanel implements MouseListener

	public Test()

	//Call this method to setup the GUI
	public void setupGUI()
		BorderLayout layout1 = new BorderLayout();
		variable0 = new JComboBox();
		add(variable0 , "Center");


	public static void main(String args[])
		JFrame f=new JFrame();
		Test t=new Test();
		f.getContentPane().setLayout(new BorderLayout());

	public void mouseClicked(MouseEvent e)

	public void mouseEntered(MouseEvent e)

	public void mouseExited(MouseEvent e)

	public void mousePressed(MouseEvent e)
		System.out.println("Mouse pressed");

	public void mouseReleased(MouseEvent e)

	private JComponent variable0;
(Review ID: 53321)

Name: rlT66838			Date: 09/28/99

Since the JDK 1.1.8 is impossible to intercept the keyboard event in the JComboBox component.

see the example :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MyComboBox extends JFrame implements KeyListener
    public MyComboBox()
        getContentPane().setLayout(new GridLayout(1, 2));
        addWindowListener(new WindowAdapter()
           public void windowClosing(WindowEvent e)

        JComboBox myComboBox = new JComboBox();

    public static void main(String arg[]) {new MyComboBox();}
    public void keyPressed(KeyEvent e) {System.out.println("keyPressed");}
    public void keyReleased(KeyEvent e) {System.out.println("keyReleased");}
    public void keyTyped(KeyEvent e) {System.out.println("keyTyped");}
(Review ID: 95842)



    component that has a glass pane, like the one provided by
      JRootPane.  The glass pane is a simple transparent JPanel
      that absorbs mouse and keyboard events, and displays the busy
      cursor.  The BusyPanel stacks the glass pane on top of its other 
      child.  Setting the BusyPanel "busy" property to true makes the 
      glass pane visible which means that it's busy cursor appears and 
      begins getting all mouse and keyboard events.  The BusyPanel
      also temporarily assigns the focus to the glass pane.

class BusyPanel extends JPanel 
    private Component oldFocusOwner = null;
    private final JComponent child;
    private final JPanel glass; 
    private final BlockEvents blockEventsListener;

    private void beep() { 

    private class BlockEvents extends MouseAdapter implements KeyListener {
	public void mousePressed(MouseEvent e) { beep(); }
	public void keyPressed(KeyEvent e) { beep(); }
	public void keyReleased(KeyEvent e) { }
	public void keyTyped(KeyEvent e) { }

    public BusyPanel(JComponent c) {
	super(new BorderLayout());
	child = c;
	blockEventsListener = new BlockEvents();

	glass = new JPanel(null);

	add(glass, 0);  // glass is on top, but not visible
	add(child, 1);  // child is below the glass

    public void setBusy(boolean busy) {
	if (isBusy() != busy) {
	    if (busy) {
		oldFocusOwner = SwingUtilities.findFocusOwner(this);
	    else if (oldFocusOwner != null) {

    public boolean isBusy() {
	return glass.isVisible();

    public boolean isOptimizedDrawingEnabled() {
	return false;

    public Dimension getPreferredSize() {
	return child.getPreferredSize();

    public Dimension getMinimumSize() {
	return child.getMinimumSize();

    public Dimension getMaximumSize() {
	return child.getMaximumSize();

    public void doLayout() {
	glass.setBounds(0, 0, getWidth(), getHeight());
	child.setBounds(0, 0, getWidth(), getHeight());

      Here are few notes about the BusyPanel implementation:

	Layout is very simple so we don't bother we a layout
	manager. The preferred, minimum, and maximum size computations
	are delegated to the child, and the doLayout method just
	ensures that the glass pane and the child have the same size
	as the BusyPanel itself.

	The glass panes opaque property is set to false so that it's
	background will not be cleared.  This is all that's needed to
	ensure that the glass pane JPanel is transparent.

	The BusyPanel class does not "tile" it's children as most
	containers do so we override the
	<code>isOptimizedDrawingEnabled</code> to return false.  This
	isn't absolutely neccessary since the glass pane is

    <h2>JComboBox and SwingUtilities.updateComponentTreeUI</h2>

      The SwingUtilities.updateComponentTreeUI() method is commonly used to
      switch the look and feel of a tree of components.  Unfortunately it
      just blindly walks from the root of the tree and sets the UI property
      of all descendants - even if they're just parts of a compound
      component.  For example when the UI of a JComboBox is set the L&F
      implementation adds subcomponents like the arrow button and the
      item text field.  When the updateComponentTreeUI redundantly sets
      the UI property of the subcomponents, the color/font/etc configuration
      created by the BasicComboBoxUI is lost.

      This problem was "fixed" in Swing by using EventQueue.invokeLater to
      initialize combo box subcomponents however this can cause
      secondary problems and it's inefficient.  What's really needed
      is a way to identify compound components so that utility methods 
      like updateUI can avoid descending into them.  This distinction
      is available in the BeanInfo classes for Swing components
      however one can't assume that the BeanInfo classes
      (e.g. JComboBoxBeanInfo) will be available in a normal
      application environment.

      In the next Java release we plan to remove the invokeLater
      workaround and either provide a way to programatically identify
      compound Swing components or move the special case to 

    <h2>Should Listeners in a Disabled Component Receive Events?</h2>

      The AWT lightweight component support doesn't prevent disabled
      components from receiving any of events defined by the listeners
      on java.awt.Component and java.awt.Container (and
      java.awt.Window).  Obviously Swing components will not fire
      higher level listeners when disabled, e.g. a JButtons
      ActionListener will not run when the button has been disabled.
      This effect is produced by the mouse/keyboard listeners
      installed by the components L&F.  When the component is
      disabled, input that would trigger a higher level listener is

      Adding an AWT event listener to a compound component like
      JComboBox, may be ineffective because some of the L&F
      implementations pack the JComboBox with subcomponents.  The
      subcomponents usually absorb mouse and keyboard events, whether
      or not the JComboBox is disabled.

      Ofcourse we don't believe that adding event listeners to a
      compound component is an effective way to customize a compound
      component, see the "Adding Listeners to a JComboBox" above.

    <address><a href="mailto:###@###.###">Hans Muller</a></address>
<!-- Created: Tue Feb 29 10:49:30 PST 2000 -->
<!-- hhmts start -->
Last modified: Thu Mar  9 17:17:28 PST 2000
<!-- hhmts end -->

hans.muller@Eng 1998-06-02
This is a basic design flaw (perhaps "choice") in Swing.  Providing a general
solution that enabled users to treat composites as simple mouse or
keyboard listeners could significantly complicate the Swing implementation.
Alternatively we specify that this sort of support was only available for
a small number of Simple Swing components, e.g. JLabel.  I think the latter
is the only reasonable choice until after JDK1.2 has shipped.

Here's the final evaluation.  It's long, it's HTML; you have my
apologies.  Please send comments to ###@###.###.
hans.muller@Eng 2000-03-09

    <title>Bug 4144505: Problems With Compound Components, Notably JComboBox </title>

  <body bgcolor="white">
    <h1>Bug 4144505: Problems With Compound Components, Notably JComboBox </h1>

      This article discusses many of the common problems developers
      have had with compound components, notably JComboBox.   The
      focus of the articles is the list of bugs that were collapsed
      (as duplicates) into bug report 4144505.

	Bug 4144505 
      was originally submitted as 
	bug 4110721
      against an early version of Swing 1.1 in February 1998.  Six
      months later bug 4144505 was created by a Swing developer as a
      catch-all for bugs that were effectively caused by the Swing
      "compound component" implementation of several components,
      notably JComboBox.  This had the good effect of centralizing all
      of the complaints related to this Swing implementation feature
      however it had the very bad effect of creating a bug report that
      wasn't likely to ever be closed.  Although some of the problems
      that fell under the bug 4144505 umbrella were corrected, the bug
      report persists to this day because some of the 12 bugs that
      fell into this sinkhole are still open.

      This document is an attempt to address the issues raised by bug
      4144505.  We plan to close the bug and open a small set of RFEs
      (two) that cover missing features that were identified here.
      The RFEs will be committed for the 1.4 release of 'Java2
      Standard Edition' (J2SE), also known as "Merlin".  

      The remaining sections review each of the bug 4144505 issues and
      our proposals for resolving them.  

    <h2>Adding Listeners to a JComboBox</h2>

      Adding AWT event listeners (like mouse and keyboard listeners)
      to a JComboBox doesn't give one access to all of the events
      associated with the combo box. Adding a listener a JComboBox and
      all of its descendants gives one access to events associated
      with the (non dynamically generated) parts of the combo box
      however it's difficult to intepret the events because they come
      from look and feel specific subcomponents.  This approach
      carries an additional penalty after a dynamic L&F switch because 
      the listeners added to descendants of the JComboBox aren't
      restored after the new UI delegate has been created.

      We do not believe that, in general, one can add a mouse or
      keyboard event listener to a complex or compound Swing component
      without creating an undesirable dependency on the components
      look and feel (L&F) and on its implementation.  On the other
      hand many of the developers who were struggling with this had
      legitimate reasons for doing so.  In most cases they were
      attempting to compensate for the lack of higher level listeners
      in JComboBox, and in a few cases for JComboBox bugs.  Here's a
      list of the problems we observed and how we plan to address them.

    <h3>Input Verification</h3>
      The motivation for adding focus, mouse, or key event listeners
      was often to enable input verification or to track the value
      of the editor part of an editable combo box.  The idea was that if
      one could detect when the user was effectively moving the focus
      to another component, the current value of the combo box could
      be checked and forced back to the combo box if invalid.

      Explicit support for input verification was added for the 1.3
      (Kestrel) release of J2SE.  There's a 
      <a href="http://www.theswingconnection.com">
	Swing Connection article
      that describes the new input verification API .

      One can use the input verififcation facility with an editable
      combo box by setting the <code>inputVerifier</code> property
      of the combo boxes <code>editor</code>.  In the example below
      the verifier only allows a focus change if the one of the first
      three items was selected:

InputVerifier checkInput = new InputVerifier() {
    public boolean verify(JComponent c) {
	return comboBox.getSelectedIndex() < 2;
    public boolean shouldYieldFocus(JComponent c) {
	boolean ok = verify(c);
	if (!ok) {
	return ok;
Component editor = comboBox.getEditor().getEditorComponent();
if (editor instanceof JTextField) {

      This approach only verifies the input when the user attempts to
      tab out of the editors textfield and it only works if the
      current L&F uses a JTextField to implement the editor.  Although
      all of the L&F implementations we know of use a JTextField, one
      could safeguard against the unexpected and deal with dynamic L&F
      switching by creating a custom ComboBoxEditor.  Here's an example:

class MyComboBoxEditor implements ComboBoxEditor 
    private final JTextField editor;

    MyComboBoxEditor() {
	editor = new JTextField("", 9);

        // Configure the editors inputVerifier or whatever else 
        // you want here.

    public Component getEditorComponent() {
        return editor;

    public void setItem(Object item) {
	editor.setText((item != null) ? item.toString() : "");

    public Object getItem() {
	String s = editor.getText().trim();
	return (s.length() == 0) ? null : s;

    public void selectAll() {

    public void addActionListener(ActionListener l) {

    public void removeActionListener(ActionListener l) {

    <h3>Customizing ComboBox Editor Behavior</h3>

      A common reason for attempting to install a KeyListener on a
      JComboBox is to customize or override the default key bindings.
      <a href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">
	new key binding architecture
      introduced in J2SE 1.3, makes this easy to do.  The bindings
      used by JComboBox are defined in a input map that's consulted
      when the JComboBox is the ancestor of the focused component.
      To add a new key binding, we add an entry to the combo boxes
      <code>InputMap</code> for the <code>KeyStroke</code> which maps
      from the key to the name of an action, and we add the action to
      the combo boxes <code>ActionMap</code>.  In the example below
      we've added a binding for VK_F1, that's the "F1" function key,
      that selects the first item in the list:

Action selectFirstAction = new AbstractAction("Select First Item") {
    public void actionPerformed (ActionEvent e) {

InputMap inputMap = comboBox.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke("F1"), "selectFirst");

ActionMap actionMap = comboBox.getActionMap();
actionMap.put("selectFirst", selectFirstAction);
      It's easy to override predefined actions with the same
      mechanism.  For example JComboBox defines an action for
      "selectNext", which is usually mapped to the down arrow key,
      that pops up the drop down menu or selects the next item in the
      list.  The up arrow ("selectPrevious") mapping is similar.  To
      customize the menu so that the arrow keys just move the
      selection up and down, without showing the drop down menu, we
      can just override the bindings for "selectNext" and

Action upAction = new AbstractAction("Select Previous Item") {
    public void actionPerformed (ActionEvent e) {
	int i = comboBox.getSelectedIndex();
	if (i == -1) {
	else if (i == 0) {
	    comboBox.setSelectedIndex(comboBox.getItemCount() - 1);
	else {
	    comboBox.setSelectedIndex((i - 1) % comboBox.getItemCount());

Action downAction = new AbstractAction("Select Next Item") {
    public void actionPerformed (ActionEvent e) {
	int i = comboBox.getSelectedIndex();
	if (i == -1) {
	else {
	    comboBox.setSelectedIndex((i + 1) % comboBox.getItemCount());

ActionMap actionMap = comboBox.getActionMap();
actionMap.put("selectPrevious", upAction);
actionMap.put("selectNext", downAction);

    <h3>Dynamic Creation of the Menu</h3>

      Developers often try adding mouse listeners to JComboBox or a
      mouse/action listener to the combo boxes arrow button descendant 
      because they want to be notified just before the drop down menu
      pops up.  Usually the notification triggers some code that
      dynamically populates the ComboBoxModel.

      In some cases this isn't strictly neccessary, because the
      ComboBoxModel itself can be a view on dynamic data.  

      In other cases it's either more convenient or just simpler to
      have the combo box notify the application before the menu drops
      down.  We've created an RFE to address this problem, it's:
	4287690 - JComboBox should send a drop down event.
      We plan to add a PopupMenuListener to JComboBox for the Merlin
      release which should address this problem nicely.

    <h2>JComboBox and ToolTips</h2>

      Setting a tooltip on an editable combo box didn't work
      correctly - the tooltip doesn't appear when the mouse is over
      the arrow button.

      This was fixed in January of 1999 (SCCS version 1.95 of
      BasicComboBoxUI.java).  BasicComboBoxUI agressively sets the
      tooltip text on the descendants of JComboBox whenever the
      JComboBox toolTipText property changes.

    <h2>JComboBox and Cursors</h2>

      Setting the cursor on JComboBox fails to change the cursor for the
      editable text field (if the combo box is editable) or for the
      the drop down menu.  The cursor does change over the arrow button
      and the (not editable) selected item field.  

      This bug has not been fixed.  It's particularly difficult to address
      this problem because the java.awt.Component cursor property is not
      bound and the property has "inherited from component ancestor"
      semantics.  In other words the value of the cursor property for a
      component is the value of the first ancestors cursor that's not null,
      starting with the component itself.  This means that one can trivially
      change the cursor for all descendants of a container - <i>that haven't
      explicitly set their own cursor</i>.  Unfortunately this doesn't really
      match the one idiom that developers would often like to implement
      with a simple setCursor call - temporarily displaying a wait
      cursor for <b>all</b> descendants of a container.

      Here's a sketch of the idiom that gives many developers trouble.

JComboBox myComboBox = new JComboBox(new String[]{"doWork"});

Runnable doDisableMyComboBox = new Runnable() {
    public void run() {

Runnable doWork = new Runnable() {
    public void run() {
	// ... do something that takes a while

ActionListener doWorkAction = new ActionListener() {
    actionPerformed(ActionEvent e) {
	new Thread(doWork).start();


      In this example we'd like to temporarily disable the JComboBox while the 
      potentially long-running "doIt" action executes on a separate
      thread.  It's important that the action runs on a separate thread; if
      it didn't the "doIt" action would block event dispatching and 
      the application would appear to hang.  More to the point, the
      repainting that we'd like to see when the the combo box's enabled
      property changes wouldn't happen.

      Unfortunately there are some problems with the code in this sketch:

	Disabling components while the application is busy can be
	visually disruptive, particularly if a large number of
	components are temporarily disabled.  Additionally the enabled
	property does not have the inherited semantics we'd like in
	this situation, a component can be enabled even if it's parent
	is disabled.  We are considering a change to the Swing or the
	AWT that would provide a counterpart property for enabled that
	had inherited semantics, in roughly the same way the read-only
	java.awt.Component "showing" property provides inherited
	semantics for the Component visible property.  Here's the RFE:
	  4177727 - propagating disEnabled "event" to all children

	And just disabling the combo box may not be what you want
	anyway.  Typically one wants to take all or part of the
	application modal in a situation like this.  For example you
	might want to block all components that can be used to launch
	more work, but not the button that cancels work in progress.

	Although we could try and make the busy cursor appear, e.g. by 
	temporarily setting the cursor property of myComboBox and
	all of its descendants, temporarily defeating event processing 
	is messy.  One could temporarily remove all of the listeners 
	on myComboBox and its descendants, or temporarily replace the 
	event queue with one that didn't dispatch events to myComboBox
	and its descendants.  These solutions are just too painful to
	be practical. 

    <h3>A Solution</h3>

      Here's an example of a utility class that addresses this
      problem.  The <code>BusyPanel</code> is simple container for one 

Hardware and Software, Engineered to Work Together