到目前为止,这就是我所得到的,但一个主要问题是交叉 L&F 问题。另一种方法是遍历 ComboBox 模型的所有值和“无选择”值,并检查哪个是最长的。然后我可以将它设置为prototypeDisplayValue。问题是我需要一个图形上下文来测量每个字符串的边界。
以下是我们使用@Enwired 和@Robin 找到的两个解决方案。感谢他们俩。
编辑:在与@Robin 讨论后,我发现这个解决方案实际上要简单得多,并且适用于所有平台和外观。唯一的缺点是我们需要创建一个额外的 JComboBox。
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UnsupportedLookAndFeelException;
public class TestComboBox {
protected void initUI() {
JFrame frame = new JFrame(TestComboBox.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
JComboBox comboBox = new JComboBox(new Object[] { "Something", "Stuff", "Beep" }) {
private JComboBox internal;
private JComboBox getInternalComboBox() {
if (internal == null) {
internal = new JComboBox(new Object[] { null });
}
return internal;
}
@Override
public Dimension getPreferredSize() {
Dimension preferredSize = super.getPreferredSize();
if (getSelectedItem() == null) {
getInternalComboBox().setRenderer(getRenderer());
Dimension nullDimension = getInternalComboBox().getPreferredSize();
preferredSize.width = Math.max(preferredSize.width, nullDimension.width);
preferredSize.height = Math.max(preferredSize.height, nullDimension.height);
}
return preferredSize;
}
@Override
public void updateUI() {
internal = null;
super.updateUI();
}
};
comboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value == null) {
setText("No selection");
}
return comp;
}
});
comboBox.setSelectedItem(null);
panel.add(comboBox);
frame.add(panel);
frame.setSize(200, 100);
frame.setVisible(true);
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestComboBox().initUI();
}
});
}
}
编辑2:在与@Enwired 讨论后,提出了这个替代解决方案,即直接覆盖ListCellRenderer getPreferredSize。在这一个中,您可以尝试浏览不同的可用 L&F。
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
public class TestComboBox {
protected void initUI() {
final JFrame frame = new JFrame(TestComboBox.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
JComboBox comboBox = new JComboBox(new Object[] { "Something", "Stuff", "Beep" });
comboBox.setRenderer(new DefaultListCellRenderer() {
private Dimension nullDimesion;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value != null && nullDimesion == null) {
nullDimesion = ((JComponent) getListCellRendererComponent(list, null, -1, false, false)).getPreferredSize();
}
Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value == null) {
setText("No selection");
}
return comp;
}
@Override
public Dimension getPreferredSize() {
Dimension preferredSize = super.getPreferredSize();
if (nullDimesion != null) {
preferredSize.width = Math.max(preferredSize.width, nullDimesion.width);
preferredSize.height = Math.max(preferredSize.height, nullDimesion.height);
}
return preferredSize;
}
@Override
public void updateUI() {
nullDimesion = null;
super.updateUI();
}
});
comboBox.setSelectedItem(null);
final JComboBox uiComboBox = new JComboBox(UIManager.getInstalledLookAndFeels());
uiComboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof LookAndFeelInfo) {
LookAndFeelInfo info = (LookAndFeelInfo) value;
setText(info.getName());
}
return comp;
}
});
uiComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(((LookAndFeelInfo) uiComboBox.getSelectedItem()).getClassName());
SwingUtilities.updateComponentTreeUI(frame);
} catch (ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InstantiationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (UnsupportedLookAndFeelException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
}
});
panel.add(comboBox);
panel.add(uiComboBox);
frame.add(panel);
frame.setSize(300, 100);
frame.setVisible(true);
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestComboBox().initUI();
}
});
}
}