我在自己的框架中将JFileChooser
与框架中的其他自定义组件一起嵌入到程序中。这是我的应用程序的设计,因为它可以帮助可视化我的问题:
如果您不知道,JFrame
标题正下方的列表就是JFileChoosers
。这种方法的工作方式是将快捷方式分配给目标,然后按这些快捷键时,所选文件将移动到目标。
我这样做的策略是将快捷方式分配给整个框架的javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW
的InputMap
范围。
但是令人讨厌的是,某些东西(我假设是JFileChooser
)不断响应/吸收我不希望的按键。例如,如果我按Ctrl+C
,则我的快捷方式操作不会运行。我已经尝试使用 native 的外观(我使用的是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);
}
}
}
最佳答案
我怀疑详细信息 View 和 ListView 之间的区别在于,一个使用JTable,另一个使用JList。因此,我猜您只需要从详细信息 View 的JTable中删除绑定(bind)即可。
无需创建详细信息面板即可完成此操作:
InputMap im = (InputMap)UIManager.get("Table.ancestorInputMap");
KeyStroke ctrlC = KeyStroke.getKeyStroke("control C");
//im.put(ctrlC, "none");
im.remove(ctrlC);
同样,应该注意的是,此解决方案(以及您当前拥有的解决方案)将删除所有组件的默认Ctrl + C功能,而不仅仅是为JFileChooser实例化的组件。
编辑:
您的代码使用getParent()方法获取包含绑定(bind)的InputMap。该InputMap由组件的所有实例共享。使用以下组件时,组件将仅具有唯一绑定(bind):
component.getInputMap(...).put(...);
即,将绑定(bind)添加到组件InputMap,而不是其父级InputMap。
参见UIManager Defaults。此列表列出了给定LAF的默认值。我不知道这是否是正确的事情。据我所知,效果与您现在使用的代码相同。这只是另一种方法,或者从InputMap删除绑定(bind)而无需实际组件访问父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);
}
关于java - 如何删除JFileChooser上的Ctrl + C Action ?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16229526/