DejanLekic
DejanLekic

Reputation: 19822

How to detect TAB key-press in JComboBox?

I am trying to find out how to detect if a JComboBox lost focus when user pressed tab or via a mouse-click outside the component's area.

Adding a FocusListener to the editor component of the JComboBox does not help me, as I can't find out if user used the mouse or moved the focus via the tab key. Any ideas would be greatly appreciated.

Edit 1: What I am trying to achieve is this:

Edit 2: It seems that I have to use setFocusTraversalKeysEnabled(false) to get notified when TAB is pressed, and when i capture that event, I should manually transfer focus... I do not like this solution, but that is so far the best I could come up with.

Solution:

Following piece of Java code is actually solving my problem. As I wrote in Edit 2 the easiest solution was to disable focus traversal. I shamelessly borrowed Kleopatra's code, and all works now. :)

    if (!isTableCellEditor()) {
        comboBoxEditor.setFocusTraversalKeysEnabled(false);

        Action myAction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                handleTabPress();
                comboBoxEditor.transferFocus();
            } // actionPerformed() method
        };

        comboBoxEditor.getActionMap().put("tab-action", myAction);
        comboBoxEditor.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
            .put(KeyStroke.getKeyStroke("TAB"), "tab-action");
    } // if

Thanks to all participants in the discussion!

Upvotes: 3

Views: 3861

Answers (2)

kleopatra
kleopatra

Reputation: 51536

As I understand your question, there are two separate problems

  • don't commit the value while navigating
  • take over the reaction to TAB

if so, the answers are

  • configure the combo so that it thinks it is the editing component of a CellEditor
  • disable the default traversal keys for the combo and take over with a custom binding

In code:

    final JComboBox simpleBox = new JComboBox(Locale.getAvailableLocales());
    // this line configures the combo to only commit on ENTER 
    // or selecting an item from the list
    simpleBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
    //
    // simpleBox.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
    //     Collections.EMPTY_SET);
    // just noticed the OPs edit - following indeed is easier to disable _all_ traversal
    // keys with one statement
    simpleBox.setFocusTraversalKeysEnabled(false);

    Action myAction = new AbstractAction() {

        @Override
        public void actionPerformed(ActionEvent e) {
            LOG.info("got it!");
            simpleBox.transferFocus();
        }

    };
    simpleBox.getActionMap().put("tab-action", myAction);
    simpleBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
       .put(KeyStroke.getKeyStroke("TAB"), "tab-action");

Upvotes: 6

Maarten Bodewes
Maarten Bodewes

Reputation: 94118

It is assumed that you have pressed the mouse (or key) right before you loose focus. So listen to all the keyboard and mouse clicks, and the one used last right before loosing focus is the culprit.

When focuslost is fired, you would check a variable you set when a mouse or key is pressed, on any part of your window. This variable just logs the last mouse and/or key pressed. You would have to capture all the mouse and keypresses of course, since clicking on any widget would let you loose focus.

Upvotes: 3

Related Questions