Hitesh saxena
Hitesh saxena

Reputation: 51

Auto select/highlight item in combox with checkBox

I used the sample code to create Combobox with checkbox items. Java - Check Boxes in a JComboBox

Sample program where i used that JComboCheckBox

import javax.swing.JCheckBox;
import javax.swing.JFrame;

public class ComboBoxMainClass {
public static void main(String[] args) {
    // Frame for our test

    JComboCheckBox combo = new JComboCheckBox(new JCheckBox[] {
            new JCheckBox(""), new JCheckBox("First"),
            new JCheckBox("Second") });

    JFrame f = new JFrame("Frame Form Example");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(combo);
    // Show the frame
    f.pack();
    f.setVisible(true);
}
}

But I cant select combo items on key press. e.g. if combo text is First, second etc.. User press "S" key, Second should be highlighted/selected. Just like in normal JComboBox. Is there any way to do it as in one of my application we need it.

Upvotes: 2

Views: 1518

Answers (2)

camickr
camickr

Reputation: 324108

Combo box item selection is done by the KeySelectionManager. The default implementation uses the value returned from the toString() method of the object added to the ComboBoxModel to determine which item to select.

You could create a custom JCheckBox component and override the toString() method to return the getText() method.

Or the other approach is to create custom KeySelectionManager to be used with the custom renderer. This approach is more involved.

Check out Combo Box With Custom Renderer for a class that is a renderer and a KeySelectionManager. However, this class is designed to display a property from a business object, not a Swing component so it will need further customization.

Below is a customized version to display a JCheckBox:

import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;

/*
 *  This class can be used as the renderer and KeySelectionManager for an
 *    Object added to the ComboBoxModel.
 *
 *  The class must be extended and the getDisplayValue() method must be
 *  implemented. This method will return a String to be rendered in the
 *  JComboBox. The same String will be used to do key selection of an
 *  item in the ComboBoxModel.
 */
public class CheckBoxKeySelectionRenderer extends BasicComboBoxRenderer
    implements JComboBox.KeySelectionManager
{
    //  Used by the KeySelectionManager implementation to determine when to
    //  start a new search or append typed character to the existing search.

    private long timeFactor;
    private long lastTime;
    private long time;
    private String prefix = "";

    public CheckBoxKeySelectionRenderer(JComboBox comboBox)
    {
        comboBox.setRenderer( this );
        comboBox.setKeySelectionManager( this );

        Long l = (Long)UIManager.get("ComboBox.timeFactor");
        timeFactor = l == null ? 1000L : l.longValue();
    }

    /**
     *  This method must be implemented in the extended class.
     *
     *  @param item an item from the ComboBoxModel
     *  @returns a String containing the text to be rendered for this item.
    */
    public String getDisplayValue(Object item)
    {
        if (item instanceof JCheckBox)
        {
            JCheckBox checkBox = (JCheckBox)item;
            return checkBox.getText();
        }
        else
            return item.toString();
    }

    //  Implement the renderer

    @Override
    public Component getListCellRendererComponent(
        JList list, Object item, int index, boolean isSelected, boolean hasFocus)
    {
        super.getListCellRendererComponent(list, item, index, isSelected, hasFocus);

        if (item instanceof JCheckBox)
        {
            Component c = (Component)item;

            if (isSelected)
            {
                c.setBackground(list.getSelectionBackground());
                c.setForeground(list.getSelectionForeground());
            }
            else
            {
                c.setBackground(list.getBackground());
                c.setForeground(list.getForeground());
            }

            return c;
        }

        return this;
    }

    //  Implement the KeySelectionManager

    @Override
    public int selectionForKey(char aKey, ComboBoxModel model)
    {
        time = System.currentTimeMillis();

        //  Get the index of the currently selected item

        int size = model.getSize();
        int startIndex = -1;
        Object selectedItem = model.getSelectedItem();

        if (selectedItem != null)
        {
            for (int i = 0; i < size; i++)
            {
                if ( selectedItem == model.getElementAt(i) )
                {
                    startIndex  =  i;
                    break;
                }
            }
        }

        //  Determine the "prefix" to be used when searching the model. The
        //  prefix can be a single letter or multiple letters depending on how
        //  fast the user has been typing and on which letter has been typed.

        if (time - lastTime < timeFactor)
        {
            if((prefix.length() == 1) && (aKey == prefix.charAt(0)))
            {
                // Subsequent same key presses move the keyboard focus to the next
                // object that starts with the same letter.
                startIndex++;
            }
            else
            {
                prefix += aKey;
            }
        }
        else
        {
            startIndex++;
            prefix = "" + aKey;
        }

        lastTime = time;

        //  Search from the current selection and wrap when no match is found

        if (startIndex < 0 || startIndex >= size)
        {
            startIndex = 0;
        }

        int index = getNextMatch(prefix, startIndex, size, model);

        if (index < 0)
        {
            // wrap
            index = getNextMatch(prefix, 0, startIndex, model);
        }

        return index;
    }

    /*
    **  Find the index of the item in the model that starts with the prefix.
    */
    private int getNextMatch(String prefix, int start, int end, ComboBoxModel model)
    {
        for (int i = start; i < end; i++ )
        {
            Object item = model.getElementAt(i);

            if (item != null)
            {
                String displayValue = getDisplayValue( item ).toLowerCase();

                if (displayValue.startsWith(prefix))
                {
                    return i;
                }
            }
        }

        return -1;
    }
}

You can use it by adding the following to your code:

new CheckBoxKeySelectionRenderer(combo);

This will replace your current renderer. However, you will still not be able to toggle the selection state of the currently selected item. This is because a combo box does not select the same item twice. This is a combo box issue, not a renderer issue. I don't know how to fix this.

Upvotes: 1

Tim B
Tim B

Reputation: 41168

That isn't how a normal jComboBox works, pressing the "S" key highlights the first entry beginning with "S", not the second entry.

You can use the arrow keys up/down to select in any combo box.

To give the behaviour you need add a key listener in the application and select the relevant entries based on the keys pressed. There's no built in way I'm aware of to do this though.

Upvotes: 0

Related Questions