2008-09-26 37 views
10

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

Un escenario de ejemplo en el que 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 me puede ayudar con cómo hacer esto o esto no es posible en Java?

Respuesta

7

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

Básicamente consiste en insertar un marcador de posición conocida en el modelo de lista y cuando se detecta el marcador de posición en el ListCellRenderer se devolver una instancia de la 'nueva JSeparator (JSeparator.HORIZONTAL)'

+2

El 'ejemplo BlockComboBoxExample' rompe la tecla del cursor y la primera navegación con la tecla de la letra El [ejemplo] de Santhosh Kumar (http://www.jroller.com/santhosh/entry/jcombobox%5Fitems%5Fwith%5Fseparators) parece funcionar mejor. – bobndrew

2

Puede usar un ListCellRenderer personalizado que dibujaría los elementos del separador de forma diferente. Ver docs y un pequeño tutorial.

4

En el momento en que escribí y probado por debajo del código, probablemente tiene mucho mejores respuestas ...
no me importa como me gustó el experimento/aprendizaje (aún un poco verde en el frente de Swing).

[EDITAR] Tres años más tarde, 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 desea 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 separación, puede ser de espesor, con colores personalizados, 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); 
     } 
    }); 
    } 
} 
+0

Su nomenclatura variable no es lo peor aquí: está rompiendo toda la selección del elemento combobox: la selección ya no está pintada y los saltos de teclas de la primera letra están rotos. Y debe definir 'm_combo' y' m_renderer' en el ámbito más pequeño posible (en 'public TestGui()'). Y no debería usar un glooooobal 'm_lastRecentIndex' para el Renderer ** y ** la clase 'TestGui' (que debería ser una clase principal solitaria, no una subclase 'JFrame'). ¡Pero me gusta el estilo de llaves! – bobndrew

+0

@bobndrew: hey! Cuando escribí, era un novato en ese momento (¡3 años ya!). Entre los pecados que no señalas, probablemente utilicé alguna plantilla de prueba de Swing que encontré y, lo que es peor, ¡no usé SwingUtilities.invokeLater! El código que tengo actualmente lo usa, al menos (pero sigue siendo una subclase JFrame ...). Y m_lastRecentIndex es más local ... Pero la mayoría de tus críticas se refieren a una clase de prueba hecha rápidamente, que no es realmente código de producción.Hoy, le presto más atención a dicho código, ya que los novatos pueden inspirarse en él ... :-) Además, tienes razón al destacar los elementos y la selección de los elementos. TODO – PhiLho

+0

Nota: he editado el código anterior para una versión más moderna/correcta. Una ventaja de mi enfoque es que es más flexible (al menos en apariencia) que JSeparator y no ocupa un espacio. – PhiLho

Cuestiones relacionadas