Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4337071
Votes 14
Synopsis Default Button does not work from JComboBox
Category java:classes_swing
Reported Against 1.3
Release Fixed 1.4(merlin-beta2)
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs
Submit Date 10-MAY-2000
Description




C:\>java -version
java version "1.3.0rc3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc3-Z)
Java HotSpot(TM) Client VM (build 1.3.0rc3-Z, mixed mode)

1.  Create a JFrame with one or more JTextFields and one or more JComboBoxes.
Also add one or more buttons and set one be default.  Add the code which will
pass the Enter key through to the default button.  When in a textbox, the enter
button gets fired, but not when in a combobox.

2.
//Title:      Bug Report
//Version:
//Author:     Freddie Schwenke
//Company:    infor
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;

//==============================================================================

public class BugApp
{

private JFrame frame = new JFrame();

private JTextField text1 = new JTextField(20);
private JTextField text2 = new JTextField(20);
private JComboBox combo1 = new JComboBox(new Object[] {"Item 1", "Item 2", "Item 3"});
private JComboBox combo2 = new JComboBox(new Object[] {"Item 1", "Item 2", "Item 3"});

private JButton okButton = new JButton("OK");
private JButton cancelButton = new JButton("Cancel");

private JPanel textPanel = new JPanel(new FlowLayout());
private JPanel buttonPanel = new JPanel(new FlowLayout());

static
{
  JTextField f = new JTextField();
  KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
  Keymap map = f.getKeymap();
  map.removeKeyStrokeBinding(enter);
}

//------------------------------------------------------------------------------

public BugApp()
{
  frame.getContentPane().setLayout(new BorderLayout());
  frame.setSize(new Dimension(400, 300));
  frame.setTitle("Frame Title");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  textPanel.add(text1);
  textPanel.add(text2);
  textPanel.add(combo1);
  textPanel.add(combo2);

  buttonPanel.add(okButton);
  buttonPanel.add(cancelButton);

  frame.getContentPane().add(textPanel, BorderLayout.CENTER);
  frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);

  frame.getRootPane().setDefaultButton(okButton);

// This is just to check when the OK Button was pressed.
  okButton.addActionListener(new ActionListener()
  {
    public void actionPerformed(ActionEvent ae)
    {
      System.err.println("OK Button pressed");
    }
  });

  combo1.setEditable(true);
  combo2.setEditable(false);
}

//------------------------------------------------------------------------------

public void show()
{
  frame.show();
}

//==============================================================================

//Main method
public static void main(String[] args)
{
  try
  {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
  }
  catch(Exception e)
  {
  }
  BugApp app = new BugApp();
  app.show();
}

//==============================================================================

}

3.  No Error, just nothing happened.

4.

5.  The problem occurred in RC1 as well, but there it was on Textboxes as
well.  The textboxes seems to be fine now.
(Review ID: 104680) 
======================================================================
Work Around
 ============================================================================     


This is a two step workaround:

 i.  In BasicComboBoxPopup.java , a dummy action for VK_ENTER is added to
     comboBox object which is in conflict with default button. 
     Reomve the dummy action using
     combo.unregisterKeyboardAction(enter);

ii.  Register new action for the editor (JTextField) in the JComboBox
    
       KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); 
       ActionListener act = new myAction(combo);
     
       JTextField it = (JTextField)combo.getEditor().getEditorComponent();
        it.registerKeyboardAction(act, "someAct", enter,
                              JComponent.WHEN_FOCUSED);
  
    where myAction is defined:
 class myAction implements ActionListener
 {
   JComboBox  box;

   myAction(JComboBox b) { box = b; }
   public void actionPerformed(ActionEvent e)
   {
     JRootPane r = ((JTextField)e.getSource()).getRootPane();
     JButton  b = r.getDefaultButton();
     b.doClick();
     System.out.println("From MyAction: " + r.getDefaultButton().getText() );
     //check if popup visible  then call hide
     if( box.isPopupVisible() == true )
     { System.out.println("Popup was visible" );
       box.hidePopup();
     }
   }
}
=====================================================================



Haven't found any yet.
======================================================================
Evaluation
This is a regression from JDK 1.2.2. Verified that the Enter key is not passed to the default button for editable and non-editable combo boxes in 1.3. This bug was introduced before 1.3.beta.

In the current development build of 1.4, the problem in the uneditable combo box goes away. 

Here is a simplfied test case:

/**
 * Simplified bug test that shows the bug on JDK 1.3 FCS but not on JDK 1.2.2
 * 
 * Pressing enter on the non-editable combo box will pass the enter to the OK button
 * if the combo box is editable, the Enter key press seems to be consumed.
 */
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;

public class EditorCombo {

    private JFrame frame = new JFrame();
    private JComboBox combo2 = new JComboBox(new Object[] {"Item 1", "Item 2", "Item 3"});
    private JButton okButton = new JButton("OK");
    private JPanel textPanel = new JPanel();

    public EditorCombo()  {
	frame.setSize(new Dimension(400, 300));
	frame.setTitle("Frame Title");
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	combo2.setEditable(false);

	JCheckBox check = new JCheckBox("Enable Editing", false);
	check.addItemListener(new ItemListener()  {
		public void itemStateChanged(ItemEvent evt)  {
		    if (evt.getStateChange() == ItemEvent.SELECTED)  {
			combo2.setEditable(true);
		    } else {
			combo2.setEditable(false);
		    }
		}
	    });

	textPanel.add(combo2);
	textPanel.add(check);

	frame.getContentPane().add(textPanel, BorderLayout.CENTER);
	frame.getContentPane().add(okButton, BorderLayout.SOUTH);

	frame.getRootPane().setDefaultButton(okButton);

	// This is just to check when the OK Button was pressed.
	okButton.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent ae) {
		    System.err.println("OK Button pressed");
		}
	    });
	frame.show();
    }

    //Main method
    public static void main(String[] args)  {
	EditorCombo app = new EditorCombo();
    }
}

Not sure where the regression is. I commented out blocks of code in BasicComboBoxUI in the PropertyChangeHandler for the "editable" property and in the configureEditor()/unconfigureEditor() methods. The BasicComboBoxUIEditor is virtually unchanged between versions. 

There could be a subtle effect in the JTextField which have prevented the pass through. 

Still investigating.

 xxxxx@xxxxx  2000-05-15


The ComboBox.ancestorInputMap in both Windows and Metal LAFs bind the Enter key to the togglePopup action. In 1.2.2, there was some fancy logic which did not process the ENTER key event. When I commented out the entry in MetalLookAndFeel, the enter was passed through to the Default Button.

In the currect 1.4 development build the Editable and Non-editable combo boxes behave the same.

 xxxxx@xxxxx  2001-04-02





Should pressing Enter activate default button from an editable combo box?
I believe not, since otherwise there's no way to set new value in the combo
box without activating the default button.

For non-editable combos, there're two ways to fix this. First, we can remove
the keybinding that binds Enter key to togglePopup action. Alternatively we
can modify this action to search and activate root pane's default button

 xxxxx@xxxxx  2001-07-04

======================================================================

I added the ENTER key binding to MetalLookAndFeel v 1.122.2.2 back in Sept, 2000 and I believe that this was for a simplification of the logic that was contained in BasicComboPopup. I'm going to investigate pulling this out but I have to test the case in which the enter will accept combo box selections when in the context of a TableCellEditor.

 xxxxx@xxxxx  2001-07-23

Here are the new semantics (for both Metal and Windows): When the popup is visible in a non-editable combo box, the enter key will hide it. If the popup is hidden, then the enter action will pass VK_ENTER binding on the JRootPane. 

If the combo box is editable then pressing the enter key in the editable portion of the combo box will behave as before. This is the same semantics of JDK 1.2.2.
 xxxxx@xxxxx  2001-07-23
Comments
  
  Include a link with my name & email   

Submitted On 02-AUG-2000
JoeDorman
I found an old workaround for when this was a bug in 1998 
that still seems to work pretty well.  Look at the 
workaround in closed bug 4164084.  The only thing I changed 
was how they handled keeping the default button on the OK 
button when tabbing through other buttons.  Their approach 
was to keep it on the OK button even when the other buttons 
are tabbed into.  If you simply change the focusGained to 
focusLost, it will work like normal Windows dialogs where 
the default only goes back to the OK button when you tab 
out of the last button.  You do have to add the focus 
listener for all buttons on your dialog other than the one 
you want to be the default.


Submitted On 21-SEP-2000
roosen
This probably is indeed due to the change in behavior of 
JTextField.  Starting with JDK1.3, the JTextField will pass 
the ENTER event to the default button if the JTextField has 
no action listeners.  If it has an action listener, the 
event isn't passed to the default button.

I expect that the JComboBox was relying on the JTextField 
to activate the default button, as it did in previous 
versions.  Starting with 1.3, the JTextField will only do 
so when the JComboBox isn't listening to it.    

In the JComboBox code, we can see that the editable 
JComboBox is listening to the field and the noneditable on 
is not.  That's probably why the problem is present in the 
editable but not in the uneditable case.

  public void setEditor(ComboBoxEditor anEditor) {
        ComboBoxEditor oldEditor = editor;
 
        if ( editor != null )
            editor.removeActionListener(this);
        editor = anEditor;
        if ( editor != null ) {
            editor.addActionListener(this);
        }
        firePropertyChange( "editor", oldEditor, editor );
    }




Submitted On 20-JUN-2001
gheiland
I tried the work around for my noneditable comboboxes, the 
solution only works because of the unregistering of the 
enter key. The actionlistener never gets called because for 
an noneditable combobox, the renderer uses a JLabel which 
does not honour any action listeners.

In my case, I am extending the JComboBox and within that 
class, I found a better solution is to override the 
KeySelectionManager, I can get my idea of the perfect 
behaviour:

In the extended class' default constructor, I specify the 
following:

// Override the JComboBox protected variable with our own
// KeySelectionManager.
keySelectionManager = new MyKeySelectionManager(this);

If you don't extend the JComboBox, you can install this 
selection manager as in the following call:

comboBox.setKeySelectionManager(new MyKeySelectionManager
(comboBox));


As an inner class (or a public class):

class MyKeySelectionManager
    implements KeySelectionManager
{
    JComboBox _box = null;
    MyKeySelectionManager(JComboBox aBox)
    {
        _box=aBox;
    }

    /**
     *  Process key pressed to see if it can drive the list
     *  navigation.
     *  Code is identical to JComboBox 
DefaultKeySelectionManager
     *  method.
     */
    public int selectionForKey(char aKey, ComboBoxModel 
aModel)
    {
        int i, c;
        int currentSelection = -1;
        Object selectedItem = aModel.getSelectedItem();
        String v;
        String pattern;

        if (selectedItem != null)
        {
            selectedItem = selectedItem.toString();

            for (i = 0, c = aModel.getSize(); i < c; i++)
            {
                if (selectedItem.equals(aModel.getElementAt
(i).toString()))
                {
                    currentSelection  =  i;
                    break;
                }
            }
        }

        pattern = ("" + aKey).toLowerCase();
        aKey = pattern.charAt(0);

        for (i = ++currentSelection, c = aModel.getSize() ; 
i < c ; i++)
        {
            v = aModel.getElementAt(i).toString
().toLowerCase();
            if (v.length() > 0 && v.charAt(0) == aKey)
            {
                return i;
            }
        }

        for (i = 0 ; i < currentSelection; ++i)
        {
            v = aModel.getElementAt(i).toString
().toLowerCase();
            if (v.length() > 0 && v.charAt(0) == aKey)
            {
                return i;
            }
        }

        // If it is an enter and popup is not visible,
	// fire the default button if we have one.

        char enterKey = '\n';
        if (aKey == enterKey && !_box.isPopupVisible())
        {
            JRootPane rootPane = (JRootPane)getRootPane();
	    if (rootPane == null)
	    {
	        return -1;
            }

            
            JButton defaultButton = 
rootPane.getDefaultButton();
	    if (defaultButton == null)
	    {
	        return -1;
            }

	    // Press the default button.
            defaultButton.doClick();
        }
        return -1;
    }
}


Submitted On 28-JUN-2004
austin.moore
Below an update to the workaround I just submitted.  The problem with the previous workaround was that the JComboBox's model did not have the updated String from the editor when the default button action is performed.  This version fixes that.

public class ActivateDefaultButtonListener
    extends KeyAdapter
    implements ActionListener
{
    private JComboBox box;
    
    /** Creates new ActivateDefaultButtonListener */
    public ActivateDefaultButtonListener(JComboBox box)
    {
        this.box = box;
    }
    
    public void keyPressed(KeyEvent e)
    {
        if(e.getKeyCode() == KeyEvent.VK_ENTER) {
            // Simulte click on default button.
            doClick(e);
        }
    }
    
    public void actionPerformed(ActionEvent e)
    {
        doClick(e);
    }
    
    private void doClick(java.util.EventObject e)
    {
        Component c = (Component)e.getSource();
        
        JRootPane rootPane = SwingUtilities.getRootPane(c);
        
        if(rootPane != null) {
            JButton defaultButton = rootPane.getDefaultButton();
            
            if(defaultButton != null && !box.isPopupVisible()) {
                final Object selection = box.getEditor().getItem();
                box.setSelectedItem(selection);
                defaultButton.doClick();
            }
        }
    }
}


Submitted On 28-JUN-2004
austin.moore
I'm using JDK1.4.2 and I still have this problem.  I tried all of the above workarounds in addition to the workarounds from closed bug 4164084, but none of them seemed to work.  I finally found a workaround that works for the case of an editable JComboBox.  When the pop-menu is open, then it lets the combo consume the enter key, thereby closing the pop-up.  When the pop-up is not open, then the default button for the window is activated.  This eliminates the bug that you have to press return twice after editing the combo box to get the default button to be activated.  Below is the workaround code.

JComboBox box = new JComboBox();
box.setEditable(true);
box.getEditor().getEditorComponent().addKeyListener(new ActivateDefaultButtonListener(box));
----
public class ActivateDefaultButtonListener
    extends KeyAdapter
    implements ActionListener
{
    private JComboBox box;
    
    /** Creates new ActivateDefaultButtonListener */
    public ActivateDefaultButtonListener(JComboBox box)
    {
        this.box = box;
    }
    
    public void keyPressed(KeyEvent e)
    {
        if(e.getKeyCode() == KeyEvent.VK_ENTER) {
            // Simulte click on default button.
            doClick(e);
        }
    }
    
    public void actionPerformed(ActionEvent e)
    {
        doClick(e);
    }
    
    private void doClick(java.util.EventObject e)
    {
        Component c = (Component)e.getSource();
        
        JRootPane rootPane = SwingUtilities.getRootPane(c);
        
        if(rootPane != null) {
            JButton defaultButton = rootPane.getDefaultButton();
            
            if(defaultButton != null && !box.isPopupVisible()) {
                defaultButton.doClick();
            }
        }
    }
}


Submitted On 26-AUG-2005
how to hide Jcombobox items



PLEASE NOTE: JDK6 is formerly known as Project Mustang