-
Bug
-
Resolution: Fixed
-
P4
-
1.3.0
-
beta
-
x86
-
windows_nt
Name: sl110371 Date: 07/31/2000
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Server VM (build 2.0fcs-E, mixed mode)
JComboBox doesn't resize in response to ListCellRenderer change. The the
underlying model changes, then the ComboBox will recompute its size, but if the
renderer changes, it will not.
In the sample program below, a ComboBox is used in a layout to get its preferred
width. A renderer is used to display the models contents in upper case, or
lower case. When the renderer is changed, at the next repaint, the ComboBox
displays the correct format. However, it maintains its old size. If you
'nudge' the ComboBox (by modifying the underlying model), then the ComboBox will
resize itself in response to the new renderer.
In the program, the JLabel at the top of the window displays the ComboBox's
preferred size. The first button on the left toggle's the ComboBox's renderer
between upper and lower. The next button on the left will 'nudge' the CombBox,
and force it to recompute its size.
The program takes one boolean parameter (which defaults to false). This
specifies whether or not only one renderer should be used. When only one
renderer is used, toggling the upper/lower effects the renderer, but the
ComboBox doesn't get a 'setRenderer' invocation.
I'm not suprised that the ComboBox does not resize when only one renderer is
used, but I think it should when I explicitly change the renderer. It would be
nice if the ComboBox would resize when its renderer implicitly changes though.
Perhaps it could respond to a property change event, or have an explicit method
requesting its size be recomputing (something like 'revalidate', though
'revalidate' doesn't work in this instance).
The sample program shows the bug at its worst when the first item is selected
and is displayed in lowercase, and the ComboBox has been 'nudged.' Then when
you change the renderer to upper case, only the first part of the item is
displayed, followed by ellipsis.
From reading BasicComboBoxUI, it seems that the ComboBox will be resized if the
font property changes, the model property changes, or if the model is modified.
It seems inconsistent that it won't be resized when the renderer changes (since
the renderer seems to be just as vital to a 'correct' size as the font or the
model).
================================================================================
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Combo extends JPanel {
static final String UP_STR = "Upper Case";
static final String LO_STR = "Lower Case";
public Combo(boolean pUseOne) {
final boolean _useOneRenderer = pUseOne;
final ToStringIfc _toUp = new ToUpper();
final ToStringIfc _toLo = new ToLower();
final StringRenderer _rendUp;
final StringRenderer _rendLo;
final JComboBox _box = new JComboBox
(new Object[] { "LLLLLLLL", "First", "Second", "Third",
"Fourth" });
final JLabel _msg = new JLabel();
ListCellRenderer _impl = _box.getRenderer();
_rendUp = new StringRenderer(_impl, _toUp);
_rendLo = new StringRenderer(_impl, _toLo);
_box.setRenderer(_rendUp);
_msg.setText(_box.getPreferredSize().toString());
final JButton _toggleBtn = new JButton(LO_STR);
ActionListener _toggle = new ActionListener() {
public void actionPerformed(ActionEvent pAE) {
boolean _isUp =
_toggleBtn.getText().equals(UP_STR);
_toggleBtn.setText(_isUp ? LO_STR : UP_STR);
if (_useOneRenderer) {
((StringRenderer)_box.getRenderer()).setToString
(_isUp ? _toUp : _toLo);
} else {
_box.setRenderer(_isUp ? _rendUp :
_rendLo);
}
_msg.setText(_box.getPreferredSize().toString());
}
};
_toggleBtn.addActionListener(_toggle);
final JButton _nudgeBtn = new JButton("Nudge");
ActionListener _nudge = new ActionListener() {
public void actionPerformed(ActionEvent pAE) {
_box.addItem(null);
_box.removeItem(null);
_msg.setText(_box.getPreferredSize().toString());
}
};
_nudgeBtn.addActionListener(_nudge);
JPanel _left = new JPanel();
_left.setLayout(new BoxLayout(_left, BoxLayout.Y_AXIS));
_left.add(_toggleBtn);
_left.add(_nudgeBtn);
JPanel _right = new JPanel();
_right.setLayout(new BoxLayout(_right, BoxLayout.X_AXIS));
_right.add(_box);
setLayout(new BorderLayout());
add(_msg, BorderLayout.NORTH);
add(_left, BorderLayout.WEST);
add(_right, BorderLayout.EAST);
}
public static void main(String[] pArgs) {
boolean _useOne = false;
try {
_useOne = Boolean.valueOf(pArgs[0]).booleanValue();
} catch (Exception _e) { }
JFrame _frame = new JFrame
(_useOne ? "One changing renderer" : "Two different
renderers");
_frame.setContentPane(new Combo(_useOne));
_frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent pWE) {
System.exit(0);
} } );
_frame.pack();
_frame.setVisible(true);
}
}
interface ToStringIfc {
public String toString(Object pO);
}
class ToUpper implements ToStringIfc {
public String toString(Object pO) {
return String.valueOf(pO).toUpperCase();
}
}
class ToLower implements ToStringIfc {
public String toString(Object pO) {
return String.valueOf(pO).toLowerCase();
}
}
class StringRenderer implements ListCellRenderer {
ListCellRenderer impl;
ToStringIfc ifc;
public StringRenderer(ListCellRenderer pImpl, ToStringIfc pToString) {
impl = pImpl;
setToString(pToString);
}
public void setToString(ToStringIfc pToString) {
ifc = pToString;
}
public Component getListCellRendererComponent
(JList pList,
Object pValue,
int pIndex,
boolean pIsSelected,
boolean pCellHasFocus) {
return impl.getListCellRendererComponent
(pList, ifc.toString(pValue), pIndex, pIsSelected,
pCellHasFocus);
}
}
(Review ID: 107761)
======================================================================