I have a ComboBox
in which I have 8 Items out of which I want to display all but on a certain condition, the user should only be able to select the first two of the
To solve @Samsotha 's code "problem" where disabled items are still selectable, I found and adapted a code which works fine for this purpose. Here is a working example on how you can call it and use it in similar way to a JComboBox:
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
/**
* Creates a util class to generate a JComboBox with enabled/disabled items.
* Strongly adapted from original post of Joris Van den Bogaert at http://esus.com/disabling-some-of-the-elements-in-a-jcombobox/
*/
@SuppressWarnings({ "unchecked" })
public class MyComboBox extends JComboBox<Object> {
private static final long serialVersionUID = 6975854742812751380L;
/**************************************************
* FOR TESTING:
*/
public static void main(String[] args) throws Exception {
// Way 1: load an array
ConditionalItem[] arr = new ConditionalItem[] {
new ConditionalItem("Item 0", false),
new ConditionalItem("Item 1", false),
new ConditionalItem("Item 2"),
new ConditionalItem("Item 3", false),
new ConditionalItem("Item 4", true)
};
MyComboBox combo = new MyComboBox(arr);
// // Way 2: load oned by one (allows run-time modification)
// MyComboBox combo = new MyComboBox();
// combo.addItem("sss", false);
// combo.addItem("ffffd", true);
// combo.addItem("eeee");
// Way 3: initial load and oned by one on run-time
combo.addItem("Item 5");
combo.addItem("Item 6", false);
combo.addItem("Item 7", true);
JPanel panel = new JPanel(new FlowLayout());
panel.add(new JLabel("Test:"));
panel.add(combo);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
Thread.sleep(2*1000);
combo.setItem("Item 2", false);
Thread.sleep(2*1000);
combo.setItem("Item 8", false);
}
/**************************************************
* CONSTRUCTORS:
*/
ActionListener listener;
public MyComboBox() {
this.setRenderer(new ConditionalComboBoxRenderer());
}
public MyComboBox(ConditionalItem[] arr) {
for(ConditionalItem ci : arr) {
this.addItem(ci);
}
this.setRenderer(new ConditionalComboBoxRenderer());
listener = new ConditionalComboBoxListener(this);
this.addActionListener(listener);
}
public void addItem(String str) {
addItem(new ConditionalItem(str, true));
}
public void addItem(String str, boolean bool) {
addItem(new ConditionalItem(str, bool));
}
public void addItem(Component ci) {
this.add(ci);
this.setRenderer(new ConditionalComboBoxRenderer());
this.addActionListener(new ConditionalComboBoxListener(this));
}
/** if combobox contains "str", sets its state to "bool";
* if it's not yet an item, ignores it;
* the method also re-sets the selected item to the first one
* shown in the list as "true", and disables the listeners in this
* process to avoid firing an action when reorganizing the list.
*/
public void setItem(String str, boolean bool) {
int n = this.getItemCount();
for (int i=0; i<n; i++) {
if(this.getItemAt(i).toString().equals(str)) {
this.removeActionListener(listener);
this.removeItemAt(i);
this.insertItemAt(new ConditionalItem(str, bool), i);
int k = this.firstTrueItem();
if(k<0) k=0; // default index 0 if no true item is shown as true
this.setSelectedIndex(k);
this.addActionListener(listener);
return;
}
}
System.err.println("Warning: item "+ str +" is not a member of this combobox: ignoring it...");
}
public Object[] getItems() {
int n = this.getItemCount();
Object[] obj = new Object[n];
for (int i=0; i<n; i++) {
obj[i] = this.getItemAt(i);
}
return obj;
}
/** @return -1 if no item is true */
int firstTrueItem() {
int i = 0;
for(Object obj : this.getItems()) {
if(((ConditionalItem) obj).isEnabled()) return i;
i++;
}
return -1;
}
}
@SuppressWarnings("rawtypes")
class ConditionalComboBoxRenderer extends BasicComboBoxRenderer implements ListCellRenderer {
private static final long serialVersionUID = 8538079002036282063L;
@Override
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());
}
try {
if (value != null && !((ConditionalItem) value).isEnabled()) {
setBackground(list.getBackground());
setForeground(UIManager.getColor("Label.disabledForeground"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
setFont(list.getFont());
setText((value == null) ? "" : value.toString());
}
return this;
}
}
class ConditionalComboBoxListener implements ActionListener {
MyComboBox combobox;
Object oldItem;
ConditionalComboBoxListener(MyComboBox combobox) {
this.combobox = combobox;
combobox.setSelectedIndex(combobox.firstTrueItem());
oldItem = combobox.getSelectedItem();
}
public void actionPerformed(ActionEvent e) {
Object selectedItem = combobox.getSelectedItem();
if (!((ConditionalItem) selectedItem).isEnabled()) {
combobox.setSelectedItem(oldItem);
System.err.println(selectedItem.toString());
} else {
oldItem = selectedItem;
System.out.println(oldItem.toString());
}
}
}
class ConditionalItem {
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;
}
@Override
public String toString() {
return object.toString();
}
}
This is going to require some hand coding. The GUI Builder is not going to help you out here.
You can implement your own BasicComboBoxRenderer
, where you pass to it a ListSelectionModel
. Based on the model you pass to it, only the selected interval will get rendered with the standard renderer. The remaining indices will get rendered in a disable fashion, by change the foreground color and it's selection background.
Note: this is only going to affect the rendering of the items, not the actual selection events
import java.awt.Color;
import java.awt.Component;
import javax.swing.JList;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
public class EnabledComboBoxRenderer extends BasicComboBoxRenderer {
private ListSelectionModel enabledItems;
private Color disabledColor = Color.lightGray;
public EnabledComboBoxRenderer() {}
public EnabledComboBoxRenderer(ListSelectionModel enabled) {
super();
this.enabledItems = enabled;
}
public void setEnabledItems(ListSelectionModel enabled) {
this.enabledItems = enabled;
}
public void setDisabledColor(Color disabledColor) {
this.disabledColor = disabledColor;
}
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
if (!enabledItems.isSelectedIndex(index)) {// not enabled
if (isSelected) {
c.setBackground(UIManager.getColor("ComboBox.background"));
} else {
c.setBackground(super.getBackground());
}
c.setForeground(disabledColor);
} else {
c.setBackground(super.getBackground());
c.setForeground(super.getForeground());
}
return c;
}
}
You can use two separate listeners. One for when the items are enabled and one for when the items are disabled. When the items are enabled, you can 1. Change the selection model 2. Add the enabled listener 3. Remove the disabled listener
private class EnabledListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(((JComboBox) e.getSource()).getSelectedItem());
}
}
private class DisabledListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (((JComboBox) e.getSource()).getSelectedIndex() != SELECTION_INTERVAL[0]
&& ((JComboBox) e.getSource()).getSelectedIndex() != SELECTION_INTERVAL[1]) {
JOptionPane.showMessageDialog(null,
"You can't Select that Item", "ERROR",
JOptionPane.ERROR_MESSAGE);
} else {
System.out.println(((JComboBox) e.getSource())
.getSelectedItem());
}
}
}
protected void enableItemsInComboBox() {
comboBox.removeActionListener(disabledListener);
comboBox.addActionListener(enabledListener);
model.setSelectionInterval(SELECTION_INTERVAL[0], comboBox.getModel()
.getSize() - 1);
}
And vice versa
protected void disableItemsInComboBox() {
comboBox.removeActionListener(enabledListener);
comboBox.addActionListener(disabledListener);
model.setSelectionInterval(SELECTION_INTERVAL[0], SELECTION_INTERVAL[1]);
}
Here's a complete running example, using EnabledComboBoxRenderer
from above
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class ComboBoxDisabledItemsDemo {
private static final int[] SELECTION_INTERVAL = { 0, 1 };
private JComboBox comboBox;
private JCheckBox disableCheckBox;
private DefaultListSelectionModel model = new DefaultListSelectionModel();
private EnabledComboBoxRenderer enableRenderer = new EnabledComboBoxRenderer();
private EnabledListener enabledListener = new EnabledListener();
private DisabledListener disabledListener = new DisabledListener();
public ComboBoxDisabledItemsDemo() {
comboBox = createComboBox();
disableCheckBox = createCheckBox();
disableCheckBox.setSelected(true); // this adds the action listener to
// the
// to the combo box
JFrame frame = new JFrame("Disabled Combo Box Items");
frame.setLayout(new GridBagLayout());
frame.add(comboBox);
frame.add(disableCheckBox);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JComboBox createComboBox() {
String[] list = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5",
"Item 6", "Item 7" };
JComboBox cbox = new JComboBox(list);
model.addSelectionInterval(SELECTION_INTERVAL[0], SELECTION_INTERVAL[1]);
enableRenderer.setEnabledItems(model);
cbox.setRenderer(enableRenderer);
return cbox;
}
private class EnabledListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(((JComboBox) e.getSource()).getSelectedItem());
}
}
private class DisabledListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (((JComboBox) e.getSource()).getSelectedIndex() != SELECTION_INTERVAL[0]
&& ((JComboBox) e.getSource()).getSelectedIndex() != SELECTION_INTERVAL[1]) {
JOptionPane.showMessageDialog(null,
"You can't Select that Item", "ERROR",
JOptionPane.ERROR_MESSAGE);
} else {
System.out.println(((JComboBox) e.getSource())
.getSelectedItem());
}
}
}
protected void disableItemsInComboBox() {
comboBox.removeActionListener(enabledListener);
comboBox.addActionListener(disabledListener);
model.setSelectionInterval(SELECTION_INTERVAL[0], SELECTION_INTERVAL[1]);
}
protected void enableItemsInComboBox() {
comboBox.removeActionListener(disabledListener);
comboBox.addActionListener(enabledListener);
model.setSelectionInterval(SELECTION_INTERVAL[0], comboBox.getModel()
.getSize() - 1);
}
private JCheckBox createCheckBox() {
JCheckBox checkBox = new JCheckBox("diabled");
checkBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
disableItemsInComboBox();
} else if (e.getStateChange() == ItemEvent.DESELECTED) {
enableItemsInComboBox();
}
}
});
return checkBox;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ComboBoxDisabledItemsDemo();
}
});
}
}