-
Enhancement
-
Resolution: Unresolved
-
P5
-
None
-
1.4.0
-
x86
-
windows_2000
Name: ddT132432 Date: 12/03/2001
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode)
I believe an editable JComboBox should behave differently.
Currently, the JComboBox will register itself as an action listener with
its editor. When the JComboBox receives an action event from the editor,
triggered by the RETURN key being pressed, it takes the edited item from
the editor and sets it as the selected item in its model ( Code Listing 1).
The popup is also closed and a "comboBoxEdited" action is fired.
------------------------------------------------------------------------
Code Listing 1: The actionPerformed() method of the JComboBox. This
method is called by the editor.
/**
* This method is public as an implementation side effect.
* do not call or override.
*/
public void actionPerformed(ActionEvent e) {
Object newItem = getEditor().getItem();
setPopupVisible(false);
getModel().setSelectedItem(newItem);
String oldCommand = getActionCommand();
setActionCommand("comboBoxEdited");
fireActionEvent();
setActionCommand(oldCommand);
}
------------------------------------------------------------------------
This logic seems correct when your purpose is for users to have the option
of selecting from the items in your JComboBox as well as a user defined
value.
HOWEVER, I expect an editable JComboBox to behave differently.
Often times an editable JComboBox is used to search a database. After a
value is entered, that value will be compared against the database and the
JComboBox will then be populated with the results. If the result has only
one item, that item will automatically be selected. If the result contains
more than one item, the popup will be displayed and the user may scroll and
select the appropriate item. An alternative to this is to automatically
select the first item of the results and allow for the user to initiate
the popup and select an alternate item.
I have been struggling through many versions of the JDK to provide this sort
of functionality on a JComboBox but have encountered many road blocks. This
posting is concerned with the JAVA 2 SDK 1.4 Beta 3, although previous
versions apply.
There has been progress towards defining the functionality of an editable
JComboBox within this version. Most important are the "comboBoxEdited" action
command that is fired and the PopupMenuListener support. The PopupMenuListener
does not seem to help in my situation. The comboBoxEdited command is a great
leap forward, but still may have issues.
By using the "comboBoxEdited" action, one may now define an action to occur
specifically when an edit has occured. (In previous versions of the SDK
developers were unable to distinguish between an action fired by the editor and
an action fired when a new item was selected.) The spirit of this would suggest
that one could now simply provide an action listener to support the
functionality I seek ( See Code Listing 2 ).
------------------------------------------------------------------------------
/*
Code Listing 2 :
This implementation of an editable JComboBox uses an action listener to
re-populate the JComboBox with items based on the value entered in the editor.
It is meant to simulate a JComboBox that allows users to enter a value and
then select from matching results on a database.
*/
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class JComboBoxTest extends JComboBox {
public static void main ( String[] args ) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create editable JComboBox
JComboBox combo = new JComboBoxTest();
combo.setEditable(true);
//Add ActionListener for comboBoxEdited actions
combo.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox c = (JComboBox)e.getSource();
//Exchange the if command with the following to account for popup visibility
//if ( "comboBoxEdited".equals(e.getActionCommand()) && !c.isPopupVisible() ) {
if ( "comboBoxEdited".equals(e.getActionCommand()) ) {
/*
Search code goes here. This could be a query to
a database or some other search operation.
Our implementation will set a new model with
values based on the search string.
*/
Vector v = new Vector();
//get String to search from editor
String searchString = (String)c.getEditor().getItem();
for(int i = 0 ; i < 10 ; i++) {
v.add(searchString + " " + i);
}
c.setModel(new DefaultComboBoxModel(v));
}
}
}
);
//Add combo to content pane
Container c = f.getContentPane();
c.setLayout(new BorderLayout());
c.add( combo , BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
/*
The following actionPerformed code hides the popup
after firing the action command.
Uncomment the following to allow this code to work
properly.
*/
/*
public void actionPerformed(ActionEvent e) {
Object newItem = getEditor().getItem();
getModel().setSelectedItem(newItem);
String oldCommand = getActionCommand();
setActionCommand("comboBoxEdited");
fireActionEvent();
setActionCommand(oldCommand);
setPopupVisible(false);
}
*/
}
---------------------------------------------------------------------
The problem with this code is that the comboBoxEdited action is fired after an
edit but also after an item is selected when scrolling through the values in
the popup. When you first enter a value and hit return, the combobox is
populated with new items, the first item is selected, and everything is groovy.
If you then scroll down and select another item by hitting RETURN, a search is
triggered once again.
To counter this, one may use the commented "if" statement which takes into
account popup visibility. However, due to placement of the setPopupVisible
method in the actionPerformed method of the JComboBox, this still will not
work. Uncomment the "actionPerformed" method in Listing 2 to fix this bug.
The only difference between this code and the official code is the placement
of the setPopupVisible statement.
Therefore, I am recommending that the setPopupVisible call be relocated to
after the comboBoxEdited action is fired in the actionPerformed method of
the JComboBox. By doing this, it may be easier to support the current
functionality of an editable JComboBox as well as the functionality which
I have suggested.
I may even suggest that the the actionPerformed method be removed altogether.
Why must the JComboBox dictate what the editor does and how it effects the
popup and the model? It would be much simpler for developers to define this
themselves. If I want to do something when an edit occurs, I would add an
action listener for "comboBoxEdited". When considering the MVC Architecture,
should not this code exist in the ComboBoxUI in the first place? Isn't this
why the actionPerfomed method warns "This method is public as an implementation
side effect - do not call or override"?
Some related Bugs:
http://developer.java.sun.com/developer/bugParade/bugs/4515752.html
http://developer.java.sun.com/developer/bugParade/bugs/4337071.html
Some related Links:
http://java.sun.com/docs/books/tutorial/uiswing/components/combobox.html
http://java.sun.com/j2se/1.4/docs/api/javax/swing/JComboBox.html
(Review ID: 135793)
======================================================================