我有一个 JComboBox,希望在元素列表中添加分隔符。如何在Java中实现此功能?
这个功能在创建字体选择的组合框时很有用,类似于Word和Excel中的字体选择控件。在这种情况下,我想在顶部显示最常用的字体,然后是一个分隔符,最后是按字母顺序排列的所有字体家族。
有谁能帮我解决如何实现这一点,或者在Java中是否不可能实现?
我有一个 JComboBox,希望在元素列表中添加分隔符。如何在Java中实现此功能?
这个功能在创建字体选择的组合框时很有用,类似于Word和Excel中的字体选择控件。在这种情况下,我想在顶部显示最常用的字体,然后是一个分隔符,最后是按字母顺序排列的所有字体家族。
有谁能帮我解决如何实现这一点,或者在Java中是否不可能实现?
这里有一个简短的教程和示例,展示了如何在java2s上使用自定义ListCellRenderer。基本上,它涉及在您的列表模型中插入已知的占位符,并在ListCellRenderer中检测到占位符时返回一个'new JSeparator(JSeparator.HORIZONTAL)'实例。
http://www.java2s.com/Code/Java/Swing-Components/BlockComboBoxExample.htm
import java.awt.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class TwoPartsComboBox extends JComboBox
{
private int m_lastFirstPartIndex;
public TwoPartsComboBox(String[] itemsFirstPart, String[] itemsSecondPart)
{
super(itemsFirstPart);
m_lastFirstPartIndex = itemsFirstPart.length - 1;
for (int i = 0; i < itemsSecondPart.length; i++)
{
insertItemAt(itemsSecondPart[i], i);
}
setRenderer(new JLRenderer());
}
protected class JLRenderer extends JLabel implements ListCellRenderer
{
private JLabel m_lastFirstPart;
public JLRenderer()
{
m_lastFirstPart = new JLabel();
m_lastFirstPart.setBorder(new BottomLineBorder());
// m_lastFirstPart.setBorder(new BottomLineBorder(10, Color.BLUE));
}
@Override
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
if (value == null)
{
value = "Select an option";
}
JLabel label = this;
if (index == m_lastFirstPartIndex)
{
label = m_lastFirstPart;
}
label.setText(value.toString());
label.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
label.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
label.setOpaque(true);
return label;
}
}
}
import java.awt.*;
import javax.swing.border.AbstractBorder;
/**
* Draws a line at the bottom only.
* Useful for making a separator in combo box, for example.
*/
@SuppressWarnings("serial")
class BottomLineBorder extends AbstractBorder
{
private int m_thickness;
private Color m_color;
BottomLineBorder()
{
this(1, Color.BLACK);
}
BottomLineBorder(Color color)
{
this(1, color);
}
BottomLineBorder(int thickness, Color color)
{
m_thickness = thickness;
m_color = color;
}
@Override
public void paintBorder(Component c, Graphics g,
int x, int y, int width, int height)
{
Graphics copy = g.create();
if (copy != null)
{
try
{
copy.translate(x, y);
copy.setColor(m_color);
copy.fillRect(0, height - m_thickness, width - 1, height - 1);
}
finally
{
copy.dispose();
}
}
}
@Override
public boolean isBorderOpaque()
{
return true;
}
@Override
public Insets getBorderInsets(Component c)
{
return new Insets(0, 0, m_thickness, 0);
}
@Override
public Insets getBorderInsets(Component c, Insets i)
{
i.left = i.top = i.right = 0;
i.bottom = m_thickness;
return i;
}
}
测试类:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class TwoPartsComboBoxDemo extends JFrame
{
private TwoPartsComboBox m_combo;
public TwoPartsComboBoxDemo()
{
Container cont = getContentPane();
cont.setLayout(new FlowLayout());
cont.add(new JLabel("Data: ")) ;
String[] itemsRecent = new String[] { "ichi", "ni", "san" };
String[] itemsOther = new String[] { "one", "two", "three" };
m_combo = new TwoPartsComboBox(itemsRecent, itemsOther);
m_combo.setSelectedIndex(-1);
cont.add(m_combo);
m_combo.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
String si = (String) m_combo.getSelectedItem();
System.out.println(si == null ? "No item selected" : si.toString());
}
});
// Reference, to check we have similar behavior to standard combo
JComboBox combo = new JComboBox(itemsRecent);
cont.add(combo);
}
/**
* Start the demo.
*
* @param args the command line arguments
*/
public static void main(String[] args)
{
// turn bold fonts off in metal
UIManager.put("swing.boldMetal", Boolean.FALSE);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame demoFrame = new TwoPartsComboBoxDemo();
demoFrame.setTitle("Test GUI");
demoFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
demoFrame.setSize(400, 100);
demoFrame.setVisible(true);
}
});
}
}
m_combo
和m_renderer
(在public TestGui()
中)。而且不应该为Renderer 和 'TestGui'类(它应该是一个孤独的Main类,而不是'JFrame'子类)使用全局的m_lastRecentIndex
。但我喜欢大括号的风格! - bobndrew尝试添加此渲染器。只需提供您想要分隔符位于上方的索引值列表即可。
private class SeperatorComboRenderer extends DefaultListCellRenderer
{
private final float SEPARATOR_THICKNESS = 1.0f;
private final float SPACE_TOP = 2.0f;
private final float SPACE_BOTTOM = 2.0f;
private final Color SEPARATOR_COLOR = Color.DARK_GRAY;
private final List<Integer> marks;
private boolean mark;
private boolean top;
public SeperatorComboRenderer(List<Integer> marks)
{
this.marks = marks;
}
@Override
public Component getListCellRendererComponent(JList list, Object object, int index, boolean isSelected, boolean hasFocus)
{
super.getListCellRendererComponent(list, object, index, isSelected, hasFocus);
top = false;
mark = false;
marks.forEach((idx) ->
{
if(index - 1 == idx)
top = true;
if(index == idx)
mark = true;
});
return this;
}
@Override
protected void paintComponent(Graphics g)
{
if(mark)
g.translate(0, (int)(SEPARATOR_THICKNESS + SPACE_BOTTOM));
Graphics2D g2 = (Graphics2D)g;
super.paintComponent(g);
if(mark)
{
g2.setColor(SEPARATOR_COLOR);
g2.setStroke(new BasicStroke(SEPARATOR_THICKNESS));
g2.drawLine(0, 0, getWidth(), 0);
}
}
@Override
public Dimension getPreferredSize()
{
Dimension pf = super.getPreferredSize();
double height = pf.getHeight();
if(top) height += SPACE_TOP;
else if(mark) height += SEPARATOR_THICKNESS + SPACE_BOTTOM;
return new Dimension((int)pf.getWidth(), (int)height);
}
}
BlockComboBoxExample
示例破坏了光标键和首字母键导航。Santhosh Kumar的示例似乎工作得更好。 - bobndrew