How can I change the width of a JComboBox dropdown list?
Asked Answered
S

7

33

I have an editable JComboBox which contains a list of single letter values. Because of that the combobox is very small.

Every letter has a special meaning which sometimes isn't clear to the user in case of rarely used letters. Because of that I've created a custom ListCellRenderer which shows the meaning of each letter in the dropdown list.

Unfortunately this explanation doesn't fit into the dropdown because it is to small, because it has the same width as the combobox.

Is there any way to make the dropdown list wider than the combobox?

This is what I want to achieve:

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

I cannot change the width of the combobox because the application is a recreation of an old legacy application where some things have to be exactly as they were before. (In this case the combobox has to keep it's small size at all costs)

Surname answered 5/6, 2009 at 14:0 Comment(0)
R
18

I believe the only way to do this with the public API is to write a custom UI (there are two bugs dealing with this).

If you just want something quick-and-dirty, I found this way to use implementation details to do it (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);
}

Put this in a PopupMenuListener and it might work for you.

Or you could use the code from the 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());
  }
}
Rummel answered 5/6, 2009 at 14:11 Comment(4)
Both methods seem to work but popupMenuWillBecomeVisible only works if you also provide a custom ListCellRenderer. The default one seems to cut the strings at the original size.Surname
The first one dose not work for me when there is bellow 8 items in the JComboBox(OSX). And the second one have the look of windows even on MAC....Brendonbrenk
First solution doesn't work, as popupMenuWillBecomeVisible is called before the size is set (see show() in BasicComboPopup), so any size you set in that listener will be overwritten.Introversion
The answer to it can be found in JDK source code 'BasicComboPopup#getPopupLocation', we can copy its solution on calculation size and adjsting size to 'popupMenuWillBecomeVisible()' of our PopupMenuListener, for too-long-item we can even set location of pop-up menu too (its location is 'on-screen location').Maritamaritain
E
16

Here is a great solution by Santhosh Kumar, without the need to mess with UI's and other nasty stuff like that!

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; 
    } 
}
Exorcism answered 3/11, 2011 at 11:38 Comment(3)
This solution does not adjust height, just the width. Adjusting height is far more complicated.Varien
this solution breaks 'arrow' of original combobox. after applied, no arrows anymoreMaritamaritain
This solution no longer works in Java 1.8.0_202. getSize() is never invoked at all in that version.Juxtaposition
M
8

Here is a nice solution from tutiez.

Before setting up the Dimension of popup list, it gets the biggest item from it and calculated the width needed to show it completely.

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

    }
}

The code above has already a main for a quick test. But notice that the statement below may be adjusted to around 20 if you want to have a vertical scroll.

return widest + 5;

Hope it is useful for future reference!

Marissamarist answered 16/4, 2012 at 21:51 Comment(0)
H
1

Sounds like you'll need to write your own ComboBoxUI.

There is a good example here that shows how to accomplish this.

Also note, the method you would probably be interested in is the createPopup() method. This is the method that creates the popup for the combo box and where you would be able to customize it.

Hickerson answered 5/6, 2009 at 14:10 Comment(1)
Note: Links are brokenInformation
H
0

You might want to use setSize() method.

combo.setSize(200, combo.getPreferredSize().height);
Histiocyte answered 28/1, 2013 at 23:51 Comment(0)
K
0

Here you have a simple piece of code without extends JComboBox nor other any class

In this example the with of drop down is 500 always. You also can modify the height or the location.

        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);
                    }                       
                };
            }
        });
Kelly answered 16/5, 2018 at 21:53 Comment(0)
H
0

This was my way of fixing it which works fine and you don't have to mess about with the ComboBoxUI so it stays with the same look. I only needed to change the width but I'm sure you could very easily change the height with this also.

new PopupMenuListener() {
  @Override
  public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    @SuppressWarnings("unchecked")
    JComboBox<String> comboBox = (JComboBox<String>) e.getSource();
    
    BasicComboPopup popup = (BasicComboPopup) comboBox.getAccessibleContext().getAccessibleChild(0);

    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        //Get the scroll pane from the popup list
        JScrollPane scrollPane = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, popup.getList());
        
        //Get the width of the popup list
        int popupWidth = popup.getList().getPreferredSize().width;
        
        //Set the scrollpane to that size
        Dimension scrollPaneSize = scrollPane.getPreferredSize();
        scrollPaneSize.width = Math.max(popupWidth, 100);
        scrollPane.setPreferredSize(scrollPaneSize);
        scrollPane.setMaximumSize(scrollPaneSize);

        //Change the location or the preferred size doesn't update
        try {
          Point location = comboBox.getLocationOnScreen();
          int height = comboBox.getPreferredSize().height;
          popup.setLocation(location.x, location.y + height - 1);
          popup.setLocation(location.x, location.y + height);
        } catch(IllegalComponentStateException exc) {
        }
      }
    });
Havener answered 18/2, 2022 at 17:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.