2009-06-05 44 views
26

Tengo un JComboBox editable que contiene una lista de valores de una sola letra. Debido a eso, el combobox es muy pequeño.¿Cómo puedo cambiar el ancho de una lista desplegable JComboBox?

Cada letra tiene un significado especial que a veces no es claro para el usuario en caso de letras poco utilizadas. Por eso he creado un ListCellRenderer personalizado que muestra el significado de cada letra en la lista desplegable.

Desafortunadamente, esta explicación no cabe en el menú desplegable porque es demasiado pequeña, porque tiene el mismo ancho que el cuadro combinado.

¿Hay alguna manera de hacer que la lista desplegable sea más amplia que el combobox?

Esto es lo que quiero lograr:

--------------------- 
| Small JCombobox | V | 
-------------------------------------------- 
| "Long item 1"        | 
-------------------------------------------- 
| "Long item 2"        | 
-------------------------------------------- 
| "Long item 3"        | 
-------------------------------------------- 

No puedo cambiar el ancho del cuadro combinado porque la aplicación es una recreación de un antiguo uso de la herencia donde algunas cosas tienen que ser exactamente como estaban antes. (En este caso, el cuadro combinado debe mantener su pequeño tamaño a toda costa)

Respuesta

14

Creo que la única forma de hacerlo con la API pública es escribir una interfaz de usuario personalizada (hay twobugs que trata esto).

Si lo que desea es algo rápido y sucio, he encontrado esta manera de utilizar los detalles de implementación para hacerlo (here):

public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 
    JComboBox box = (JComboBox) e.getSource(); 
    Object comp = box.getUI().getAccessibleChild(box, 0); 
    if (!(comp instanceof JPopupMenu)) return; 
    JComponent scrollPane = (JComponent) ((JPopupMenu) comp).getComponent(0); 
    Dimension size = new Dimension(); 
    size.width = box.getPreferredSize().width; 
    size.height = scrollPane.getPreferredSize().height; 
    scrollPane.setPreferredSize(size); 
    // following line for Tiger 
    // scrollPane.setMaximumSize(size); 
} 

poner esto en un PopupMenuListener y fuerza trabajo por usted .

O puede utilizar el código de la first linked bug:

class StyledComboBoxUI extends BasicComboBoxUI { 
    protected ComboPopup createPopup() { 
    BasicComboPopup popup = new BasicComboPopup(comboBox) { 
     @Override 
     protected Rectangle computePopupBounds(int px,int py,int pw,int ph) { 
     return super.computePopupBounds(
      px,py,Math.max(comboBox.getPreferredSize().width,pw),ph 
     ); 
     } 
    }; 
    popup.getAccessibleContext().setAccessibleParent(comboBox); 
    return popup; 
    } 
} 

class StyledComboBox extends JComboBox { 
    public StyledComboBox() { 
    setUI(new StyledComboBoxUI()); 
    } 
} 
+0

Ambos métodos parecen funcionar pero popupMenuWillBecomeVisible solo funciona si también proporciona un ListCellRenderer personalizado. El predeterminado parece cortar las cuerdas en el tamaño original. –

+0

La primera dosis no me funciona cuando hay menos de 8 elementos en JComboBox (OSX). Y el segundo tiene el aspecto de Windows incluso en MAC ... – Grains

+0

La primera solución no funciona, ya que se llama a popupMenuWillBecomeVisible antes de que se establezca el tamaño (ver show() en BasicComboPopup), por lo que cualquier tamaño que establezca en ese oyente será sobrescrito –

1

Parece que tendrá que escribir su propio ComboBoxUI.

Hay un buen ejemplo here que muestra cómo lograr esto.

También tenga en cuenta que el método que probablemente le interese es el método createPopup(). Este es el método que crea la ventana emergente para el cuadro combinado y donde podría personalizarlo.

13

Aquí es una gran solución por Santhosh Kumar, sin la necesidad de meterse con la interfaz de usuario y otras cosas desagradables ¡como eso!

http://www.jroller.com/santhosh/entry/make_jcombobox_popup_wide_enough

import javax.swing.*; 
import java.awt.*; 
import java.util.Vector; 

// got this workaround from the following bug: 
//  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4618607 
public class WideComboBox extends JComboBox{ 

    public WideComboBox() { 
    } 

    public WideComboBox(final Object items[]){ 
     super(items); 
    } 

    public WideComboBox(Vector items) { 
     super(items); 
    } 

     public WideComboBox(ComboBoxModel aModel) { 
     super(aModel); 
    } 

    private boolean layingOut = false; 

    public void doLayout(){ 
     try{ 
      layingOut = true; 
       super.doLayout(); 
     }finally{ 
      layingOut = false; 
     } 
    } 

    public Dimension getSize(){ 
     Dimension dim = super.getSize(); 
     if(!layingOut) 
      dim.width = Math.max(dim.width, getPreferredSize().width); 
     return dim; 
    } 
} 
+0

Esta solución no ajusta la altura, solo el ancho. Ajustar la altura es mucho más complicado. – DejanLekic

+0

no funciona para mí – user489872

+0

esta solución rompe la 'flecha' del combobox original. después de aplicado, ya no hay flechas –

3

Aquí es una buena solución de tutiez.

Antes de configurar la dimensión de la lista emergente, obtiene el elemento más grande y calcula el ancho necesario para mostrarlo por completo.

public class WiderDropDownCombo extends JComboBox { 

    private String type; 
    private boolean layingOut = false; 
    private int widestLengh = 0; 
    private boolean wide = false; 

    public WiderDropDownCombo(Object[] objs) { 
     super(objs); 
    } 

    public boolean isWide() { 
     return wide; 
    } 

    // Setting the JComboBox wide 
    public void setWide(boolean wide) { 
     this.wide = wide; 
     widestLengh = getWidestItemWidth(); 

    } 

    public Dimension getSize() { 
     Dimension dim = super.getSize(); 
     if (!layingOut && isWide()) 
      dim.width = Math.max(widestLengh, dim.width); 
     return dim; 
    } 

    public int getWidestItemWidth() { 

     int numOfItems = this.getItemCount(); 
     Font font = this.getFont(); 
     FontMetrics metrics = this.getFontMetrics(font); 
     int widest = 0; 
     for (int i = 0; i < numOfItems; i++) { 
      Object item = this.getItemAt(i); 
      int lineWidth = metrics.stringWidth(item.toString()); 
      widest = Math.max(widest, lineWidth); 
     } 

     return widest + 5; 
    } 

    public void doLayout() { 
     try { 
      layingOut = true; 
      super.doLayout(); 
     } finally { 
      layingOut = false; 
     } 
    } 

    public String getType() { 
     return type; 
    } 

    public void setType(String t) { 
     type = t; 
    } 

    public static void main(String[] args) { 
     String title = "Combo Test"; 
     JFrame frame = new JFrame(title); 

     String[] items = { 
       "I need lot of width to be visible , oh am I visible now", 
       "I need lot of width to be visible , oh am I visible now" }; 
     WiderDropDownCombo simpleCombo = new WiderDropDownCombo(items); 
     simpleCombo.setPreferredSize(new Dimension(180, 20)); 
     simpleCombo.setWide(true); 
     JLabel label = new JLabel("Wider Drop Down Demo"); 

     frame.getContentPane().add(simpleCombo, BorderLayout.NORTH); 
     frame.getContentPane().add(label, BorderLayout.SOUTH); 
     int width = 200; 
     int height = 150; 
     frame.setSize(width, height); 
     frame.setVisible(true); 

    } 
} 

El código anterior ya tiene una fuente principal para una prueba rápida.Pero tenga en cuenta que la siguiente declaración se puede ajustar a alrededor de si desea tener un desplazamiento vertical.

return widest + 5; 

Espero que sea útil para futuras referencias.

0

Es posible que desee utilizar el método setSize().

combo.setSize(200, combo.getPreferredSize().height); 
Cuestiones relacionadas