Pregunta

Tengo un JComboBox y me gustaría tener un separador en la lista de elementos. ¿Cómo hago esto en Java?

Un escenario de ejemplo en el que esto sería útil es cuando se hace un cuadro combinado para la selección de la familia de fuentes; similar a la fuente-familia-selección-control en Word y Excel. En este caso, me gustaría mostrar las fuentes más usadas en la parte superior, luego un separador y finalmente todas las familias de fuentes debajo del separador en orden alfabético.

¿Puede alguien ayudarme a hacer esto o esto no es posible en Java?

¿Fue útil?

Solución

Hay un tutorial bastante corto con un ejemplo que muestra cómo usar un ListCellRenderer personalizado en java2s   http://www.java2s.com/Code/Java/Swing-Components /BlockComboBoxExample.htm

Básicamente, implica la inserción de un marcador de posición conocido en su modelo de lista y cuando detecta el marcador de posición en el ListCellRenderer, devuelve una instancia de 'new JSeparator (JSeparator.HORIZONTAL)'

Otros consejos

Cuando escribí y probé el código a continuación, probablemente tengas muchas mejores respuestas ...
No me importa ya que disfruté el experimento / aprendizaje (todavía un poco verde en el frente de Swing).

[EDITAR] Tres años después, soy un poco menos verde y tomé en cuenta los comentarios válidos de Bobndrew. No tengo ningún problema con la navegación clave que simplemente funciona (¿tal vez fue un problema de versión de JVM?). Aunque mejoré el renderizador para mostrar lo más destacado. Y utilizo un mejor código de demostración. La respuesta aceptada es probablemente mejor (más estándar), la mía es probablemente más flexible si desea un separador personalizado ...

La idea base es utilizar un procesador para los elementos del cuadro combinado. Para la mayoría de los artículos, es un JLabel simple con el texto del artículo. Para el último artículo más reciente / más usado, decoré la JLabel con un borde personalizado dibujando una línea en su parte inferior.

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

Clase separadora, puede ser gruesa, con color personalizado, etc.

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

clase de prueba:

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

Puede usar un ListCellRenderer personalizado que dibujaría los elementos separadores de manera diferente. Consulte docs y un pequeño tutorial .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top