need JComboBox items with tabs or ability to line up
Hello,
I am working on a Swing application. It has a javax.swing.JComboBox in it. The items of the JComboBox are Strings with 3 pieces of information concatenated together, like City, State, ZIP. However, I need the Cities, States and ZIPs to line up.
I tried using tabs \t, but JComboBox filters them out. I have to use a proportion font, so I can write code to insert spaces to get them to line up. How can this be done?
Thanks
Mike
[465 byte] By [
mbrown36a] at [2007-10-2 7:57:21]

You can use a custom renderer to align the data in columns, however there is no easy way to know the maximum width of each column unless you loop throught the entire model and calculate the witdth of each column. This example shows two ways to create a custom renderer:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class ComboBoxMultiColumn extends JFrame
{
public ComboBoxMultiColumn()
{
String[] tabs =
{
"123456\tone",
"2\ta really really long description goes here",
"3\tthree",
"41\tfour"
};
JComboBox comboBox = new JComboBox( tabs );
comboBox.setRenderer( new TextAreaRenderer() );
//comboBox.setRenderer( new TextPaneRenderer() );
comboBox.setSelectedIndex(2);
getContentPane().add( comboBox );
JComponent renderer = (JComponent)comboBox.getRenderer();
System.out.println(renderer);
renderer.setBackground(Color.yellow);
}
public static void main(String[] args)
{
JFrame frame = new ComboBoxMultiColumn();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
/*
** Tabs are easier to use in a JTextArea, but not very flexible
*/
class TextAreaRenderer extends JTextArea implements ListCellRenderer
{
public TextAreaRenderer()
{
setBackground(Color.blue);
setTabSize(10);
}
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus)
{
System.out.println(getBackground());
setText(value.toString());
setBackground(isSelected ? list.getSelectionBackground() : null);
setForeground(isSelected ? list.getSelectionForeground() : null);
return this;
}
}
/*
** Tabs are harder to use in a JTextPane, but much more flexible
*/
class TextPaneRenderer extends JTextPane implements ListCellRenderer
{
private final int TAB_COLUMN = 10;
public TextPaneRenderer()
{
setMargin( new Insets(0, 0, 0, 0) );
FontMetrics fm = getFontMetrics( getFont() );
int width = fm.charWidth( 'w' ) * TAB_COLUMN;
TabStop[] tabs = new TabStop[1];
tabs[0] = new TabStop( width, TabStop.ALIGN_LEFT, TabStop.LEAD_NONE );
TabSet tabSet = new TabSet(tabs);
SimpleAttributeSet attributes = new SimpleAttributeSet();
StyleConstants.setTabSet(attributes, tabSet);
getStyledDocument().setParagraphAttributes(0, 0, attributes, false);
}
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus)
{
setText( value.toString() );
setBackground(isSelected ? list.getSelectionBackground() : null);
setForeground(isSelected ? list.getSelectionForeground() : null);
return this;
}
}
}
another way, multi-column combobox (but with a renderer)
import javax.swing.*;
import java.awt.*;
class Testing extends JFrame
{
JComboBox cbo = new JComboBox();
public Testing()
{
setLocation(400,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
cbo.setRenderer(new MyRenderer());
getContentPane().add(cbo);
cbo.addItem(new String[]{"Reno","Nevada","11111"});
cbo.addItem(new String[]{"Miami","Florida","22222"});
cbo.addItem(new String[]{"San Francisco","California","33333"});
cbo.addItem(new String[]{"Boston","Massachusetts","44444"});
pack();
}
public static void main(String[] args){new Testing().setVisible(true);}
}
class MyRenderer extends JPanel implements ListCellRenderer
{
JLabel[] lbl = new JLabel[3];
public MyRenderer()
{
setLayout(new GridLayout(0,3));
for(int x = 0; x < lbl.length; x++)
{
lbl[x] = new JLabel();
lbl[x].setOpaque(true);
add(lbl[x]);
}
}
public Component getListCellRendererComponent(JList list,Object value,
int index,boolean isSelected,boolean cellHasFocus)
{
for(int x = 0; x < lbl.length; x++)
{
lbl[x].setText((String)((String[])value)[x]);
if(isSelected)lbl[x].setBackground(Color.CYAN);
else lbl[x].setBackground(Color.WHITE);
}
return this;
}
}
> However, what html tag will line up the strings? Is there a tab html tag?
One way to do it is to use a table. Here is an example using the same data from my other example:
String[] htmlData =
{
"<html><table><tr><td width=50>123456</td><td width=100>one</td></tr></table></html>",
"<html><table><tr><td width=50>2</td><td width=150>long description here</td></tr></table></html>",
"<html><table><tr><td width=50>3</td><td width=100>three</td></tr></table></html>",
"<html><table><tr><td width=50>41</td><td width=100>four</td></tr></table></html>"
};
JComboBox comboBox3 = new JComboBox( htmlData );
getContentPane().add( comboBox3 );
but again the problem with these approaches is that you somehow need to calculate the width you want to use for each column. This would mean looping through your entire data to find the largest text string for each column and then calculate the column widths accordingly.
Michael's solution takes a simpler approach and makes the width of each column equal to the width of the largest text string in the model.
Only you know what your exact requirement is.