2

I have a JList with a key listener to make it easy for the user to delete an item from the list. On windows, it works fine. You hit the delete key and the item is removed. On mac, the program does not respond to the delete key. I am using KeyEvent.VK_DELETE and I thought this was a platform neutral way of detecting special keys. Is there a different way I should be detecting the key press on the Mac?

    studentJList.setModel(studentListModel);  // a custom model I wrote
    studentJList.addKeyListener(new KeyListener() {
        @Override
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_DELETE) {
                studentListModel.remove(studentJList.getSelectedIndex());
                studentJList.revalidate();
            }
        }

        @Override
        public void keyReleased(KeyEvent e) { }

        @Override
        public void keyTyped(KeyEvent e) { }
    });
Thorn
  • 4,015
  • 4
  • 23
  • 42

2 Answers2

7

Use keybindings instead of key listeners and the behavior will be the same on all platforms.

See also KeyAdapter listener works in Windows, not on Mac, which is more or less the same problem and the solution also applies for your problem.

Community
  • 1
  • 1
Robin
  • 36,233
  • 5
  • 47
  • 99
  • Thank you. I've never touched keyBindings before, but the tutorial makes it look easy enough. I don't see why the keyListener shouldn't work, though. @mKorbel - thank you for posting a code example of this. – Thorn Apr 02 '12 at 13:04
  • 1
    In the linked question others brought up the possibility of differences in the focus behavior between Windows and OSX. And the keylistener needs focus before it is triggered – Robin Apr 02 '12 at 13:11
  • @Thorn be sure that you follows great suggestion by (@kleopatra), these commnent driving me crazy :-) – mKorbel Apr 02 '12 at 13:13
  • I had a related problem, but the code worked well under MacOS and not under Windows. Shift key events were not being generated under MacOS and thus not expected by the developer who writes mostly on that platform. Windows implementation was broken due to "spurious" shift key events. – Fuhrmanator Dec 12 '12 at 03:52
4

for example

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ListDemo extends JPanel {

    private static final long serialVersionUID = 1L;
    private JFrame frame = new JFrame("ListDemo");
    private JList list;
    private DefaultListModel listModel;

    public ListDemo() {
        super(new BorderLayout());
        listModel = new DefaultListModel();
        listModel.addElement("Jane Doe");
        listModel.addElement("John Smith");
        listModel.addElement("Kathy Green");
        list = new JList(listModel);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.setSelectedIndex(0);
        list.setVisibleRowCount(5);
        JScrollPane listScrollPane = new JScrollPane(list);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(listScrollPane, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
        setKeyBindings();
    }

    private void setKeyBindings() {
        list.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
                .put(KeyStroke.getKeyStroke("DELETE"), "clickDelete");
        list.getActionMap().put("clickDelete", new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                int index = list.getSelectedIndex();
                if (index > -1) {
                    listModel.remove(index);
                }
            }
        });
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                ListDemo listDemo = new ListDemo();
            }
        });
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • 1
    _I see I lost too much of time_ probably because your code again is-not an sscce. SCNR :-) – kleopatra Apr 02 '12 at 12:40
  • on a more serious beat: don't use a ComponentInputMap (that's the one of type WHEN_IN_FOCUSED_WINDOW) except if it's absolutely necessary, it's hard to get such bindings unique-enough and they are always the last to see it. Instead, register the bindings with WHEN_ANCESTOR of the nearest parent that makes sense, here f.i. the contentPane – kleopatra Apr 02 '12 at 12:48
  • @kleopatra right agreed, but that was reason to restrict of KeyStroke DELETE only if JList has focus in the window :-) maybe my dirty hack, maybe my non_****, because is possible put this listener directly to the JList .... – mKorbel Apr 02 '12 at 12:52
  • _only if JList has focus_ if that's your intention, the binding is downright wrong - use the list's inputMap of type WHEN_FOCUSED - obviously with the same focus-related problems as the OP in the keyListener ;-) – kleopatra Apr 02 '12 at 12:57
  • @kleopatra please see my edit, this is way how to I understand what `KeyBindings` works, I appreciating your valuable info, but not possible to testing difference and fired events betweens `ANCESTOR` and `FOCUSED` right now – mKorbel Apr 02 '12 at 12:59
  • I thruth in your comments, I must to test all possible (five) combinations, thank you – mKorbel Apr 02 '12 at 13:01
  • @kleopatra `obviously with the same focus-related problems as the OP in the keyListener` not you have to select Item before DELETE, then my code in this form, this is wrong example about JList, I have to test with JTextField or JComboBox – mKorbel Apr 02 '12 at 13:04
  • This debate is confusing me. I expect the user to select some items in the JList, then hit the delete key to say good-bye to the selection. So where should the binding be placed? Would not the JList be the most logical place? The input panel contains text fields. If the user is in a text field, the delete key should NOT fire this action - only when the JList has focus. – Thorn Apr 02 '12 at 13:09
  • @kleopatra aaaach this is very funny, every answerers wrote only `use KeyBindings rather than Keylistener` except HFOE, hahaha after searching here I found nice `ZOO`, thank you for notified me – mKorbel Apr 02 '12 at 13:11
  • @Thorn add listener to the JList, change WHEN_IN_FOCUSED_WINDOW to WHEN_ANCESTOR, this could works in all cases, maybe better would be post here concrete question How KeyBindings works, there are 2-3 persons that can explain your question (sure for me too) and with SSCCE :-) please – mKorbel Apr 02 '12 at 13:17
  • when I get to it, I'll take the advice here and use it, but it turns out the code I originally works fine! There are two delete keys on the Mac keyboard and one if them works more like a backspace. The user was just hitting the "wrong" delete key. – Thorn Apr 11 '12 at 16:33