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: 4199622
Votes 30
Synopsis RFE: JComboBox shouldn't sending ActionEvents for keyboard navigation
Category java:classes_swing
Reported Against 1.2beta4
Release Fixed
State 5-Cause Known, request for enhancement
Priority: 4-Low
Related Bugs 4452879
Submit Date 23-DEC-1998
Description


When the user pops up a JComboBox (hits the
spacebar for Metal L&F), and then tries to
navigate with the arrow keys, any ActionListeners
for that CB will have their actionPerformed
methods called, and there isn't any information in
the given ActionEvent to show that this was only a
navigation action rather than a selection
(spacebar) action.

Source:

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

public class inc37498 extends JFrame
{
 public inc37498()
 {
 	 try {UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); }
 	 catch (Exception e) {System.out.println("L&F error"); }
 
 	 String[] items = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"};
 
 	 JComboBox cb = new JComboBox(items);
 	 getContentPane().add(cb);
 
	 cb.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
	      if (e.getID() == ActionEvent.ACTION_PERFORMED) {
	        System.out.println("CB action performed:" + e);
	      } else {
	        System.out.println("CB action:" + e);
	      }
	    }
	  });
	  
	  pack();
 }
 
 public static void main(String[] args)
 {
 	new inc37498().show();
 }
}
(Review ID: 37498)
======================================================================
  xxxxx@xxxxx   10/12/04 18:24 GMT
Work Around


I could trap KeyEvents and set a flag each time
an arrow key was pressed, unsetting the flag after
it was released, and not perform my "selection
action" if the flag is currently set.
======================================================================

Serious Hack Alert:

What is desired is for the JComboBox to behave like its a table cell editor. Starting with 1.4, the indication that the combo is in a JTable context is provided by the boolean client property "JComboBox.isTableCellEditor". See DefaultCellEditor(JComboBox).

You can spoof the JComboBox to make it behave like it's in a JTable by setting the client property for each JComboBox:

comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);

You would have to add an actionListener to the combo box to manually hide the combo popup:

comboBox.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
     JComboBox combo = (JComboBox)evt.getSource();
     combo.hidePopup();
  }
});


  xxxxx@xxxxx   2002-05-31
Evaluation
Currently, keyboard navigation causes the combo box selection to change while keyboard navigating.  We have a way of doing lightweight navigation (not public yet) but we can't add it to the API until we get the ok to add public API.  I'm changing this to be an RFE.
  xxxxx@xxxxx   1999-01-25

The semantics for ComboBox is such that the navigational changes correspond to the selection changes (setSelectedItem) and an actionEvent is fired with the value of getActionCommand(). At this stage we will not be changing the semantics of the combo box events. 

  xxxxx@xxxxx   2002-05-30

After a dialog with Ethan, I think I understand the issue. Specifically, the semantics of Keyboard navigation should be like Mouse navigation. This is further supported by the fact that the combo box as a Table cell editor will perform the desired semantics of not changing selection when using keyboard navigation. There is switching logic in BasicComboBoxUI which takes care of this situation so the solution would be to consolidate this behavour. Perhap the table cell editor semantics can be applied to the Metal LAF and the Windows LAF can retain the old selected item behaviour.

The solution is pretty simple but the repurcusions could be enourmous. We may be able to change these semantics for Metal but not for the Windows LAF. In order for these changes to occur we should discuss this issue with a lot of people: HIE, Swing tech lead, Java client architect and some of our partners. 

  xxxxx@xxxxx   2002-05-31
Just to record my thoughts:

1) We definitely need to change things such that navigating within the popup doesn't send action events until the popup is unposted. This includes both when used with Metal L&F and when the popup is shown with ALT+Down in Windows.

2) Additionally, I'd like to see a property added to JComboBox to control whether or not it behaves like a Windows or Metal combobox in response to the down arrow. Metal posts the popup whereas most Windows comboboxes don't. However, some Windows comboboxes do post popups on the down key. As such, the need for a property.
Posted Date : 2006-04-26 04:10:36.0
Comments
  
  Include a link with my name & email   

Submitted On 15-JUN-1999
ivanhu
What just makes it even worse, JComboBox doesn't fire ActionEvent on each
press of the ENTER key, but only if the state changes (see RFE 4147476).
As a matter of fact, in a non-editable JComboBox, the ENTER key doesn't send
ActionEvent at all. The API document states that the ActionEvent is fired when
the user makes his selection final.


Submitted On 24-JUL-1999
uob
The current practise of firing selection events on keyboard navigation
in the dropdown list is just plain WRONG!!! I want to know the item I select;
not each one I navigated over. It is also completely inconsistent with
mouse navigation (which does it correctly). This should not be a RFE; 
it should is a huge defect in the way JCombobx works. 


Submitted On 26-OCT-1999
jonabbey
This is a horrible problem with JComboBox, one that makes the entire thing
almost
unusable for lists of any size.  I want to use a custom KeySelectionManager to
allow my user to type a sequence of keystrokes to select an item based on more
than the first letter, with a timer running to determine whether the keystroke
should
reset the match criteria or append to it, but at each keystroke the JComboBox
fires
off an item selected action, which on my app involves a round-trip to the
server.
Ugh, ugh, ugh, ugh.
It should put up the pop-up, move the highlight as they type according to my
key selection manager, and then when they hit tab or enter fire an action
selecting the item they have highlighted.


Submitted On 09-DEC-1999
qec
If you carefully examine the code for BasicComboBoxUI in
the Swing 1.1.1 release, you will find an unadvertised
workaround for the lightweight keyboard navigation mentioned
above.  You need to call
putClientProperty("JComboBox.lightweightKeyboardNavigation",
"Lightweight");
on your JComboBox.  I put the call in the constructor of my
subclass of JComboBox.  I haven't tested it thoroughly yet, 
but does get rid of all those excess ActionEvents.



Submitted On 22-JUN-2000
MonadizadehB
I do have the exact same problem with the JComboBox. 
Whenever user wants to select an new item in JComboBox I 
have to go to db to read to appropriate data for the new 
selection. Unfortunately, there is no way of knowing when 
the user has made the final selection. I have used the hack 
described above but it has one drawback that after user 
navaigates through the last selection with up or down arrow 
keys, if he/she clicks outside the combobox or hits the tab 
key then the last selection is not updated.
 


Submitted On 01-SEP-2000
busche
Oh my gosh!  This caused me so much pain.  I wish I had seen the
secret putClientProperty() work-around identified by gec before
I had spent so many hours fighting this.  I tried checking
isPopupVisible(), but apparently the pop-up doesn't go away until
the selection event has been processed.   My eventual work-around
was to track pressed/released events on the up/down arrow keys and
then use that information to determine whether the JComboBox
actionEvent was a result of an uninteresting arrow key press.  This
worked but I consider myself lucky that no one cut my fingers off
for writing such an abomination.  I'm now in the process of eradicating
my arrow key state tracker.


Submitted On 08-DEC-2000
ari1meyer
One problem with the putClientProperty("JComboBox.lightweightKeyboardNavigation", "Lightweight"); 
workaround offered by gec -- no ItemEvents or ActionEvents are delivered on ENTER/SPACEBAR if your 
JComboBox is editable (using JDK 1.2.2_005, Windows NT 4.0).  This is a real pain!  Does anyone know of 
alternatives besides writing another "abomination" like busche described?

Thanks,
Ari


Submitted On 15-DEC-2000
arcoli
I forgot, regarding the message I left on :Fri Dec 15 
12:42:48 PST 2000
the method "cmbWBOrig_valueChanged()" is where you actualy 
process the change of value as a final selection.


Submitted On 15-DEC-2000
arcoli
Here is something that fixes this behavior using threads:
Note that a flag (updateInAction)is set so not to activate 
to many threads for nothing:


public void itemStateChanged(java.awt.event.ItemEvent e){
  if (!updateInAction)
  {
     updateInAction = true;
     Thread thread = new Thread()
     {                    // Treated in a thread to block 
out 
                          // the selection trigered by 
scrolling in the
	public void run() // the list with the keyboard.
	{
	  if (!getCmbWBOrig().isPopupVisible())
	    cmbWBOrig_valueChanged();
	}
     };
     javax.swing.SwingUtilities.invokeLater(thread);
     Thread thread2 = new Thread()
     {
	public void run()
	{
	  updateInAction = false;
	}
     };
     javax.swing.SwingUtilities.invokeLater(thread2);
  }
}


Submitted On 28-FEB-2001
tfox
This is just plain nastiness.  So keyboard users are left 
to waste away in many cases.  Even if Sun does not correct 
this problem right away, they should at least provide a 
decent workaround.  TRASH, I tell you, TRASH!


Submitted On 07-JUN-2001
ksrivani
I was implementing the searchable combobox where I use 
KeySelectionManager,so the user can type in more than one 
character  to select an item.At every keystroke the 
JComboBox fires the event which will make my application to 
contact the server.

 It should highlight as the user types in and when the user 
hits the enterkey the event should be fired.This is really 
a big problem with the JComboBox.Can you let me know when 
this will be fixed.


Submitted On 25-FEB-2002
homerjk
Just a note:  the workaround
putClientProperty("JComboBox.lightweightKeyboardNavigation","Lightweight");
has been removed from J2sdk1.4.0.  I believe they have
implemented a new keyboard binding infrastructure (which was
introduced in J2sdk1.3, I believe) which is detailed here:
http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html.

Now I just need to learn to use the new API and, hopefully,
there will be a more standard workaround to this issue.

Hope that helps someone.

Jake


Submitted On 31-MAY-2002
gdesmet
Just another workaround: replace the actionListener by an 
itemListener and a keyListener.
I used the description example and rewrote it a little bit:


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

public class inc37498 extends JFrame
{
  private JComboBox cb = null;
  private boolean cbSelectionOK = true;
  private int cbSelectedIndex = -1;

 public inc37498()
 {
 	 try {UIManager.setLookAndFeel
("javax.swing.plaf.metal.MetalLookAndFeel"); }
 	 catch (Exception e) {System.out.println("L&F 
error"); }

 	 String[] items = {"Item 1", "Item 2", "Item 
3", "Item 4", "Item 5"};

 	 cb = new JComboBox(items);
 	 getContentPane().add(cb);

   cb.addItemListener(new ItemListener() {
      public void itemStateChanged( ItemEvent event ) {
        if( event.getStateChange() == ItemEvent.SELECTED ) {
          if(cbSelectionOK) {
            cbSelectedIndex = cb.getSelectedIndex();
            // LET'S DO IT HERE TOO !!!
            doIt();
          }
          cbSelectionOK = true;
		    }
	    }
    });

   cb.addKeyListener(new KeyAdapter() {
      public void keyPressed( KeyEvent event ) {
        super.keyPressed(event);
        if(event.getKeyCode() != KeyEvent.VK_ENTER &&
           event.getKeyCode() != KeyEvent.VK_SPACE)
          cbSelectionOK = false;
        else if( cb.isPopupVisible() )
          doIt(); // LET'S DO IT !!!

        if( event.getKeyCode() == KeyEvent.VK_ESCAPE &&
            cb.isPopupVisible() ) {
          if( cbSelectedIndex != -1 )
            cb.setSelectedIndex(cbSelectedIndex);
          cbSelectionOK = true ;
        }
	    }
    });


	  pack();
 }

  private void doIt () {
    System.out.println("Let's do the job! " + 
cb.getSelectedItem());
  }


 public static void main(String[] args)
 {
 	new inc37498().show();
 }
}

Greetings,
Geert


Submitted On 10-JUN-2002
barbey
A solution with less repercussions would be to keep the 
actual semantics, but to add a flag to the generated 
ActionEvent (e.g. in a subclass ComboActionEvent) that 
would tell whether this is a navigational action event or 
an eventual event...


Submitted On 11-JUL-2002
jtr
Note that this causes the JFileChooser to behave badly.  The 
JFileChooser under the Windows L&F (as well as Metal) changes 
directories as the user moves the selection in the JComboBox.
This is not the behavior under Windows (at least not NT 4.0).


The workaround posted 2002-05-31 would probably work to fix it.



Submitted On 28-OCT-2002
bridgehajen
As homerjk notes, 
the "JComboBox.lightweightKeyboardNavigation" property 
seems to be desupported starting at 1.4; instead 
a "JComboBox.isTableCellEditor" property has been added. To 
my experience they seem to do the same thing, i.e.

comboBox.putClientProperty
("JComboBox.lightweightKeyboardNavigation", "Lightweight"); /
/ 1.3
comboBox.putClientProperty("JComboBox.isTableCellEditor", 
Boolean.TRUE); // 1.4

Would both cause the ComboBox to fire "few" action events, 
where as

comboBox.putClientProperty
("JComboBox.lightweightKeyboardNavigation", "Heavyweight"); 
// 1.3
comboBox.putClientProperty("JComboBox.isTableCellEditor", 
Boolean.FALSE); // 1.4

would both cause the combo box to fire "many" action events 
(actually, this was the behaviour that I desired when using 
editable combo boxes in a JTable).

Also I believe that there is no harm done in setting both the 
1.3-style property and the 1.4-style property if messing 
around with this. It seems to work OK for me (tested on 
1.3.1_03 and 1.4.0)


Submitted On 16-OCT-2006
kshanti
Also using either ItemListener or ActionListeners an event gets fired whenever an item is added to the list. If this is going to happen there should be a distinction between user-caused selection and internal selection.


Submitted On 14-MAY-2008
19810205
A possible fix for the selection problem which enables cell editor behavior when the popup is shown and disables it when the popup is hidden. The popup is hidden when a selection is made. The class needs to be added as PopupMenuListener and ActionListener.

    /**
     * A fix for bug 4199622 (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4199622).
     */
    private class Bug4199622Fix implements PopupMenuListener, ActionListener {

        /**
         * {@inheritDoc}
         * 
         * @see PopupMenuListener#popupMenuCanceled(PopupMenuEvent)
         */
        public void popupMenuCanceled(PopupMenuEvent e) {
            JComboBox combo = (JComboBox) e.getSource();
            combo.putClientProperty("JComboBox.isTableCellEditor", Boolean.FALSE);
        }
        
        /**
         * {@inheritDoc}
         * 
         * @see PopupMenuListener#popupMenuWillBecomeVisible(PopupMenuEvent)
         */
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            JComboBox combo = (JComboBox) e.getSource();
            combo.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
        }

        /**
         * {@inheritDoc}
         * 
         * @see PopupMenuListener#popupMenuWillBecomeInvisible(PopupMenuEvent)
         */
        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
            JComboBox combo = (JComboBox) e.getSource();
            combo.putClientProperty("JComboBox.isTableCellEditor", Boolean.FALSE);
        }

        /**
         * {@inheritDoc}
         * 
         * @see ActionListener#actionPerformed(ActionEvent)
         */
        public void actionPerformed(ActionEvent e) {
            JComboBox combo = (JComboBox) e.getSource();
            combo.hidePopup();
        }

    }



PLEASE NOTE: JDK6 is formerly known as Project Mustang