|
Quick Lists
|
|
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
|
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
|
|
|
 |