简体   繁体   中英

How to disable certain items in a JComboBox

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 them, so I have programmed that if the condition is true and the user chooses any other option then it shows up a Message Box showing "You cannot choose this" and then selecting the default automatically. So far so good.

But now the thing is that the user cannot make out by seeing the options of JComboBox that which ones can he select, So what I want to do is that if the condition is true then all the options other than the first two should be disabled(or grey out or something) so that users can make out that you cannot select it, and if they still do then my Message Box should come up.

What I tried : I tried looking up this but I couldn't make out what was done in the question (it's answer is for no use for me) and I also tried other options but was unsuccessful.

Note : I am using Netbeans GUI to create everything, and the code I am writing is on JComboBoxActionPerformed and I am a newbie so I couldn't figure out myself, apologies for that

First of all...

This is going to require some hand coding. The GUI Builder is not going to help you out here.

As for the rendering...

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

在此处输入图片说明

As for selecting items...

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

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("ddd", 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();
}
}

Extending the DefaultComboBoxModel and preventing items from being selected worked well for me. There are cases where you may want a disabled item to be set, and in those cases you'll need to call setAllowDisabledItemSelection(true) before setting that item.

import javax.swing.*;
import java.awt.*;
import java.util.HashSet;
import java.util.Set;

public class JComboBoxWithDisabledItems<E> extends JComboBox<E>
{
    private final Set<E> disabledItems;

    private final DisabledItemComboBoxModel<E> model;

    private ListCellRenderer<? super E> renderer;

    public JComboBoxWithDisabledItems()
    {
        super();
        model = new DisabledItemComboBoxModel<>();
        setModel( model );
        setRenderer( new DefaultListCellRenderer());

        disabledItems = new HashSet<>();
        super.setRenderer( ( list, value, index, isSelected, cellHasFocus ) ->
        {
            Component component = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
            Color foreground = component.getForeground();
            Color background = component.getBackground();
            if( disabledItems.contains( value ) )
            {
                if( isSelected )
                {
                    background = UIManager.getColor( "ComboBox.background" );
                }

                foreground = Color.GRAY;
            }

            component.setBackground( background );
            component.setForeground( foreground );

            return component;
        } );
    }


    @Override
    public void setRenderer( ListCellRenderer<? super E> renderer )
    {
        this.renderer = renderer;
    }


    public void setDisabledItems( Set<E> disabledItems )
    {
        this.disabledItems.clear();
        this.disabledItems.addAll( disabledItems );

        model.setDisabledItems( disabledItems );
    }


    public void setAllowDisabledItemSelection( boolean allowDisabledItemSelection )
    {
        model.setAllowDisabledItemSelection( allowDisabledItemSelection );
    }


    private static final class DisabledItemComboBoxModel<E> extends DefaultComboBoxModel<E>
    {
        private final Set<E> disabledItems;
        private boolean allowDisabledItemSelection;
        public DisabledItemComboBoxModel()
        {
            disabledItems = new HashSet<>();
            allowDisabledItemSelection = false;
        }

        @Override
        public void setSelectedItem( Object anObject )
        {
            if( allowDisabledItemSelection || !disabledItems.contains( anObject ) )
                super.setSelectedItem( anObject );
            else
                System.out.println( "selection of item " + anObject + " disabled" );
        }

        public void setDisabledItems( Set<E> disabledItems )
        {
            this.disabledItems.clear();
            this.disabledItems.addAll( disabledItems );
        }


        public void setAllowDisabledItemSelection( boolean allowDisabledItemSelection )
        {
            this.allowDisabledItemSelection = allowDisabledItemSelection;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM