I am experiencing a problem with this CheckBoxJList class (I found it posted somewhere, it is not mine), in which when there are no boxes checked, and then you check a box, you cannot click to uncheck it--you must first check another box. This is an annoying bug and I'm unsure how to fix it. Any help would be greatly appreciated!

import java.awt.BorderLayout;
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.Component;

import java.util.HashSet;
import java.util.Iterator;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.UIDefaults;
import javax.swing.UIManager;

import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

/**
 * JList that displays items as checkboxes.
 *
 * @see JList
 * @see ListSelectionListener
 */
public class CheckBoxJList extends JList
   implements ListSelectionListener
{

   static Color listForeground, listBackground, listSelectionForeground,
                listSelectionBackground;

   /**
    * Sets up look and feel.
    */
   static
   {
      UIDefaults uid = UIManager.getLookAndFeel().getDefaults();
      listForeground =  uid.getColor ("List.foreground");
      listBackground =  uid.getColor ("List.background");
      listSelectionForeground =  uid.getColor ("List.selectionForeground");
      listSelectionBackground =  uid.getColor ("List.selectionBackground");
   }

   HashSet<Integer> selectionCache;
   int toggleIndex;
   boolean toggleWasSelected;

   /**
    * Constructor.
    */
   public CheckBoxJList()
   {
      super();

      selectionCache = new HashSet<Integer>();
      toggleIndex = -1;

      setCellRenderer (new CheckBoxListCellRenderer());
      addListSelectionListener (this);
   }

   // ListSelectionListener implementation

   /**
    * Fired when a value changes.
    *
    * @param lse the ListSelectionEvent
    */
   public void valueChanged (ListSelectionEvent lse)
   {
      if (!lse.getValueIsAdjusting())
      {
          removeListSelectionListener (this);

          // remember everything selected as a result of this action
          HashSet<Integer> newSelections = new HashSet<Integer>();
          int size = getModel().getSize();
          for (int i = 0; i < size; i++)
          {
             if (getSelectionModel().isSelectedIndex(i))
             {
                 newSelections.add (new Integer(i));
             }
          }

          // turn on everything that was previously selected
          Iterator it = selectionCache.iterator();
          while (it.hasNext())
          {
             int index = ((Integer) it.next()).intValue();
              getSelectionModel().addSelectionInterval(index, index);
          }

          // add or remove the delta
          it = newSelections.iterator();
          while (it.hasNext())
          {
             Integer nextInt = (Integer) it.next();
             int index = nextInt.intValue();

             if (selectionCache.contains (nextInt))
             {
                getSelectionModel().removeSelectionInterval (index, index);
             }
             else
             {
                getSelectionModel().addSelectionInterval (index, index);
             }
          }

          // save selections for next time
          selectionCache.clear();
          for (int i = 0; i < size; i++)
          {
             if (getSelectionModel().isSelectedIndex(i))
             {
                selectionCache.add (new Integer(i));
             }
          }

          addListSelectionListener (this);
      }
   }


   /**
    * ListCellRenderer for our CheckBoxJList.
    *
    * @see JComponent
    * @see ListCellRenderer
    */
   class CheckBoxListCellRenderer extends JComponent
      implements ListCellRenderer
   {
      DefaultListCellRenderer defaultComp;
      JCheckBox checkbox;

      /**
       * Constructor.
       */
      public CheckBoxListCellRenderer()
      {
         setLayout (new BorderLayout());
         defaultComp = new DefaultListCellRenderer();
         checkbox = new JCheckBox();
         add (checkbox, BorderLayout.WEST);
         add (defaultComp, BorderLayout.CENTER);
      }


      /**
       * getListCellRendererComponent. 
       */
      public Component getListCellRendererComponent(JList list,
                                                    Object  value,
                                                    int index,
                                                    boolean isSelected,
                                                    boolean cellHasFocus)
      {
         defaultComp.getListCellRendererComponent (list, value, index,
                                                   isSelected, cellHasFocus);
         checkbox.setSelected (isSelected);
         Component[] comps = getComponents();

         for (int i = 0; i < comps.length; i++)
         {
            comps[i].setForeground (listForeground);
            comps[i].setBackground (listBackground);
         }

         return this;
      }
   }
}
This article has been dead for over six months. Start a new discussion instead.