modificar - ¿Cómo agrego un separador a un JComboBox en Java?
modificar jcombobox java (3)
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 insertar 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 ''nuevo JSeparator (JSeparator.HORIZONTAL)''
Tengo un JComboBox y me gustaría tener un separador en la lista de elementos. ¿Cómo hago esto en Java?
Un escenario de muestra donde esto sería útil es cuando se crea un cuadro combinado para la selección de la familia de fuentes; similar al control de selección de la familia de fuentes en Word y Excel. En este caso, me gustaría mostrar las fuentes más utilizadas en la parte superior, luego un separador y finalmente todas las familias de fuentes debajo del separador en orden alfabético.
¿Alguien puede ayudarme con cómo hacer esto o esto no es posible en Java?
Puede usar un ListCellRenderer
personalizado que dibujaría los elementos separadores de forma diferente. Ver documentos y un pequeño tutorial .
En el momento en que escribí y probé el código a continuación, probablemente obtuviste muchas mejores respuestas ...
No me molesta, ya que disfruté el experimento / aprendizaje (todavía un poco verde en el frente de Swing).
[EDITAR] Tres años después, estoy un poco menos verde, y tomé en cuenta los comentarios válidos de bobndrew. No tengo ningún problema con la navegación de teclas que simplemente funciona (¿quizás fue un problema de versión de JVM?). Sin embargo, mejoré el renderizador para mostrar el resaltado. Y uso 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 quieres un separador personalizado ...
La idea básica es usar 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, decorar el 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 de separador, puede ser grueso, 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);
}
});
}
}