Creating a JComboBox that doesn’t close when I click one of its JCheckBox items

Main.java:

import javax.swing.*;
import java.awt.*;
import java.util.*;
 
public class Main extends JFrame
{
   public Main() {
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
      getContentPane().setLayout(new FlowLayout());
       
      Vector v = new Vector();
      v.add("Europe");
      v.add(new JCheckBox("Brussels", false));
      v.add(new JCheckBox("Paris", false));
      v.add(new JCheckBox("London", false));
      v.add("United States");
      v.add(new JCheckBox("New York", false));
      v.add(new JCheckBox("Detroit", false));
      v.add(new JCheckBox("San Francisco", false));
 
      getContentPane().add(new JComboCheckBox(v));
   }
    
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(300, 300);
      main.setVisible(true);
   }
}

JComboCheckBox.java:

import javax.swing.*;
import java.awt.event.*;
 
import javax.swing.plaf.ComboBoxUI;
import javax.swing.plaf.basic.*;
import javax.swing.plaf.metal.MetalComboBoxUI;
 
import com.sun.java.swing.plaf.motif.MotifComboBoxUI;
import com.sun.java.swing.plaf.windows.WindowsComboBoxUI;
 
import java.awt.*;
import java.util.*;
 
public class JComboCheckBox extends JComboBox 
{
   public JComboCheckBox() { 
      init(); 
   }
    
   public JComboCheckBox(JCheckBox[] items) { 
      super(items); 
      init(); 
   }
    
   public JComboCheckBox(Vector items) { 
      super(items); 
      init(); 
   }
    
   public JComboCheckBox(ComboBoxModel aModel) { 
      super(aModel); 
      init(); 
   }
    
   public void updateUI() {
      ComboBoxUI cui = (ComboBoxUI) UIManager.getUI(this);
      if (cui instanceof MetalComboBoxUI) {
         cui = new MetalNoCloseComboBoxUI();
      } else if (cui instanceof MotifComboBoxUI) {
         cui = new MotifNoCloseComboBoxUI();       
      } else if (cui instanceof WindowsComboBoxUI) {
         cui = new WindowsNoCloseComboBoxUI();
      }
       
      setUI(cui);
   }
    
   class MetalNoCloseComboBoxUI extends MetalComboBoxUI {
      protected ComboPopup createPopup() {
         return new NoCloseBasicComboPopup(comboBox);
      }
   }
 
   class WindowsNoCloseComboBoxUI extends WindowsComboBoxUI {
      protected ComboPopup createPopup() {
         return new NoCloseBasicComboPopup(comboBox);
      }
   }
 
   class MotifNoCloseComboBoxUI extends MotifComboBoxUI {
      protected ComboPopup createPopup() {
         return new NoCloseBasicComboPopup(comboBox);
      }
   }
    
   private void init() {
      setRenderer(new ComboBoxRenderer());
      addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) { 
            itemSelected(); 
         }
      });
   }
 
   private void itemSelected() {
      if (getSelectedItem() instanceof JCheckBox) {
         JCheckBox jcb = (JCheckBox)getSelectedItem();
         jcb.setSelected(!jcb.isSelected());
         repaint();
      }
   }
 
   class ComboBoxRenderer implements ListCellRenderer {
      private JLabel label;
      
      public ComboBoxRenderer() { 
         setOpaque(true); 
      }
      
      public Component getListCellRendererComponent(JList list, Object value, int index, 
                                                    boolean isSelected, boolean cellHasFocus) {
         if (value instanceof JCheckBox) {
            list.repaint();
         }
         if (value instanceof Component) {
            Component c = (Component)value;
            if (isSelected) {
               c.setBackground(list.getSelectionBackground());
               c.setForeground(list.getSelectionForeground());
            } else {
               c.setBackground(list.getBackground());
               c.setForeground(list.getForeground());
            }
            
            return c;
         } else {
            if (label==null) {
               label = new JLabel(value.toString());
            }
            else {
               label.setText(value.toString()); 
            }
            
            return label;
         }
      }
   }
 
   class NoCloseBasicComboPopup extends BasicComboPopup
   {
      public NoCloseBasicComboPopup(JComboBox combo) {
         super(combo);         
      }
   
      protected MouseListener createListMouseListener() {
         return new ListMouseHandler();
      }
   
      protected class ListMouseHandler extends MouseAdapter {
         public void mousePressed(MouseEvent e) {
         }
      
         public void mouseReleased(MouseEvent anEvent) {
            comboBox.setSelectedIndex(list.getSelectedIndex());
            Object o = list.getSelectedValue();
            if (! (o instanceof JCheckBox)) {
               hide();
            }
         }
      }   
   }   
}

Showing a different tooltip for every item in a JComboBox

Modify the behavior of the ListRenderer such that it includes the currently selected JComboBox item in determining the tooltip text. Here’s an example:

import javax.swing.plaf.basic.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
    
public class Main extends JFrame
{ 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
      
      final JComboBox combobox = new JComboBox(new String[] { "Item 1", "Item 2", "Item 3" });
 
      getContentPane().add(combobox);
 
      combobox.setRenderer(new BasicComboBoxRenderer() {
         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 
            if (isSelected) { 
               setBackground(list.getSelectionBackground()); 
               setForeground(list.getSelectionForeground()); 
               if (index > -1) {
                  list.setToolTipText("Tooltip #" + new Integer(index).toString()); 
               }
            }
            else { 
               setBackground(list.getBackground()); 
               setForeground(list.getForeground()); 
            } 
            setFont(list.getFont()); 
            setText((value == null) ? "" : value.toString()); 
 
            return this; 
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });      
   
      setSize(new Dimension(200, 200));
   } 
 
   public static void main(String[] args) throws Exception {
      Main main = new Main();
      main.setVisible(true);
   }
}

Displaying animated GIFs in a JList

Try this example with the following two images:

import javax.swing.border.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
 
public class Main {
   public static void main(String args[]) {
      JFrame frame = new JFrame("JList Background Demonstration");
 
      JList list = new JList();
 
      String [] imageIcon = new String[] {
         "female.gif", "male.gif"
      };
 
      // create model
      Vector v = new Vector();
      for (int i=0; i<10; i++) {
         ImageIcon ii = new ImageIcon(imageIcon[i % 2]);
         ii.setImageObserver(new AnimatedObserver(list, i));
         v.addElement(ii);
      }
 
      list.setListData(v);
  
      frame.getContentPane().add(BorderLayout.CENTER, list); //new JScrollPane(list));
      frame.setDefaultCloseOperation(3);
      frame.pack();
      frame.setVisible(true);
   }
}
 
class AnimatedObserver implements ImageObserver 
{ 
   JList list; 
   int index; 
 
   public AnimatedObserver(JList list, int index) { 
      this.list = list; 
      this.index = index; 
   }  
 
   public boolean imageUpdate (Image img, int infoflags, int x, int y, int width, int height) {
      if ((infoflags & (FRAMEBITS|ALLBITS)) != 0) { 
         Rectangle rect = list.getCellBounds(index, index); 
         list.repaint(rect); 
      } 
 
      return (infoflags & (ALLBITS|ABORT)) == 0; 
   }
} 

Disabling some of the elements in a JComboBox

We wrap a JComboBox element in our ConditionalItem object that includes a boolean variable isEnabled. Now, in order to change the default behavior of the JComboBox, we need to handle two things: first blur out the elements that are disabled using our own renderer and second ensure the disabled elements cannot be selected by adding a ActionListener that selects the old selected element in case a disabled item was selected.

Main.java:

import javax.swing.plaf.basic.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
    
public class Main extends JFrame
{ 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
      
      final JComboBox combobox = 
         new JComboBox(
            new ConditionalItem[] { 
               new ConditionalItem("Item 1"),
               new ConditionalItem("Item 2", false),
               new ConditionalItem("Item 3", false),
               new ConditionalItem("Item 4")
            }
         );
 
      getContentPane().add(combobox);
      combobox.setRenderer(new ConditionalComboBoxRenderer());
      combobox.addActionListener(new ConditionalComboBoxListener(combobox));
  
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });      
   
      setSize(new Dimension(200, 200));
   } 
 
   public static void main(String[] args) throws Exception {
      Main main = new Main();
      main.setVisible(true);
   }
}
 
class ConditionalComboBoxRenderer extends BasicComboBoxRenderer implements ListCellRenderer
{
   public Component getListCellRendererComponent(JList list, 
           Object value, int index, boolean isSelected, boolean cellHasFocus) {
      if (isSelected) {
        setBackground(list.getSelectionBackground());
        setForeground(list.getSelectionForeground());
      } else {
        setBackground(list.getBackground());
        setForeground(list.getForeground());
      } 
 
      if (!((Conditionable) value).isEnabled()) {
        setBackground(list.getBackground());
        setForeground(UIManager.getColor("Label.disabledForeground"));
      }
 
      setFont(list.getFont());
      setText((value == null) ? "" : value.toString());
      return this;
   }  
}
 
class ConditionalComboBoxListener implements ActionListener {
   JComboBox combobox;
   Object oldItem;
    
   ConditionalComboBoxListener(JComboBox combobox) {
      this.combobox = combobox;
      combobox.setSelectedIndex(0);
      oldItem = combobox.getSelectedItem();
   }
    
   public void actionPerformed(ActionEvent e) {
      Object selectedItem = combobox.getSelectedItem();
      if (!((Conditionable) selectedItem).isEnabled()) {
         combobox.setSelectedItem(oldItem);
      } else {
         oldItem = selectedItem;
      }
   }
}
 
class ConditionalItem implements Conditionable {
   Object  object;
   boolean isEnabled;
    
   ConditionalItem(Object object, boolean isEnabled) {
      this.object = object;
      this.isEnabled = isEnabled;
   }
    
   ConditionalItem(Object object) {
     this(object, true);
   }
   
   public boolean isEnabled() {
      return isEnabled;
   }
    
   public void setEnabled(boolean isEnabled) {
      this.isEnabled = isEnabled;
   }
    
   public String toString() {
      return object.toString();
   }
}
 
interface Conditionable {
   public boolean isEnabled();
   public void setEnabled(boolean enabled);
   public String toString();
}

Creating a background for a JList

Here’s an example:

import javax.swing.*;
import java.util.*;
import java.awt.*;
 
public class Main {
   public static void main(String args[]) {
      JFrame frame = new JFrame("JList Background Demonstration");
      final ImageIcon imageIcon = new ImageIcon("bg1.jpg");
 
      Vector v = new Vector();
      for (int i=0; i<10; i++) {
         v.addElement("Item #" + i);
      }
 
      JList list = new JList(v) {
         Image image = imageIcon.getImage();
         { 
            setOpaque(false);
         }
         public void paintComponent(Graphics g) {
            g.drawImage(image, 0, 0, this);
            super.paintComponent(g);
         }
      };
      list.setCellRenderer(new OpaqueCellRenderer());
      
      frame.getContentPane().add(BorderLayout.CENTER, list); //new JScrollPane(list));
      frame.setDefaultCloseOperation(3);
      frame.pack();
      frame.setVisible(true);
   }
}
 
class OpaqueCellRenderer extends DefaultListCellRenderer implements ListCellRenderer {
   public Component getListCellRendererComponent(
      JList list,
      Object value,            // value to display
      int index,               // cell index
      boolean isSelected,      // is the cell selected
      boolean cellHasFocus)    // the list and the cell have the focus
   {
      Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 
      if (isSelected) {
         ((JComponent) c).setOpaque(true);
         c.setBackground(list.getSelectionBackground());
         c.setForeground(list.getSelectionForeground());
      }
      else {
         ((JComponent) c).setOpaque(false);
         c.setBackground(list.getBackground());
         c.setForeground(list.getForeground());
      }
 
      return c;
   }
}

bg1.jpg:

Creating a JComboBox with a divider separator line

Create a cellRenderer that does not convert the element to a String in order to show it, but instead checks whether it is a JSeparator and returns that component instead. Then make sure the JSeparator itself cannot be selected by adding an ActionListener to the combobox.

Main.java:

import javax.swing.plaf.basic.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
    
public class Main extends JFrame
{ 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
      
      final JComboBox combobox = 
         new JComboBox(new Object[] {
               "Item 1",
               "Item 2",
               "Item 3",
               new JSeparator(JSeparator.HORIZONTAL),
               "Item 4",
               "Item 5"
            }
         );
 
      getContentPane().add(combobox);
      combobox.setRenderer(new SeparatorComboBoxRenderer());
      combobox.addActionListener(new SeparatorComboBoxListener(combobox));
  
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });      
   
      setSize(new Dimension(200, 200));
   } 
 
   public static void main(String[] args) throws Exception {
      Main main = new Main();
      main.setVisible(true);
   }
}
 
class SeparatorComboBoxRenderer extends BasicComboBoxRenderer implements ListCellRenderer
{
   public SeparatorComboBoxRenderer() {
      super();
   }
   
   public Component getListCellRendererComponent( JList list, 
           Object 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());
      if (value instanceof Icon) {
         setIcon((Icon)value);
      }
      if (value instanceof JSeparator) {
         return (Component) value;
      }
      else {
         setText((value == null) ? "" : value.toString());
      }
 
      return this;
  }  
}
 
class SeparatorComboBoxListener implements ActionListener {
   JComboBox combobox;
   Object oldItem;
    
   SeparatorComboBoxListener(JComboBox combobox) {
      this.combobox = combobox;
      combobox.setSelectedIndex(0);
      oldItem = combobox.getSelectedItem();
   }
     
   public void actionPerformed(ActionEvent e) {
      Object selectedItem = combobox.getSelectedItem();
      if (selectedItem instanceof JSeparator) {
         combobox.setSelectedItem(oldItem);
      } else {
         oldItem = selectedItem;
      }
   }
}

Adding a border to each element in a JList

Change the default cell renderer as in following example:

import javax.swing.border.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
 
public class Main {
   public static void main(String args[]) {
      JFrame frame = new JFrame("JList Background Demonstration");
      final ImageIcon imageIcon = new ImageIcon("bg1.jpg");
 
      Vector v = new Vector();
      for (int i=0; i<10; i++) {
         v.addElement("Item #" + i);
      }
 
      JList list = new JList(v);
 
      list.setCellRenderer(new BorderCellRenderer(new BevelBorder(BevelBorder.LOWERED)));
//      list.setCellRenderer(new BorderCellRenderer(new BevelBorder(BevelBorder.RAISED)));
//      list.setCellRenderer(new BorderCellRenderer(new EtchedBorder(EtchedBorder.LOWERED)));
//      list.setCellRenderer(new BorderCellRenderer(new EtchedBorder(EtchedBorder.RAISED)));
      
      frame.getContentPane().add(BorderLayout.CENTER, list); //new JScrollPane(list));
      frame.setDefaultCloseOperation(3);
      frame.pack();
      frame.setVisible(true);
   }
}
 
class BorderCellRenderer extends DefaultListCellRenderer implements ListCellRenderer {
   AbstractBorder border;
 
   public BorderCellRenderer(AbstractBorder border) {
      this.border = border;
   }
 
   public Component getListCellRendererComponent(
      JList list,
      Object value,            // value to display
      int index,               // cell index
      boolean isSelected,      // is the cell selected
      boolean cellHasFocus)    // the list and the cell have the focus
   {
      Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 
      ((JComponent) c).setBorder(border);
 
      return c;
   }
}

Removing all the elements of a JList

The quickest way to find an answer to these kind of questions is to look at the API. You can call either removeAllElements or clear on the list model. clear is preferred.

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
  
public class Main extends JFrame {
 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
 
      final DefaultListModel listModel = new DefaultListModel();   
 
      // populate listmodel
      for (int i=0; i&lt;5; i++) {
         listModel.addElement(&quot;list item #&quot; + i);
      }
 
      final JList list = new JList(listModel); 
 
      getContentPane().add(new JScrollPane(list));    
      JButton removeAllButton = new JButton(&quot;Remove all elements&quot;);
      removeAllButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
 
            listModel.clear();
 
         }
      });
      getContentPane().add(removeAllButton);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      pack();
   }
   
   public static void main(String[] args) {
      (new Main()).show();
   }
}

Showing a popup-menu when a user right-clicks on an element in a JList

This example creates a JList and shows a popupmenu only when the user clicked on the selected item.
Main.java:

import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
  
public class Main extends JFrame {
 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
 
      final DefaultListModel listModel = new DefaultListModel();   
 
      // populate listmodel
      for (int i=0; i<5; i++) {
         listModel.addElement("list item #" + i);
      }
 
      final JList list = new JList(listModel); 
      getContentPane().add(new JScrollPane(list));    
 
      final JPopupMenu popupMenu = new JPopupMenu();
      popupMenu.add(new JMenuItem("PopupItem 1"));
      popupMenu.add(new JMenuItem("PopupItem 2"));
      popupMenu.add(new JPopupMenu.Separator());
      popupMenu.add(new JMenuItem("PopupItem 3"));
 
      list.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent me) {
            if (SwingUtilities.isRightMouseButton(me)    // if right mouse button clicked
                  && !list.isSelectionEmpty()            // and list selection is not empty
                  && list.locationToIndex(me.getPoint()) // and clicked point is
                     == list.getSelectedIndex()) {       //   inside selected item bounds
               popupMenu.show(list, me.getX(), me.getY());
            }
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      pack();
   }
   
   public static void main(String[] args) {
      (new Main()).show();
   }
}

Getting the selected item(s) from a JList

There are several functions to determine the selected value(s) of a JList:

  • getSelectedIndex() returns the first selected index
  • getSelectedIndices() returns all of the selected indices
  • getSelectedValue() returns the first selected value
  • getSelectedValues() returns all of the selected values

Here’s an example:

import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
  
public class Main extends JFrame {
 
   public Main() {
      getContentPane().setLayout(new FlowLayout());
 
      Vector v = new Vector();
      for (int i=0; i<20; i++) {
         v.addElement("Item #" + i);
      }
 
      final JList list = new JList(v);
      getContentPane().add(new JScrollPane(list));
      JButton button = new JButton("Show selected items");
      getContentPane().add(button);
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) { 
            System.out.println("Selected values:");
            Object[] oarr = list.getSelectedValues();
            for (int i=0; i<oarr.length; i++) {
               System.out.println(oarr[i]);
            }
 
            System.out.println("Selected indices:");
            int[] iarr = list.getSelectedIndices();
            for (int i=0; i<iarr.length; i++) {
               System.out.println(iarr[i]);
            }
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent event) {
            System.exit(0);   
         }      
      });
 
      setSize(200, 250);
   }
   
   public static void main(String[] args) {
      (new Main()).show();
   }
}