Как добавить разделитель в JComboBox в Java?

У меня есть JComboBox и хотел бы иметь разделитель в списке элементов. Как это сделать на Java?

Примерный сценарий, в котором это может пригодиться, – это сделать combobox для выбора семейства шрифтов; аналогично элементу выбора font-family в Word и Excel. В этом случае я хотел бы показать наиболее используемые шрифты вверху, затем разделитель и, наконец, все шрифтовые семейства под разделителем в алфавитном порядке.

Может ли кто-нибудь помочь мне с тем, как это сделать, или это невозможно в Java?

    Существует довольно короткий учебник с примером, который показывает, как использовать пользовательский ListCellRenderer для java2s http://www.java2s.com/Code/Java/Swing-Components/BlockComboBoxExample.htm

    В основном это связано с вставкой известного заполнителя в вашу модель списка и при обнаружении заполнителя в ListCellRenderer вы возвращаете экземпляр «нового JSeparator (JSeparator.HORIZONTAL)»,

    К тому времени, как я написал и протестировал код ниже, вы, вероятно, получили много лучших ответов …
    Я не возражаю, поскольку я наслаждался экспериментом / обучением (все еще немного зеленым на фронте Swing).

    [EDIT] Спустя три года я немного менее зеленый, и я принял во внимание действительные замечания bobndrew. У меня нет проблем с ключевой навигацией, которая просто работает (возможно, это проблема с версией JVM?). Однако я улучшил рендеринг, чтобы показать выделение. И я использую лучший демо-код. Принятый ответ, вероятно, лучше (более стандартный), мой, вероятно, более гибкий, если вы хотите использовать специальный разделитель …

    Основная идея – использовать средство рендеринга для элементов комбинированного блока. Для большинства элементов это простой JLabel с текстом элемента. Для последнего последнего / наиболее используемого элемента я украшаю JLabel специальной рамкой, рисующей линию внизу.

     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); } }); } } 

    Вы можете использовать пользовательский ListCellRenderer который будет рисовать элементы разделителя по-разному. См. Документы и небольшой учебник .