我在JFileChooser
中有一个JFrame
。我已将ActionListener
添加到JFileChooser
,以便点击时“取消”按钮有效。我也可以选择“取消”按钮,但是当我按下“Enter”键时,没有任何反应(即,ActionListener
没有使用事件命令JFileChooser.CANCEL_SELECTION
调用)。我必须对JFileChooser
做什么才能在“取消”按钮上点击“回车”键相当于点击“取消”按钮?
以下是我所看到的(错误)行为的一个简单示例:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.exit(0);
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
要查看(错误)行为,请执行程序,选项卡为“取消”,然后单击“确定”键。程序不会在我的平台上终止 - 尽管我点击“取消”按钮时会这样做。
扩展JFileChooser
并覆盖cancelSelection()
也不起作用(显然,当在“取消”按钮上点击“Enter”键时,不会调用该函数。)
使用Java 5,6和7在我的Fedora 10 x86_64系统上发生(错误)行为。
ADDENDUM:以下内容为当前KeyEventPostProcessor
添加了KeyboardFocusManager
,似乎可以按照我的意愿行事:
import java.awt.Component;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public final class TestApp {
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final JFileChooser chooser = new JFileChooser();
chooser.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
System.out.println(e.paramString());
System.exit(0);
}
});
final KeyboardFocusManager kfm = KeyboardFocusManager
.getCurrentKeyboardFocusManager();
kfm.addKeyEventPostProcessor(new KeyEventPostProcessor() {
@Override
public boolean postProcessKeyEvent(final KeyEvent e) {
if (e.getID() == KeyEvent.KEY_RELEASED
&& e.getKeyCode() == KeyEvent.VK_ENTER) {
final Component comp = e.getComponent();
if (chooser.isAncestorOf(comp)) {
if (!(comp instanceof JButton)) {
chooser.approveSelection();
}
else {
final JButton button = (JButton) comp;
if ("Cancel".equals(button.getText())) {
chooser.cancelSelection();
}
else {
chooser.approveSelection();
}
}
}
}
return false;
}
});
final JFrame frame = new JFrame();
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
catch (final Throwable t) {
t.printStackTrace();
}
}
});
}
}
然而,看起来很多工作只是为了能够区分点击“取消”按钮上的输入键与其他任何地方的输入键。
你觉得它有什么问题吗?
发现的解决方案:将GUI外观和感觉设置为我的系统(Linux)的原生内容,无需任何其他操作即可实现我想要的功能。这是我一无所知和我在寻找的东西。解决方案是具备以下内容
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
作为main()
方法的第一个可执行语句。然后可以省去所有焦点听众,关键事件处理器等。
我已经向最有帮助的受访者颁发了100分。
答案 0 :(得分:3)
该程序不会在我的平台上终止。
我在Mac OS X 10.5,Ubuntu 10和Windows 7上使用(各种)Java 5和6进行正常操作。我将exit()
替换为println()
以查看事件:
System.out.println(rootDirChooser.getSelectedFile().getName() + e.paramString());
指定您的平台和版本可能会有所帮助;如果可能,也要验证安装是否正确。
我不确定我理解你的目标;但是,作为替代方案,请考虑覆盖approveSelection()
:
private static class MyChooser extends JFileChooser {
@Override
public void approveSelection() {
super.approveSelection();
System.out.println(this.getSelectedFile().getName());
}
}
附录:
目标是在“取消”按钮上点击“Enter”键的操作与点击“取消”按钮相同。
正如Key Bindings中所述,您可以更改与VK_ENTER
相关联的操作。
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
InputMap map = chooser.getInputMap(JFileChooser.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
map.put(enter, "cancelSelection");
如果您希望仅在“取消”按钮具有焦点时才进行更改,则需要在Focus Listener中进行更改。
附录:
我找到了一个使用
KeyboadFocusManager
的解决方案。你觉得怎么样?
我可以看到专业人士每个方面都有所帮助,所以我在下面列出了两个方面。使用KeyboadFocusManager
查找所有按钮,但不提供区域设置独立方式来区分它们; Focus Listener
方法只能看到批准按钮,而且它是特定于UI的。不过,您可以将方法结合起来以获得更好的结果。第二种意见不会出现问题。
附录:
我已更新下面的代码,无需知道“取消”按钮的本地化名称,并使用键绑定。
import java.awt.EventQueue;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.plaf.metal.MetalFileChooserUI;
public final class FileChooserKeys
implements ActionListener, FocusListener, PropertyChangeListener {
private final JFileChooser chooser = new JFileChooser();
private final MyChooserUI myUI = new MyChooserUI(chooser);
private final KeyStroke enterKey =
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
private void create() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
chooser.addActionListener(this);
myUI.installUI(chooser);
myUI.getApproveButton(chooser).addFocusListener(this);
KeyboardFocusManager focusManager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(this);
frame.add(chooser);
frame.pack();
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.paramString());
}
@Override
public void focusGained(FocusEvent e) {
System.out.println("ApproveButton gained focus.");
}
@Override
public void focusLost(FocusEvent e) {
System.out.println("ApproveButton lost focus.");
}
@Override
public void propertyChange(PropertyChangeEvent e) {
Object o = e.getNewValue();
InputMap map = chooser.getInputMap(
JFileChooser.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
if (o instanceof JButton) {
if ("focusOwner".equals(e.getPropertyName())) {
JButton b = (JButton) o;
String s = b.getText();
boolean inApproved = b == myUI.getApproveButton(chooser);
if (!(s == null || "".equals(s) || inApproved)) {
map.put(enterKey, "cancelSelection");
} else {
map.put(enterKey, "approveSelection");
}
}
}
}
private static class MyChooserUI extends MetalFileChooserUI {
public MyChooserUI(JFileChooser b) {
super(b);
}
@Override
protected JButton getApproveButton(JFileChooser fc) {
return super.getApproveButton(fc);
}
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new FileChooserKeys().create();
}
});
}
}