JDK-4626920 : Editable JComboBox width not correct
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-01-23
  • Updated: 2003-04-12
  • Resolved: 2002-08-12
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.
Other
1.4.2 mantisFixed
Description
 Build 020122_1, Win 2000, JDK 1.3.1
javax.jms.Queue displayed without letter 'j' in the Type drop list of the 'Add Resource Environment Reference' dialog.

****

Real problem here is that an editable JComboBox is not
sized correctly. The longest string is not entirely
displayed.

Here is a test app that exhibits the problem:

/* ComboTest.java */

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

public class ComboTest extends JPanel {

    static public final String[] RES_TYPES = {
                "a really really long entry",
                "javax.jms.Queue",      // NOI18N
                "javax.jms.Topic"       // NOI18N
    };


    public ComboTest () {

        setLayout (new BoxLayout (this, BoxLayout.Y_AXIS));

        JPanel cbpanel = new JPanel ();
        cbpanel.setLayout (new FlowLayout (FlowLayout.CENTER));

        /* The editable JComboBox width will not be OK (not wide enough) */
        JComboBox cb = new JComboBox (RES_TYPES);
        cb.setEditable (true);
        cbpanel.add (cb);

        add (cbpanel);

        /* The non-editable JComboBox width will be OK */
        cb = new JComboBox (RES_TYPES);
        cbpanel = new JPanel ();
        cbpanel.add (cb);

        add (cbpanel);

    }

    public static void main (String [] args) {
        JFrame jf = new JFrame ("Editable JComboBox Test");
        jf.addWindowListener (new WindowAdapter () {
            public void windowClosing (WindowEvent evt) {
                System.exit (0);
            }
        });
        ComboTest combotest = new ComboTest ();
        jf.getContentPane ().add (combotest);
        jf.pack ();
        jf.setLocation (300, 300);
        jf.setSize (200, 200);
        jf.setVisible (true);
    }

}


Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis mantis-b02 FIXED IN: mantis mantis-b02 INTEGRATED IN: mantis mantis-b02
14-06-2004

PUBLIC COMMENTS .
10-06-2004

EVALUATION This seems to be a swing bug. I wrote a small test case with a JComboBox with the same 2 entries and it exhibited the same problem. It appears that the combo box is not sized properly (width-wise) when it is editable. If it is not editable, then the longest string appears just fine. I've included a sample app that exhibits the problem in the "Description". ###@###.### 2002-04-10 The front of the string in an editable combo box appears to be cropped. One workaround is to use the prototype display value for the combo box and set it for a larger value. See the workaround section for details. Unfortunately, that exposes a small bug in BasicComboBoxUI.getDisplaySize() such that the preferred size of the editable combo box doesn't take into account of the size of the editor. The block starting with comboBox.isEditable() should be moved out of the else clause in which the prototype value does not exist. I'm not sure why the size of the element is shy by a few pixels. One solution is to introduce a magic number that will pad the width of the getMinimumSize(). However, this isn't the real solution. The getDisplaySize() iterates over the combo box values and uses the DefaultListCellRenderer with the current JComboBox font. Ultimately, the calculation is performed by BasicLabelUI.getPreferredSize(JComponent). The real bug may lie somewhere down that codepath. ###@###.### 2002-05-06 I think the calculation using the BasicComboBoxRenderer.getPreferedSize may be coming up a little short. This calculation is performed as part of the BasicComboBoxUI.getDisplaySize() calculation. This ultimately calls the BasicLabelUI.getPreferredSize() - which calculates the Insets of the JLabel renderer based on the BasicComboBoxRenderer border. Doing a little hacking, tif the border of BasicComboBoxRenderer has the dimensions: 1,2,1,2, then the edit field seems to look ok. It seems that this problem has been with swing since the beginning. The empty noFocusBorder has been the same dimensions since the beginning. The size calculation for the combo box seems far too complex. Perhaps it should be simplified by taking the properties of the ComboBox renderer from the combo box properties rather than the list. The addition of the renderer to the CellRendererPane is also questionable. ###@###.### 2002-06-26 This bug only exists for the MetalLookAndFeel (or Basic) and not the WindowsLookAndFeel. Another problem is that the size of the editor in calculating the display size is not taken into account if a prototype value is used. This was documented in my original evaluation. BasicComboBoxUI: This algorithm of adding the renderer component to the currentValuePane, getting the dimensions and then removing it is in the code in 3 places: currentValuePane.add(comp); comp.setFont(comboBox.getFont()); Dimension d = comp.getPreferredSize(); currentValuePane.remove(comp); Not sure what is trying to be achieved here but should try to get rid of this and simplify for the next major release. My first suspiction was that the JTextField sizing is incorrect since the problem also exists for JTextField. However, the bounds and the calculation of the editable portion of the combo box doesn't use JTextField at all - instead it uses the sizing for BasicLabelUI from the BasicComboBoxRenderer. The text field sizing bug may be a separate problem. The solution will be to adjust the border dimensions in the BasicComboBoxRenderer. ###@###.### 2002-06-28 Code review from Scott: I think this bug is caused by an interaction between MetalComboBoxUI and BasicComboBoxUI, where MetalComboBoxUI specializes calculating the preferred size but doesn't specialize layout. MetalComboBoxUI.getMinimumSize has the following: else if ( comboBox.isEditable() && arrowButton != null && editor != null ) { size = super.getMinimumSize( c ); Insets margin = arrowButton.getMargin(); size.height += margin.top + margin.bottom; } Which appears to amount to adding 1 to the height. MetalComboBoxUI ends up calling into BasicComboBoxUI.ComboBoxLayoutManager to do layout, ComboBoxLayoutManager makes the button square, basing the size off the height. Because the height has been adjusted by 1, the button ends up being 1 pixel wider, and hence your off by 1 error in the width. YECK! If you agree that this is in fact the source of your woes, a simple solution would be to change MetalComboBoxUI.getMinimumSize to look like: else if ( comboBox.isEditable() && arrowButton != null && editor != null ) { size = super.getMinimumSize( c ); Insets margin = arrowButton.getMargin(); size.height += margin.top + margin.bottom; size.width += margin.left + margin.right; } ###@###.### 2002-07-17
17-07-2002

WORK AROUND A workaround is to use the new setPrototypeDisplayValue() method on JComboBox. This has a performance benefit as well since it doesn't have to iterate over the combo box items to find the longest item. In the example, you would use: cb.setPrototypeDislayValue(RES_TYPES[0] + " "); ###@###.### 2002-05-06
06-05-2002

SUGGESTED FIX Partial fix for the bug uncovered by setting a prototype display value on an editable combo box: ------- BasicComboBoxUI.java ------- 1274c1274 < Dimension d; --- > Dimension d; 1296,1301d1295 < if ( comboBox.isEditable() ) { < d = editor.getPreferredSize(); < result.width = Math.max(result.width,d.width); < result.height = Math.max(result.height,d.height); < } < 1302a1297,1302 > if ( comboBox.isEditable() ) { > Dimension d = editor.getPreferredSize(); > result.width = Math.max(result.width,d.width); > result.height = Math.max(result.height,d.height); > } > ###@###.### 2002-05-06
06-05-2002