How do you remove the Ctrl+C action on a JFileChooser?

China☆狼群 提交于 2019-11-29 13:38:07

the details view will still have a populated inputmap

I suspect the difference between the details view and the list view is that one uses a JTable the other a JList. So I would guess you only need to remove the bindings from the JTable of the details view.

This can be done without creating the details panel:

InputMap im = (InputMap)UIManager.get("Table.ancestorInputMap");
KeyStroke ctrlC = KeyStroke.getKeyStroke("control C");
//im.put(ctrlC, "none");
im.remove(ctrlC);

Again, it should be noted that this solution (along with the solution you currently have) will remove the default Ctrl+C functionality for all components, not just the ones instantiated for the JFileChooser.

Edit:

Shouldn't it only be removing it from the ones I remove it from?

Your code uses the getParent() method to get the InputMap that contains the binding. This InputMap is shared by all instances of a component. A component will only have unique bindings when you use:

component.getInputMap(...).put(...);

That is, the binding is added to the components InputMap, not its parents InputMap.

How did you know you could do this and this is the right thing to do

See UIManager Defaults. This list the defaults for the given LAF. I don't know if this is the right thing to do. As far as I know the effect is the same as the code you use now. This is just another way or removing a binding from an InputMap without needing an actual component to access the parents InputMap.

Second edit:

Some simple code to show the InputMaps are the same:

public static void main(String[] args)
{
    JButton first = new JButton("button");
    System.out.println(first.getInputMap().getParent());

    InputMap im = (InputMap) UIManager.get("Button.focusInputMap");
    System.out.println(im);
}
Mike Clark

Apparently InputMaps can have parents. So your purging of all built-in key "reactors" is not entirely complete. As you've probably guessed, Swing registers certain default keyboard bindings for itself on certain components. On Windows this often includes Ctrl+C, since that is the OS-standard hotkey for copying data to the clipboard.

This modified removeKeyboardReactors gets the System.out.println appearing for me:

private static void removeKeyboardReactors(JComponent root) {
    System.out.println("I'm going to clear the inputMap of: " + root);
    clearInputMap(root.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
    clearInputMap(root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW));
    clearInputMap(root.getInputMap(JComponent.WHEN_FOCUSED));

    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);
        }
    }
}

private static void clearInputMap(InputMap inputMap) {
    inputMap.clear();
    while ((inputMap = inputMap.getParent()) != null) {
        inputMap.clear();
    }
}

I had to remove this code from removeKeyboardReactors because it was causing a stack overflow:

if (root.getRootPane() != null) {
    removeKeyboardReactors(root.getRootPane());
}

The entire modified Sandbox class follows below. Hopefully this is enough to get you on your way. If you want the key-binding removal to be more key-specific, have a look at InputMap#remove(KeyStroke).

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!");
            }
        });

        JFileChooser fileChooser = buildFileChooser();
        panel.add(fileChooser); //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();

        removeKeyboardReactors(fileChooser);

        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;
    }

    private static void clearInputMap(InputMap inputMap)
    {
        inputMap.clear();
        while ((inputMap = inputMap.getParent()) != null)
        {
            inputMap.clear();
        }
    }

    private static void removeKeyboardReactors(JComponent root) {
        System.out.println("I'm going to clear the inputMap of: " + root);
        clearInputMap(root.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
        clearInputMap(root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW));
        clearInputMap(root.getInputMap(JComponent.WHEN_FOCUSED));

        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);
            }
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!