如何在点击“Enter"时采取行动在“取消"时JFileChooser 中的按钮?
我在 JFrame
中有一个 JFileChooser
.我在 JFileChooser
中添加了一个 ActionListener
,以便单击取消"按钮时可以使用.我也可以选择取消"按钮,但是当我按下Enter"键时,什么也没有发生(即,ActionListener
没有被事件命令 JFileChooser.CANCEL_SELECTION 调用代码>).我必须对
JFileChooser
做什么,以便在取消"按钮上按Enter"键相当于单击取消"按钮?
I have a JFileChooser
in a JFrame
. I've added an ActionListener
to the JFileChooser
so that the "Cancel" button works when clicked. I can also tab to the "Cancel" button, but when I then hit the "Enter" key, nothing happens (i.e., the ActionListener
isn't called with the event command JFileChooser.CANCEL_SELECTION
). What must I do with the JFileChooser
so that hitting the "Enter" key when on the "Cancel" button is equivalent to clicking on the "Cancel" button?
这是我看到的(错误)行为的一个简单示例:
Here's a simple example of the (mis)behavior I'm seeing:
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();
}
}
});
}
}
要查看(错误)行为,请执行程序,使用 Tab 键选择取消",然后按Enter"键.该程序不会在我的平台上终止——尽管当我单击取消"按钮时它会终止.
To see the (mis)behavior, execute the program, tab to "Cancel", and then hit the "Enter" key. The program doesn't terminate on my platform -- although it does when I click on the "Cancel" button.
扩展 JFileChooser
和覆盖 cancelSelection()
也不起作用(显然,当在取消"按钮).
Extending JFileChooser
and overriding cancelSelection()
also doesn't work (apparently, that function isn't called when the "Enter" key is hit while on the "Cancel" button).
(错误)行为发生在我的 Fedora 10 x86_64 系统上,使用 Java 5、6 和 7.
The (mis)behavior occurs on my Fedora 10 x86_64 system with Java 5, 6, and 7.
ADDENDUM:以下将 KeyEventPostProcessor
添加到当前 KeyboardFocusManager
并且似乎可以执行我想要的操作:
ADDENDUM: The following adds a KeyEventPostProcessor
to the current KeyboardFocusManager
and appears to do what I want:
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();
}
}
});
}
}
然而,这似乎需要做很多工作,只是为了能够区分按下取消"按钮上的回车键和其他任何地方.
It seems like a lot of work, however, just to be able to distinguish between hitting the enter key on the "Cancel" button versus anywhere else.
你觉得它有什么问题吗?
Do you see any problems with it?
发现的解决方案:将 GUI 外观设置为我的系统 (Linux) 的本机外观和感觉可以满足我的需求,而无需其他任何东西.这是我所不知道的,也是我一直在寻找的.解决方案是有以下
DISCOVERED SOLUTION: Setting the GUI Look and Feel to the native one for my system (Linux) does what I want without the need for anything else. This is what I was ignorant of and what I was looking for. The solution is to have the following
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
作为 main()
方法的第一个可执行语句.然后可以省去所有焦点侦听器、关键事件处理器等.
as the first executable statement of the main()
method. One can then dispense with all focus listeners, key event processors, etc.
我已将 100 分奖励给最有帮助的受访者.
I've awarded the 100 points to the most helpful respondent.
推荐答案
程序不会在我的平台上终止.
The program doesn't terminate on my platform.
我看到在 Mac OS X 10.5、Ubuntu 10 和 Windows 7 上使用(各种)Java 5 和 6 正常运行.我用 println()
exit()> 观看活动:
I see normal operation on Mac OS X 10.5, Ubuntu 10 and Windows 7 using (variously) Java 5 and 6. I replaced your exit()
with println()
to see the event:
System.out.println(rootDirChooser.getSelectedFile().getName() + e.paramString());
指定您的平台和版本可能会有所帮助;如果可能,还要验证安装是否正确.
It may help to specify your platform and version; if possible, verify correct installation as well.
我不确定我是否理解您的目标;但是,作为替代方案,请考虑覆盖 approveSelection()
:
I'm not sure I understand your goal; but, as an alternative, consider overriding approveSelection()
:
private static class MyChooser extends JFileChooser {
@Override
public void approveSelection() {
super.approveSelection();
System.out.println(this.getSelectedFile().getName());
}
}
附录:
目标是让在取消"按钮上按Enter"键的操作与单击取消"按钮的操作相同.
The goal is to have the action of hitting the "Enter" key while on the "Cancel" button be identical to clicking on the "Cancel" button.
如 键绑定中所述a>,您可以更改与 VK_ENTER
关联的操作.
As discussed in Key Bindings, you can change the action associated with VK_ENTER
.
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
InputMap map = chooser.getInputMap(JFileChooser.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
map.put(enter, "cancelSelection");
如果您希望仅在取消"按钮具有焦点时发生更改,您需要在 焦点监听器.
If you want the change to occur only while the "Cancel" button has focus, you'll need to do it in a Focus Listener.
附录:
我找到了一个使用 KeyboadFocusManager
的解决方案.你怎么看?
I found a solution that uses
KeyboadFocusManager
, instead. What do you think?
我可以看到优点&各方面的缺点,所以我在下面概述了两者.使用 KeyboadFocusManager
可以找到所有按钮,但没有提供独立于区域设置的方法来区分它们;Focus Listener
方法只能看到批准按钮,并且是特定于 UI 的.不过,您可以结合这些方法以获得更好的结果.第二意见不会有问题.
I can see pros & cons each way, so I've outlined both below. Using KeyboadFocusManager
finds all buttons, but offers no locale independent way to distinguish among them; the Focus Listener
approach can only see the approve button, and it's UI specific. Still, you might combine the approaches for better results. A second opinion wouldn't be out of order.
附录:
我更新了下面的代码,不再需要知道取消"按钮的本地化名称并使用键绑定.
I've updated the code below to eliminate the need to know the localized name of the "Cancel" button and use key bindings.
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();
}
});
}
}
相关文章