1

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?

c0der
  • 18,467
  • 6
  • 33
  • 65
Unhandled Exception
  • 1,427
  • 14
  • 30
  • `jComboBox1.setToolTipText(jComboBox1.getSelectedItem().toString());` – DevilsHnd - 退職した Jul 27 '19 at 04:11
  • *"Dynamically size the width of a JComboBox to avoid '…' in all scenarios"* Let the layouts take care of it. Oh, `f.setLayout(null);` and **don't** do that. Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). – Andrew Thompson Jul 27 '19 at 05:00
  • I am not sure why (and who has done) my answer is downvoted. Here is the solution to your current problem. Best practices apart, the solution works given your problem: https://github.com/fiveobjects/reference/blob/master/java/misc/src/main/java/org/openapex/samples/misc/swing/JComboBoxDynamicWidth57224561.java – fiveelements Jul 27 '19 at 05:21
  • @fiveelements did you want to add this comment to your answer ? I am not the down-voter but it may be due to the quality of the solution. "solution works" is essential but not enough. Up / down voting reflects the quality of the answer / question. In this case I think your proposed solution is not of high quality. – c0der Jul 27 '19 at 05:39
  • I tried the code from fiveelements and it throws a StackOverflowError. Although the Combo box is wide enough, it seems abnormally wide. What I am gathering from the answers is there isn't a direct way and need to work with the layout manager to sort of resize itself. – Unhandled Exception Jul 29 '19 at 11:10

2 Answers2

2

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

c0der
  • 18,467
  • 6
  • 33
  • 65
  • This worked nicely and was able to add a Label and Left justify and it still looks good. Will have to work with the Layout manager more as additional components are added to ensure it looks aesthetically pleasing. – Unhandled Exception Jul 29 '19 at 11:32
  • Glad it helped. If you post new questions leave me a message and I'll try yo help. – c0der Jul 29 '19 at 12:54
2

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);
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433