JDK-4760078 : JComboBox with empty item list generates spurious ActionEvent when focus lost
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-10-08
  • Updated: 2005-06-22
  • Resolved: 2005-04-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b32Fixed
Related Reports
Relates :  
Description

Name: sv35042			Date: 10/08/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Not applicable

A DESCRIPTION OF THE PROBLEM :
A JComboBox with an empty item list generates a spurious
ActionEvent when the focus is lost.  I think this occurs
because:

a)	getItem() in BasicComboBoxEditor will never return
null, as can be seen from the following lines 61-81:
    public Object getItem() {
        Object newValue = editor.getText();
        
        if (oldValue != null && !(oldValue instanceof
String))  {
            // The original value is not a string. Should
return the value in it's
            // original type.
            if (newValue.equals(oldValue.toString()))  {
                return oldValue;
            } else {
                // Must take the value from the editor and
get the value and cast it to the new type.
                Class cls = oldValue.getClass();
                try {
                    Method method = cls.getMethod
("valueOf", new Class[]{String.class});
                    newValue = method.invoke(oldValue, new
Object[] { editor.getText()});
                } catch (Exception ex) {
                    // Fail silently and return the
newValue (a String object)
                }
            }
        }
        return newValue;
    }

b)	focusLost in EditorFocusListener in BasicComboBoxUI
only ducks out for the above returning null,  or the
currently selection item equaling the Editor item,  as can
be seen from lines 1559-1569 of the code:
        public void	focusLost( FocusEvent e ) {
	    ComboBoxEditor editor = comboBox.getEditor();
            Object item = editor.getItem();

            if (!e.isTemporary() && item != null &&
		!item.equals( comboBox.getSelectedItem())) {
                comboBox.actionPerformed
                    (new ActionEvent(editor, 0, "",
                                     
EventQueue.getMostRecentEventTime(), 0));
            }
        }

Seeing as the item returned by the editor is never null,
while the selected item from an empty list is null,  the
optout condition is not met,  and a spurious event is
generated.

The following code demos this.  Compile and run it,  click
in the combo,  then click in the text area.  An event is
generated the first time this is attempted,  because the
item list is still empty.  On subsequent trials,  the list
now has one spurious blank entry generated by the first try
bug,  and the optout condition then works as it is
comparing two blank strings.

I think the Editor should return a null where no input has
ever been received.  This would avoid the problem.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See full description

EXPECTED VERSUS ACTUAL BEHAVIOR :
See full description

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ComboBoxDemo extends JFrame
	{
	public static void main( String args[] )
		{
		JFrame frame = new ComboBoxDemo("JComboBox Bug Demo");
		}

	public ComboBoxDemo( String aTitle )
		{
		super( aTitle );
		addWindowListener(
							new WindowAdapter()
								{
								public void
windowClosing( WindowEvent e )
									{
								
	System.exit(0);
									}
								}
						);

		MyComboBox theComboBox = new MyComboBox();
		getContentPane().setLayout( new BorderLayout() );
		getContentPane().add( new JTextArea( "Something that can
receive focus ..." ), BorderLayout.CENTER );
		getContentPane().add( theComboBox, BorderLayout.SOUTH );

		pack();
		theComboBox.requestFocus();
		setVisible(true);
		}

	protected class MyComboBox extends JComboBox
		{
		protected MyComboBox()
			{
			super();
			setEditable( true );
			addActionListener	(
									new
ActionListener()
										
	{
										
	public void actionPerformed( ActionEvent ae )
										
		{
										
		System.out.println( "ActionEvent:" + ae );
										
		String input = getInput();
										
		System.out.println( "Input:      " + input );
										
		}
										
	}
								);
			} // protected MyComboBox()

		protected String getInput()
			{
			String theInput = (String)getEditor().getItem();

			insertItemAt( theInput, 0 );
			for( int i = 1; i < getItemCount(); i++ )
				if( theInput.equalsIgnoreCase( (String)getItemAt
(i) ) )
					removeItemAt( i-- );
			while( getItemCount() > PREVIOUSCOMMANDS )
				removeItemAt( PREVIOUSCOMMANDS );

			setSelectedIndex(0);
			getEditor().selectAll();

			return theInput;
			}

		// The maximum number of previous commands to remember
		private	final int PREVIOUSCOMMANDS = 10;

		} // protected class MyComboBox extends JComboBox
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
It's trivial if you don't mind having at least one item in
the list from the start,  but if you do,  then there's no
easy workaround.

I tried extending BasicComboBoxEditor to override getItem
(),  but was screwed by the fact that oldValue is private
access ( it's the sort of value that should be protected,
not private )
(Review ID: 143279) 
======================================================================

Comments
SUGGESTED FIX http://sa.sfbay.sun.com/projects/swing_data/mustang/4760078.0/ ###@###.### 2005-03-14 16:27:25 GMT
14-03-2005

EVALUATION In 1.4, there are two ActionEvents that are invoked: comboBoxChanged, comboBoxEdited. In 1.3x, only the comboBoxChanged event is fired. ###@###.### 2002-10-09 BasicComboBoxUI.Handler.focusLost() could be changed to prevent event generation in this case. ###@###.### 2005-03-14 16:27:25 GMT ###@###.### 2005-03-14 17:08:35 GMT
14-03-2005