I have a list of texts, some of which are large, and I need to display them in a JComboBox. The trouble is, the JComboBox displays all the items in a single line. Consider that the following items need to be displayed:
I am having the following code that displays a JComboBox in a JFrame:
package com.swayam.demo.combo; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.List; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; @SuppressWarnings("serial") public class LargeTextComboFrameWithCustomRenderer1 extends JFrame { private static final List LARGE_COMBO_BOX_ITEMS = Arrays .asList("JNLP is supposed to be the latest and greatest in the Java Applet world post 1.6 release! Personally, I was never a great fan of Applets. I have always felt that Applets are a pain in the wrong place. Inherently difficult and cumbersome to use and deploy. But some of these concerns have been addressed", "This is really tiny", "As shown above, the 4 progress bars start one after another after the start button is clicked. The following code is for the JPanel with the 4 progress bars: @SuppressWarnings("serial") public class ProgressPanel extends JPanel { private CountDownLatch startTrigger; private CountDownLatch endTrigger; private JProgressBar bar1; private JSpinner spinner1; private JProgressBar bar2; private"); public LargeTextComboFrameWithCustomRenderer1() { init(); } private void init() { getContentPane().setLayout(new BorderLayout()); JLabel title = new JLabel("Large Text Combo Demo: Custom ComboBox Renderer 1, With Max and Preferred Size Hints", JLabel.CENTER); getContentPane().add(title, BorderLayout.NORTH); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new FlowLayout()); JLabel comboLabel = new JLabel("Large Combo: ", JLabel.LEFT); mainPanel.add(comboLabel); mainPanel.add(getLargeComboBox()); getContentPane().add(mainPanel, BorderLayout.CENTER); setSize(new Dimension(600, 500)); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); } private JComboBox getLargeComboBox() { JComboBox largeComboBox = new JComboBox<>(); for (String item : LARGE_COMBO_BOX_ITEMS) { largeComboBox.addItem(item); } largeComboBox.setRenderer(new LargeComboBoxRenderer1(200)); largeComboBox.setPreferredSize(new Dimension(200, 30)); largeComboBox.setMaximumSize(new Dimension(200, 30)); return largeComboBox; } public static void main(String[] args) { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { LargeTextComboFrameWithCustomRenderer1 frame = new LargeTextComboFrameWithCustomRenderer1(); frame.setVisible(true); } }); } catch (InvocationTargetException | InterruptedException e) { e.printStackTrace(); } } }
It looks like this:
[caption id="attachment_506" align="aligncenter" width="300"] Large Text Combo Demo: Default ComboBox Renderer[/caption]
You can see it in action here:
Note that the JComboBox stretches depending on the width of the largest text as rendered on a single line.
We can do that by setting the PrefrerredSize and the MaximumSize of the JComboBox:
private JComboBox getLargeComboBox() { JComboBox largeComboBox = new JComboBox<>(); for (String item : LARGE_COMBO_BOX_ITEMS) { largeComboBox.addItem(item); } largeComboBox.setPreferredSize(new Dimension(200, 30)); largeComboBox.setMaximumSize(new Dimension(200, 30)); return largeComboBox; }
It looks like this:
[caption id="attachment_511" align="aligncenter" width="300"] Large Text Combo Demo: Default ComboBox Renderer, With Max and Preferred Size Hints[/caption]
You can see it in action here:
The problem with this approach is that the text is truncated.
We will have a custom renderer for JComboBox which wraps this text into nice HTML so that it is displayed in multi-lines.
private JComboBox getLargeComboBox() { JComboBox largeComboBox = new JComboBox<>(); for (String item : LARGE_COMBO_BOX_ITEMS) { largeComboBox.addItem(item); } largeComboBox.setRenderer(new LargeComboBoxRenderer1(200)); largeComboBox.setPreferredSize(new Dimension(200, 30)); largeComboBox.setMaximumSize(new Dimension(200, 30)); return largeComboBox; }
This is how the renderer looks like:
@SuppressWarnings("serial") public class LargeComboBoxRenderer1 extends JLabel implements ListCellRenderer{ private final int wordWrapWidth; public LargeComboBoxRenderer1(int wordWrapWidth) { this.wordWrapWidth = wordWrapWidth; } @Override public Component getListCellRendererComponent(JList extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) { if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } setFont(list.getFont()); setOpaque(true); setText(getHtmlWrappedText(value)); return this; } private String getHtmlWrappedText(String text) { StringBuilder sb = new StringBuilder(300); sb.append(""); sb.append(" "); sb.append(text); sb.append("
"); sb.append(""); return sb.toString(); } private String getParagraphStyle() { StringBuilder sb = new StringBuilder(100); sb.append("word-wrap: break-word;"); sb.append("width: "); sb.append(wordWrapWidth); sb.append("px;"); return sb.toString(); } }
And this is how it looks like now:
[caption id="attachment_514" align="aligncenter" width="300"] Large Text Combo Demo: Custom ComboBox Renderer 1, With Max and Preferred Size Hints[/caption]
You can see it in action here:
As shown above, this does not look good when the pop-up is not there in the JComboBox.
We need to make a distinction between when there is a pop-out and when there is not. This is done by the int index parameter in the ListCellRenderer::getListCellRendererComponent(JList extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) method. When index == -1, it indicates that the item is not popped out. This is the code:
@Override public Component getListCellRendererComponent(JList extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) { if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } setFont(list.getFont()); setOpaque(true); // index is -1 when there is no pop-up if (index == -1) { setText(value); } else { setText(getHtmlWrappedText(value)); } return this; }
This is how it looks now:
[caption id="attachment_515" align="aligncenter" width="300"] Large Text Combo Demo: Custom ComboBox Renderer 2, With Max and Preferred Size Hints[/caption]
You can see it in action here:
The sources can be found https://github.com/paawak/blog/tree/master/code/Demo.