Dynamically size the width of a JComboBox to avoid '...' in all scenarios

1k Views Asked by At

The following example places a JComboBox on a Frame and loads 5 items.

When the application runs, the combobox is displayed and what is seen is "Long Item..."

Without knowing actually activating the combobox, the user has no idea which record is actually visible.

Keep in mind, this is actually a dynamically loaded JComboBox. Using hard-coded values only for the example. As a result, the length of the longest string won't be available until run-time.

import javax.swing.JComboBox;
import javax.swing.JFrame;
public class JComboBoxTestLength  {
    JFrame f;
    JComboBoxTestLength (){
        f=new JFrame("ComboBox Example");
        String country[]={"Long Item 5","Long Item 2","Long Item 1","Long Item 8","Long Item 4"};
        JComboBox cb=new JComboBox(country);
        cb.setBounds(50, 50,90,20);
        f.add(cb);
        f.setLayout(null);
        f.setSize(400,500);
        f.setVisible(true);
    }
    public static void main(String[] args) {
        new JComboBoxTestLength ();
    }
}

Some threads indicate to avoid using setPreferredSize().

Although I could just set the setBounds() values to be long enough but want it to look aesthetically pleasing and would like to calculated it based on the longest string + 2 or something like that.

Is it possible to calculate the width for the JComboBox to avoid seeing '...' appear for any of the text?

2

There are 2 best solutions below

2
c0der On BEST ANSWER

As commented by Andrew Thomson use Layout managers to achieve the desired layout.
In this case wrapping the combo with a JPanel that uses FlowLayout can do the work for you:

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class JComboBoxTestLength  {

    JComboBoxTestLength (){
        JFrame f=new JFrame("ComboBox Example");
        String country[]={"Long Item 5","Long Item 2","Long Item 1","Long Item 8","Long Item 4"};
        JComboBox<String> cb=new JComboBox<>(country);
        JPanel comboPane = new JPanel(); //uses FlowLayout by default
        comboPane.add(cb);
        f.add(cb); //JFrame content pane uses BorderLayout by default 
        f.pack();
        f.setVisible(true);
    }
    public static void main(String[] args) {
        new JComboBoxTestLength ();
    }
}

enter image description here

2
Andrew Thompson On

Here is a more complete example of using a FlowLayout to correctly position and size 20 combo boxes. The width of the combo boxes is only known at initialization, yet each is wide enough to display the longest string it contains.

enter image description here

For suggesting a size when the combo will only be populated later, give the combo the longest string expected and call setPrototypeDisplayValue(E), then set an empty model after the GUI is packed.

Here is the code which produces the view as seen above.

import java.awt.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class BigComboSize {

    private JComponent ui = null;
    public final static String INPUT = "Lorem ipsum dolor sit amet, ex mea nostro dictas, duo ludus quando perpetua et. Vis wisi delicata referrentur ex, nec sonet verear molestie eu, commodo impetus ea sit. Mea an audiam debitis similique. No fastidii facilisi democritum est.";
    public final static String[] INPUT_ARRAY = INPUT.split(" ");
    Random random = new Random();

    BigComboSize() {
        initUI();
    }

    public final void initUI() {
        if (ui!=null) return;

        ui = new JPanel(new BorderLayout(4,4));
        ui.setBorder(new EmptyBorder(4,4,4,4));

        JPanel comboPanel = new JPanel();
        comboPanel.setPreferredSize(new Dimension(800,150));
        ui.add(comboPanel);
        for (int ii=0; ii<20; ii++) {
            String[] strings = {
                getRandomString(), getRandomString(), getRandomString()
            };
            JComboBox<String> combo = new JComboBox<>(strings);
            comboPanel.add(combo);
        }

        JTextArea inputArea = new JTextArea(INPUT, 3, 100);
        inputArea.setEnabled(false);
        inputArea.setLineWrap(true);
        inputArea.setWrapStyleWord(true);
        ui.add(new JScrollPane(inputArea), BorderLayout.PAGE_END);
    }

    private String getRandomString() {
        StringBuilder sb = new StringBuilder();

        int sttIndex = random.nextInt(INPUT_ARRAY.length-7);
        int endIndex = sttIndex + 1 + random.nextInt(6);
        for (int ii=sttIndex; ii<endIndex; ii++) {
            sb.append(INPUT_ARRAY[ii]);
            sb.append(" ");
        }

        return sb.toString().trim();
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception useDefault) {
            }
            BigComboSize o = new BigComboSize();

            JFrame f = new JFrame(o.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);

            f.setContentPane(o.getUI());
            f.pack();
            f.setMinimumSize(f.getSize());

            f.setVisible(true);
        };
        SwingUtilities.invokeLater(r);
    }
}