What happens is that the combo's internals try to find the preferred size dynamically. For doing so, it loops through all items in the list, feeds the renderer with the items to measure the rendering component's preferred size.
You can prevent that by setting a prototypeValue for measuring, then the size is measured once using that prototype
comboBox.setPrototypeDisplayValue(sampleFont);
Edit: as @Boro detected, that's not enough - it sets the prototype for the comboBox itself only, not for the list in the popup (as it should, how crazily buggy can that ... possibly be). To hack around, we have to manually set it, here's a code snippet to play with
public class ComboWithPrototype {
private JComponent createContent() {
final Font[] systemFonts = GraphicsEnvironment
.getLocalGraphicsEnvironment().getAllFonts();
final JComboBox box = new JComboBox();
box.setRenderer(new ComboBoxRenderer());
box.setPrototypeDisplayValue(systemFonts[0]);
Accessible a = box.getUI().getAccessibleChild(box, 0);
if (a instanceof javax.swing.plaf.basic.ComboPopup) {
JList popupList = ((javax.swing.plaf.basic.ComboPopup) a).getList();
// route the comboBox' prototype to the list
// should happen in BasicComboxBoxUI
popupList.setPrototypeCellValue(box.getPrototypeDisplayValue());
}
Action action = new AbstractAction("set model") {
@Override
public void actionPerformed(ActionEvent e) {
box.setModel(new DefaultComboBoxModel(systemFonts));
}
};
JComponent panel = new JPanel(new BorderLayout());
panel.add(box);
panel.add(new JButton(action), BorderLayout.SOUTH);
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ComboWithPrototype().createContent());
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
});
}
Custom ListCellRenderer (slightly changed, to expect items of type Font)
private class ComboBoxRenderer extends DefaultListCellRenderer {
private Font baseFont = new JLabel("Test").getFont();
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected,
cellHasFocus);
if (value instanceof Font) {
Font font = (Font) value;
setFont(new Font(font.getName(), baseFont.getStyle(), baseFont.getSize()));
setText(font.getName());
}
return this;
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…