JComboBox comboBox = new JComboBox(); comboBox.setRenderer(new MyComboBoxRenderer()); comboBox.setEditor(new MyComboBoxEditor());The renderer class must implement javax.swing.ListCellRenderer interface. It is used to render component’s GUI in normal state. For example, the following class, MyComboBoxRenderer – implements a simple renderer which is a JLabel:
package net.codejava.swing.combobox; import java.awt.Color; import java.awt.Component; import java.awt.Font; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; public class MyComboBoxRenderer extends JLabel implements ListCellRenderer { public MyComboBoxRenderer() { setOpaque(true); setFont(new Font("Arial", Font.BOLD | Font.ITALIC, 14)); setBackground(Color.BLUE); setForeground(Color.YELLOW); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setText(value.toString()); return this; } }As we can see, the renderer class has to override the method getListCellRendererComponent() which is defined by the interface ListCellRenderer. The method must return a subclass of Component class which is rendered as list item in the combo box. In the example above, it returns an instance of JLabel class, and results in a combo box looks like following:
package net.codejava.swing.combobox; import java.awt.Color; import java.awt.Component; import java.awt.FlowLayout; import java.awt.Font; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.plaf.basic.BasicComboBoxEditor; public class MyComboBoxEditor extends BasicComboBoxEditor { private JLabel label = new JLabel(); private JPanel panel = new JPanel(); private Object selectedItem; public MyComboBoxEditor() { label.setOpaque(false); label.setFont(new Font("Arial", Font.BOLD, 14)); label.setForeground(Color.BLACK); panel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2)); panel.add(label); panel.setBackground(Color.GREEN); } public Component getEditorComponent() { return this.panel; } public Object getItem() { return "[" + this.selectedItem.toString() + "]"; } public void setItem(Object item) { this.selectedItem = item; label.setText(item.toString()); } }This editor class extends the BasicComboBoxEditor class and overrides the following three methods:
comboBox.setEditable(true);
package net.codejava.swing.combobox; import java.awt.Color; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.ListCellRenderer; /** * Customer renderer for JComboBox * @author www.codejava.net * */ public class CountryItemRenderer extends JPanel implements ListCellRenderer { private JLabel labelItem = new JLabel(); public CountryItemRenderer() { setLayout(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.HORIZONTAL; constraints.weightx = 1.0; constraints.insets = new Insets(2, 2, 2, 2); labelItem.setOpaque(true); labelItem.setHorizontalAlignment(JLabel.LEFT); add(labelItem, constraints); setBackground(Color.LIGHT_GRAY); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { String[] countryItem = (String[]) value; // set country name labelItem.setText(countryItem[0]); // set country flag labelItem.setIcon(new ImageIcon(countryItem[1])); if (isSelected) { labelItem.setBackground(Color.BLUE); labelItem.setForeground(Color.YELLOW); } else { labelItem.setForeground(Color.BLACK); labelItem.setBackground(Color.LIGHT_GRAY); } return this; } }As we can see, a JLabel is used for displaying an icon of country flag and country name. Its background and foreground are set differently for selected state and non-selected state.
package net.codejava.swing.combobox; import java.awt.Color; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.plaf.basic.BasicComboBoxEditor; /** * Editor for JComboBox * @author wwww.codejava.net * */ public class CountryItemEditor extends BasicComboBoxEditor { private JPanel panel = new JPanel(); private JLabel labelItem = new JLabel(); private String selectedValue; public CountryItemEditor() { panel.setLayout(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.HORIZONTAL; constraints.weightx = 1.0; constraints.insets = new Insets(2, 5, 2, 2); labelItem.setOpaque(false); labelItem.setHorizontalAlignment(JLabel.LEFT); labelItem.setForeground(Color.WHITE); panel.add(labelItem, constraints); panel.setBackground(Color.BLUE); } public Component getEditorComponent() { return this.panel; } public Object getItem() { return this.selectedValue; } public void setItem(Object item) { if (item == null) { return; } String[] countryItem = (String[]) item; selectedValue = countryItem[0]; labelItem.setText(selectedValue); labelItem.setIcon(new ImageIcon(countryItem[1])); } }The editor also uses a JLabel to display the selected country item but with different background and foreground than the renderer. It returns country name as the selected object from getItem() method.
package net.codejava.swing.combobox; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; /** * A custom combo box with its own renderer and editor. * @author wwww.codejava.net * */ public class CountryComboBox extends JComboBox { private DefaultComboBoxModel model; public CountryComboBox() { model = new DefaultComboBoxModel(); setModel(model); setRenderer(new CountryItemRenderer()); setEditor(new CountryItemEditor()); } /** * Add an array items to this combo box. * Each item is an array of two String elements: * - first element is country name. * - second element is path of an image file for country flag. * @param items */ public void addItems(String[][] items) { for (String[] anItem : items) { model.addElement(anItem); } } }
This combo box uses the renderer class and editor class shown above. In addition, it uses a DefaultComboBoxModel to hold items. The addItems(String[][]) method is for adding an array of items to the drop down list. Each item is also an array in which the first item is country name and the second is path of an image file represents country flag.
package net.codejava.swing.combobox; import java.awt.Dimension; import java.awt.FlowLayout; import javax.swing.JFrame; import javax.swing.SwingUtilities; public class CustomComboBoxTester extends JFrame { public CustomComboBoxTester() { super("Demo program for custom combobox"); setLayout(new FlowLayout()); CountryComboBox customCombobox = new CountryComboBox(); customCombobox.setPreferredSize(new Dimension(120, 30)); customCombobox.setEditable(true); customCombobox.addItems(countryList); add(customCombobox); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 100); setLocationRelativeTo(null); // center on screen } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new CustomComboBoxTester().setVisible(true); } }); } private String[][] countryList = {{"USA", "us.png"}, {"India", "in.png"}, {"Vietnam", "vn.png"}, {"Germany", "de.png"}, {"Canada", "ca.png"}, {"Japan", "jp.png"}, {"Great Britain", "gb.png"}, {"France", "fr.png"}}; }The demo program is a JFrame window that contains only one combo box and declares a countryList array which holds a list of items added to the combo box. When running, it looks like the following screenshot:You can download the zip file for both Java source files and flag images.