Java 如何删除Ctrl+;C对JFileChooser的操作?

Java 如何删除Ctrl+;C对JFileChooser的操作?,java,swing,key-bindings,jfilechooser,key-events,Java,Swing,Key Bindings,Jfilechooser,Key Events,我在我自己的框架中的程序中嵌入了一个JFileChooser,框架中还有其他自定义组件。以下是我的应用程序的设计,因为它可能有助于可视化我的问题: 如果您不知道,则直接在JFrame标题下的列表是jfilechooser。其工作方式是将快捷键指定给目标,然后当您按这些快捷键时,选定的文件将移动到目标 我这样做的策略是将快捷方式分配给整个帧的InputMap范围的javax.swing.JComponent.WHEN\u-IN\u-FOCUSED\u窗口 但令人恼火的是,有些东西(我假设JFil

我在我自己的框架中的程序中嵌入了一个
JFileChooser
,框架中还有其他自定义组件。以下是我的应用程序的设计,因为它可能有助于可视化我的问题:

如果您不知道,则直接在
JFrame
标题下的列表是
jfilechooser
。其工作方式是将快捷键指定给目标,然后当您按这些快捷键时,选定的文件将移动到目标

我这样做的策略是将快捷方式分配给整个帧的
InputMap
范围的
javax.swing.JComponent.WHEN\u-IN\u-FOCUSED\u窗口

但令人恼火的是,有些东西(我假设
JFileChooser
)不停地响应/吸收我不希望的按键。例如,如果我按下
Ctrl+C
我的快捷操作不会运行。我尝试过使用本机外观(我使用的是windows 7)和默认L&F,这两种情况都有相同的问题。我认为它可能试图在
JFileChooser
中执行所选文件的复制操作,因为如果我单击其中一个按钮使其失去焦点,我的
Ctrl+C
命令会突然执行我的操作

但是,我真的不确定
JFileChooser
是如何做到这一点的。当我对它调用
getKeyListeners()
时,它返回一个空数组。我还尝试在所有三个范围内清除该组合键的输入映射,但它似乎仍在吸收按键

谁能给我一些示例代码,让
JFileChooser
忽略
Ctrl+C
?另外,如果将来有人能告诉我如何调试这样的问题,那会很有帮助


这是我到目前为止尝试过的一些代码。您也可以使用它来尝试自己测试,因为这段代码编译和运行如下:

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

更新:我甚至递归地清除了inputMaps,删除了JFileChooser及其所有子组件的KeyListener,而JFileChooser仍然接受了我的Ctrl+C命令。下面是我用来做这件事的代码(我将JFileChooser传递到了这里):


显然,InputMaps可以有父母。因此,您对所有内置关键“反应器”的清除还没有完全完成。正如您可能猜到的,Swing在某些组件上为自己注册某些默认键盘绑定。在Windows上,这通常包括Ctrl+C,因为这是操作系统将数据复制到剪贴板的标准热键

此修改的
removeKeyboardReactors
为我显示System.out.println:

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();
    }
}
我必须从
removeKeyboardReactors
中删除此代码,因为它导致堆栈溢出:

if (root.getRootPane() != null) {
    removeKeyboardReactors(root.getRootPane());
}
整个修改后的沙盒类如下所示。希望这足以让你走上正轨。如果您希望密钥绑定的删除更加特定于密钥,请查看

详细信息视图仍将有一个填充的inputmap

我怀疑details视图和list视图之间的区别在于一个使用JTable,另一个使用JList。所以我猜您只需要从details视图的JTable中删除绑定

这可以在不创建详细信息面板的情况下完成:

InputMap im = (InputMap)UIManager.get("Table.ancestorInputMap");
KeyStroke ctrlC = KeyStroke.getKeyStroke("control C");
//im.put(ctrlC, "none");
im.remove(ctrlC);
再次需要注意的是,此解决方案(以及您当前拥有的解决方案)将删除所有组件的默认Ctrl+C功能,而不仅仅是为JFileChooser实例化的组件

编辑:

它不应该只是从我从中移除它吗

代码使用getParent()方法获取包含绑定的InputMap。此InputMap由组件的所有实例共享。当您使用以下选项时,组件将仅具有唯一绑定:

component.getInputMap(...).put(...);
也就是说,绑定被添加到组件InputMap,而不是其父级InputMap

你怎么知道你能做到这一点,这是正确的做法

看。该列表列出了给定LAF的默认值。我不知道这样做是否正确。据我所知,效果与您现在使用的代码相同。这只是从InputMap中删除绑定的另一种方法,而不需要实际的组件来访问父InputMap

第二次编辑:

显示输入映射的一些简单代码是相同的:

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

我很快就会试试这个,谢谢你的回答。对于将来如何调试此类问题,您有什么建议吗?例如:有没有办法打开“swing调试”,这样我就可以看到一条日志消息,上面写着:“Ctrl+C是由inputmap Y中的X操作处理的”我发现了一个问题。如果将其切换到详细视图,然后单击仍包含“Control C”的文件。但是如果你点击文本字段,它就不起作用了,这很好,因为它以前是这样的。知道是什么原因吗?显然JFileChooser有一个文件窗格。此对象有一个JPanel(或其他东西)来显示当前视图,而getComponents将只返回当前显示的视图。这意味着,如果清除inputMap,然后切换到details视图,则details视图仍将具有填充的inputMap。我可以通过切换到这两个视图并清除每个视图中的输入映射,然后返回到您所在的位置来解决这个问题,但我认为这很有技巧。据我所知,没有简单的调试机制。细节视图这件事有点不对劲。我会考虑一下,然后再给您回复。您可以使用UIManager删除绑定,前提是您知道是哪个组件导致了问题。看看我的建议。不知道你为什么要我帮忙。你有答案。Ctrl C不能一直工作,因为像JTextField和JList这样的组件映射这些键绑定。您已经从文件选择器上的所有组件中删除了此绑定,因此您的代码现在应该可以工作了。当然,这个解决方案的问题是,它将删除Ctrl+C功能f
component.getInputMap(...).put(...);
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);
}