I'm embedding a JFileChooser
in my program in my own frame with other custom components in the frame. Here's a design of my app as it may help visualize my issues:
If you can't tell, the lists directly under the JFrame
titles are JFileChoosers
. The way this is supposed to work is you assign shortcuts to destinations and then when you press those shortcut keys, the selected file moves to the destination.
My strategy for doing this is to assign the shortcut to a javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW
scope of the InputMap
of the entire frame.
But what's annoying is that something (I assume the JFileChooser
) keeps on responding/absorbing key presses I don't want it to. For example, if I press Ctrl+C
my shortcut action doesn't get run. I've tried this with the native Look and Feel (I'm using windows 7) and the default L&F and both situations have the same problem. I think it might be trying to do a copy action of the selected file in the JFileChooser
because if I click on one of the buttons to force it to lose focus, all the sudden my Ctrl+C
command does my action.
But, I'm not really sure how the JFileChooser
is doing this. When I call getKeyListeners()
on it, it returns an empty array. I've also tried clearing its input map for this key combination at all three scopes, and it still seems to be absorbing the keypress.
Can anyone give me some sample code that makes the JFileChooser
ignore Ctrl+C
? Also, it'd be helpful if someone could tell me how to debug problems like this in the future.
Here is some code of what I've tried so far. You can also use this to try to test this on your own, since this code compiles and runs, as-is:
package com.sandbox;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class Sandbox {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control C"), "println");
panel.getActionMap().put("println", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println("The JPanel action was performed!");
}
});
panel.add(buildFileChooser()); //if you comment out this line, Ctrl+C does a println, otherwise my action is ignored.
frame.setContentPane(panel);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static JFileChooser buildFileChooser() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.getActionMap().clear(); //I've tried lots of ideas like this, but the JFileChooser still responds to Ctrl+C
return fileChooser;
}
}
UPDATE: I've gone as far as to recursively clear the inputMaps and remove the keyListeners of the JFileChooser and all of its child components and the JFileChooser still swallows my Ctrl+C command. Here's the code I've used to do this (I passed my JFileChooser into this):
private static void removeKeyboardReactors(JComponent root) {
System.out.println("I'm going to clear the inputMap of: " + root);
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).clear();
root.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).clear();
root.getInputMap(JComponent.WHEN_FOCUSED).clear();
root.getActionMap().clear();
if (root.getRootPane() != null) {
removeKeyboardReactors(root.getRootPane());
}
for (KeyListener keyListener : root.getKeyListeners()) {
root.removeKeyListener(keyListener);
}
for (Component component : root.getComponents()) {
if (component instanceof JComponent) {
removeKeyboardReactors((JComponent) component);
} else if (component instanceof Container) {
Container container = (Container) component;
for (Component containerComponent : container.getComponents()) {
if (containerComponent instanceof JComponent) {
removeKeyboardReactors((JComponent) containerComponent);
} else {
System.out.println("This Container Component was not a JComponent: " + containerComponent);
}
}
} else {
System.out.println("This was not a JComponent: " + component);
}
}
}
See Question&Answers more detail:
os