如何删除JFileChooser上的Ctrl + C操作?

Dan*_*lan 8 java swing key-events jfilechooser key-bindings

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

我是如何使用JFileChooser的

如果你不能说,JFrame标题下面的列表是JFileChoosers.这应该是有效的方法是您为目标分配快捷方式,然后当您按下这些快捷键时,所选文件将移动到目标.

我这样做的策略是将快捷方式分配给一个javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW范围InputMap的整个框架.

但令人讨厌的是,某些东西(我假设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;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:我已经走到递归清除inputMaps并删除JFileChooser及其所有子组件的keyListeners,并且JFileChooser 仍然吞下我的Ctrl + C命令.这是我用来做这个的代码(我将JFileChooser传递给了这个代码):

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

cam*_*ckr 4

详细信息视图仍将有一个填充的输入映射

我怀疑详细信息视图和列表视图之间的区别在于,一个使用 JTable,另一个使用 JList。所以我猜您只需要从详细信息视图的 JTable 中删除绑定即可。

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

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

再次,应该注意的是,此解决方案(以及您当前拥有的解决方案)将删除所有组件的默认 Ctrl+C 功能,而不仅仅是为 JFileChooser 实例化的组件。

编辑:

难道它不应该只从我从中删除它的人中删除它吗?

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

component.getInputMap(...).put(...);
Run Code Online (Sandbox Code Playgroud)

也就是说,绑定被添加到组件InputMap,而不是其父级InputMap。

您怎么知道您可以做到这一点并且这是正确的做法

请参阅UIManager 默认值。这列出了给定 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);
}
Run Code Online (Sandbox Code Playgroud)

  • @tieTYT,“Table.ancestorInputMap”是所有 JTable 组件的父 InputMap。因此,如果您从 UIManager 中删除绑定,就好像该绑定从未存在过一样。请参阅我的第二次编辑。请注意,我更改了代码以实际使用 im.remove(...) 而不是 im.put(...)。这应该更符合您现有的代码。 (2认同)