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;
}
}
}