I have a JFileChooser in a JFrame. I've added an ActionListener to the JFileChooser so that the "Cancel" button works when clicked. I can also tab to the "Cancel" button, but when I then hit the "Enter" key, nothing happens (i.e., the ActionListener isn't called with the event command JFileChooser.CANCEL_SELECTION). What must I do with the JFileChooser so that hitting the "Enter" key when on the "Cancel" button is equivalent to clicking on the "Cancel" button?
Here's a simple example of the (mis)behavior I'm seeing:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.exit(0);
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
To see the (mis)behavior, execute the program, tab to "Cancel", and then hit the "Enter" key. The program doesn't terminate on my platform -- although it does when I click on the "Cancel" button.
Extending JFileChooser and overriding cancelSelection() also doesn't work (apparently, that function isn't called when the "Enter" key is hit while on the "Cancel" button).
The (mis)behavior occurs on my Fedora 10 x86_64 system with Java 5, 6, and 7.
ADDENDUM: The following adds a KeyEventPostProcessor to the current KeyboardFocusManager and appears to do what I want:
import java.awt.Component;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.out.println(e.paramString());
System.exit(0);
}
});
final KeyboardFocusManager kfm = KeyboardFocusManager
.getCurrentKeyboardFocusManager();
kfm.addKeyEventPostProcessor(new KeyEventPostProcessor() {
@Override
public boolean postProcessKeyEvent(final KeyEvent e) {
if (e.getID() == KeyEvent.KEY_RELEASED
&& e.getKeyCode() == KeyEvent.VK_ENTER) {
final Component comp = e.getComponent();
if (chooser.isAncestorOf(comp)) {
if (!(comp instanceof JButton)) {
chooser.approveSelection();
}
else {
final JButton button = (JButton) comp;
if ("Cancel".equals(button.getText())) {
chooser.cancelSelection();
}
else {
chooser.approveSelection();
}
}
}
}
return false;
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
It seems like a lot of work, however, just to be able to distinguish between hitting the enter key on the "Cancel" button versus anywhere else.
Do you see any problems with it?
DISCOVERED SOLUTION: Setting the GUI Look and Feel to the native one for my system (Linux) does what I want without the need for anything else. This is what I was ignorant of and what I was looking for. The solution is to have the following
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
as the first executable statement of the main() method. One can then dispense with all focus listeners, key event processors, etc.
I've awarded the 100 points to the most helpful respondent.