-->

你如何删除上一个JFileChooser按Ctrl + C动作?(How do you remove

2019-09-01 04:01发布

我嵌入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;
    }
}

更新 :据递归清除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);
        }
    }
}

Answer 1:

细节来看仍会有一个人口稠密的InputMap

我怀疑差的详细信息视图和列表视图是一个使用JTable中其他一个JList。 所以我猜你只需要的细节来看,从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。

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

见UIManager的默认值 。 该列表的默认值给出LAF。 我不知道这是否是正确的事情。 据我所知,效果是一样的,你现在使用的代码。 这又是另一种或删除从InputMap中的绑定,而无需实际组件来访问父母的InputMap。

第二个编辑:

一些简单的代码来显示InputMaps是相同的:

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


Answer 2:

显然InputMaps可以有父母。 所以,你的所有内置密钥“反应堆”的清洗还没有完全完成。 正如你可能已经猜到,秋千注册某些组件本身的某些默认键盘绑定。 在Windows上,通常包括按Ctrl + C,因为这是用于将数据复制到剪贴板中的OS标准热键。

此修改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#删除(的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);
            }
        }
    }
}


文章来源: How do you remove the Ctrl+C action on a JFileChooser?