2009-06-05 12 views
26

Ho un JComboBox modificabile che contiene un elenco di valori a lettera singola. Per questo motivo la casella combinata è molto piccola.Come posso modificare la larghezza di un elenco a discesa JComboBox?

Ogni lettera ha un significato speciale che a volte non è chiaro all'utente in caso di lettere usate raramente. Per questo motivo ho creato una custom ListCellRenderer che mostra il significato di ogni lettera nell'elenco a discesa.

Sfortunatamente questa spiegazione non rientra nel menu a discesa perché è troppo piccola, perché ha la stessa larghezza della casella combinata.

Esiste un modo per rendere l'elenco a discesa più ampio rispetto alla casella combinata?

Questo è ciò che voglio raggiungere:

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

Non posso cambiare la larghezza della casella combinata perché l'applicazione è una ricostruzione di una vecchia applicazione legacy in cui alcune cose devono essere esattamente come erano prima. (In questo caso la casella combinata deve mantenere le sue dimensioni ridotte a tutti i costi)

risposta

14

Credo che l'unico modo per farlo con l'API pubblica sia scrivere un'interfaccia utente personalizzata (ci sono twobugs che si occupano di questo).

Se si desidera solo qualcosa di veloce-e-sporca, ho trovato questo modo per utilizzare i dettagli di implementazione per farlo (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); 
} 

mettere questo in un PopupMenuListener e forza lavoro per voi .

Oppure si potrebbe usare il codice dal 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

Entrambi i metodi sembrano funzionare ma popupMenuWillBecomeVisible funziona solo se si fornisce anche un ListCellRenderer personalizzato. Quello predefinito sembra tagliare le stringhe alla dimensione originale. –

+0

La prima dose non funziona per me quando sono presenti 2 elementi in JComboBox (OSX). E il secondo ha l'aspetto di Windows anche su MAC .... – Grains

+0

La prima soluzione non funziona, come popupMenuWillBecomeVisible viene chiamato prima che la dimensione sia impostata (vedi show() in BasicComboPopup), quindi qualsiasi dimensione impostata in quel listener sarà sovrascritto. –

1

Suoni come se fosse necessario scrivere il proprio ComboBoxUI.

C'è un buon esempio here che mostra come ottenere ciò.

Nota anche, il metodo che probabilmente ti interessa è il metodo createPopup(). Questo è il metodo che crea il popup per la casella combinata e dove potresti personalizzarlo.

13

Ecco una grande soluzione per Santhosh Kumar, senza la necessità di pasticciare con interfaccia utente e altre cose brutte come quello!

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

Questa soluzione non regola l'altezza, ma solo la larghezza. La regolazione dell'altezza è molto più complicata. – DejanLekic

+0

non funziona per me – user489872

+0

questa soluzione rompe la "freccia" della casella combinata originale. dopo l'applicazione, nessuna freccia più –

3

Ecco una bella soluzione da tutiez.

Prima di impostare la dimensione dell'elenco popup, ottiene l'elemento più grande da esso e calcolato la larghezza necessaria per mostrarlo completamente.

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

    } 
} 

Il codice sopra è già un elemento principale per un test rapido.Ma si noti che la seguente dichiarazione può essere adattata a circa se si desidera avere uno scorrimento verticale.

return widest + 5; 

Spero che sia utile per riferimento futuro!

0

È possibile utilizzare il metodo setSize().

combo.setSize(200, combo.getPreferredSize().height); 
Problemi correlati