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.