Как удалить действие Ctrl+C на JFileChooser?

я врежу JFileChooser в моей программе в моем собственном фрейме с другими пользовательскими компонентами в фрейме. Вот дизайн моего приложения, поскольку это может помочь визуализировать мои проблемы:

How I'm using JFileChooser

если вы не можете сказать, списки непосредственно под JFrame заголовки JFileChoosers. Способ, которым это должно работать, заключается в назначении ярлыков назначениям, а затем при нажатии этих клавиш выбранный файл перемещается к назначению.

моя стратегия для это делается для назначения ярлыка javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW объем InputMap всего кадра.

но что раздражает-это что-то (я предполагаю, что JFileChooser) продолжает отвечать / поглощать нажатия клавиш, которые я не хочу. Например, если я нажму Ctrl+C мое действие ярлыка не запускается. Я пробовал это с родным внешним видом (я использую windows 7), а по умолчанию L&F и обе ситуации имеют одну и ту же проблему. Я думаю, что это может быть попытка сделать действие копирования выбранный файл в JFileChooser потому что, если я нажму на одну из кнопок, чтобы заставить его потерять фокус, внезапно мой тут мой действие.

но я не совсем уверен, как 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 и удалить keyListeners JFileChooser и весь его ребенок компоненты и 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);
        }
    }
}

2 ответов


просмотр подробностей будет еще заполнен 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.

Edit:

разве он не должен удалять его только из тех, из которых я его удаляю?

ваш код использует метод 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);
}

по-видимому, InputMaps могут иметь родителей. Таким образом, ваша очистка всех встроенных ключевых "реакторов" не полностью завершена. Как вы, наверное, догадались, Swing регистрирует определенные привязки клавиатуры по умолчанию для себя на определенных компонентах. В Windows это часто включает Ctrl+C, так как это стандартная горячая клавиша для копирования данных в буфер обмена.

этот модифицированный removeKeyboardReactors получает система.из.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();
    }
}

I пришлось удалить этот код removeKeyboardReactors потому что это вызывает переполнение стека:

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

весь измененный класс песочницы приведен ниже. Надеюсь, этого достаточно, чтобы вы отправились в путь. Если вы хотите, чтобы удаление привязки ключа было более специфичным для ключа, посмотрите на InputMap#remove (нажатие клавиши).

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