我有以下情况:在JCombobox中,首选大小基于最大的项目大小。但是,此计算不考虑为null
呈现的值。它只关心模型中的值。因此,当渲染空值的文本大于另一个元素时,标签会被截断,并且我在末尾有三个点(...)。我想避免这种情况。
这是我正在谈论的一个小演示:
import java.awt.Component;
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;
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" });
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) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestComboBox().initUI();
}
});
}
}
我想知道你是否有任何建议。到目前为止,我的想法是扩展JComboBox,覆盖首选大小,还执行null值的呈现,并将调用的最大维度带到super.preferredSize和空值呈现之一。但我发现这有点令人失望。
我真的不想使用prototypeDisplayValue 绝对不是一个选项,因为我不知道该下拉列表中的值。
答案 0 :(得分:1)
我将利用这样一个事实:我们知道从Component
返回的DefaultListCellRenderer.getListCellRendererComponent
是DefaultListCellRenderer
对象本身,并且它是{{1}的实例}}
我还假设您的外观以常规方式计算组合框的首选大小,类似于JLabel
。
有了这些信息,这个解决方案可能很丑陋且效率低下,但它确实有效:
BasicComboBoxUI
答案 1 :(得分:1)
我没有在代码中对此进行测试,但我的方法是:
preferredSize
Component
与preferredSize
的实际JComboBox
之间的差异。不是通过使用任何硬编码值,而只是通过创建仅包含一个项目和已知渲染器的幕后JComboBox
,并将JComboBox
的首选大小与大小相比较已知渲染器返回的Component
。UIManager
getPreferredSize
的{{1}}并返回JComboBox
和super.getPreferredSize()
这应该处理“外观”问题,避免不必要的计算,您可以轻松创建包含此功能的getPreferredSize( rendererComponent ) + calculatedDifference
扩展名。
答案 2 :(得分:0)
所以这就是我到目前为止所得到的,但一个主要问题是交叉L&amp; F问题。另一种方法是遍历ComboBox模型的所有值和值“No selection”,并检查哪一个是最长的。然后我可以将它设置为prototypeDisplayValue。问题是我需要一个图形上下文来测量每个字符串的边界。
以下是我们在@Enwired和@Robin中找到的2个解决方案。感谢他们两人。
编辑:在与@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&amp; 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();
}
});
}
}