web-dev-qa-db-fra.com

Comment changer la largeur d'une liste déroulante de JComboBox?

J'ai une variable JComboBox éditable qui contient une liste de valeurs à lettre unique. Pour cette raison, la liste déroulante est très petite.

Chaque lettre a une signification spéciale qui, parfois, n’est pas claire pour l’utilisateur lorsque les lettres sont rarement utilisées. À cause de cela, j'ai créé une variable ListCellRenderer personnalisée qui indique la signification de chaque lettre de la liste déroulante.

Malheureusement, cette explication ne rentre pas dans la liste déroulante car elle est trop petite, car elle a la même largeur que la liste déroulante.

Est-il possible d'élargir la liste déroulante au-delà de la liste déroulante?

C'est ce que je veux réaliser:

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

Je ne peux pas modifier la largeur de la liste déroulante car l'application est une reconstitution d'une ancienne application héritée dans laquelle certaines choses doivent être exactement comme avant. (Dans ce cas, la combobox doit conserver sa petite taille à tout prix)

27
Daniel Rikowski

Je crois que la seule façon de faire cela avec l'API publique est d'écrire une interface utilisateur personnalisée (il y a deux _ { bugs qui traitent de cela).

Si vous voulez juste quelque chose de rapide et sale, j'ai trouvé cette façon d'utiliser les détails d'implémentation pour le faire ( ici ):

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

Mettez ceci dans un PopupMenuListener et il pourrait travailler pour vous.

Ou vous pouvez utiliser le code du premier bogue lié :

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());
  }
}
14
Michael Myers
16
Charlie

Voici une excellente solution de Santhosh Kumar, sans avoir à vous soucier de l’interface utilisateur et d’autres choses désagréables comme celle-là!

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

Voici une belle solution de tutiez .

Avant de configurer la liste Dimension of popup, il en extrait le plus gros élément et calcule la largeur nécessaire pour l'afficher complètement.

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

    }
}

Le code ci-dessus a déjà un principal pour un test rapide. Mais remarquez que l’énoncé ci-dessous peut être ajusté à environ20si vous souhaitez un défilement vertical.

return widest + 5;

J'espère que c'est utile pour référence future!

5
rafaelrezend

On dirait que vous aurez besoin d'écrire votre propre ComboBoxUI .

Il y a un bon exemple ici qui montre comment y parvenir.

Notez également que la méthode qui vous intéresserait probablement est la méthode createPopup(). C'est la méthode qui crée la fenêtre contextuelle pour la liste déroulante et où vous pourrez la personnaliser.

1
thedude19

Vous voudrez peut-être utiliser la méthode setSize().

combo.setSize(200, combo.getPreferredSize().height);
0
Ned

Ici vous avez un simple morceau de code sans extension JComboBox ni autre classe

Dans cet exemple, la fin de la liste est toujours 500. Vous pouvez également modifier la hauteur ou l'emplacement.

        FaceCorrectiveReasonComboBox.getTextComponent().setUI(new BasicComboBoxUI() {
            @Override protected ComboPopup createPopup() {
                return new BasicComboPopup(comboBox) {
                    protected Rectangle computePopupBounds(int px,int py,int pw,int ph) {
                        return super.computePopupBounds(px, py, 500, ph);
                    }                       
                };
            }
        });
0
josepmra