【问题标题】:How to act upon hitting "Enter" when on "Cancel" button in JFileChooser?如何在 JFileChooser 中的“取消”按钮上按“Enter”时采取行动?
【发布时间】:2011-03-23 16:04:38
【问题描述】:

我在JFrame 中有一个JFileChooser。我在JFileChooser 中添加了一个ActionListener,以便单击“取消”按钮时起作用。我也可以选择“取消”按钮,但是当我按下“Enter”键时,什么也没有发生(即,ActionListener 没有被事件命令JFileChooser.CANCEL_SELECTION 调用)。我必须如何处理JFileChooser,以便在“取消”按钮上按“Enter”键等同于单击“取消”按钮?

这是我看到的(错误)行为的一个简单示例:

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

要查看(错误)行为,请执行程序,选择“取消”,然后按“Enter”键。该程序不会在我的平台上终止——尽管当我点击“取消”按钮时它会终止。

扩展JFileChooser 和覆盖cancelSelection() 也不起作用(显然,当在“取消”按钮上按下“Enter”键时不会调用该函数)。

(错误)行为发生在我的 Fedora 10 x86_64 系统上,使用 Java 5、6 和 7。

附录:以下内容将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 分奖励给最有帮助的受访者。

【问题讨论】:

  • 谢谢,我很高兴有机会研究这个有趣的问题。这不是默认的 L&F 吗?
  • @trashgod 默认 L&F 取决于 OS/JVM 组合:对于 Linux 或 Solaris 和 Sun 的 JVM,它是 Java(跨平台)L&F;对于 Windows/Sun,它是 Windows L&F;对于 Mac OS/X 和 Mac 的 JVM,它是 Mac L&F。请参阅 download.oracle.com/javase/tutorial/uiswing/lookandfeel/…> 了解更多信息。

标签: java swing keyboard look-and-feel jfilechooser


【解决方案1】:

程序不会在我的平台上终止。

我看到使用(各种)Java 5 和 6 在 Mac OS X 10.5、Ubuntu 10 和 Windows 7 上正常运行。我将您的 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();
            }
        });
    }
}

【讨论】:

  • 如果您单击“取消”按钮,则程序将终止。目标是在“取消”按钮上按“Enter”键的操作与单击“取消”按钮相同。
  • @Steve Emmerson:Mac OS 上的 aqua L&F 似乎不像其他 L&F 那样实现文件选择器键绑定。
  • @stacker:VirtualBox 让它太容易了,但现在我有 三个 系统需要修补。 :-)
  • @trashgod 根据取消键是否具有焦点来更改与回车键关联的操作似乎有点多。我找到了一个使用 KeyboadFocusManager 的解决方案。你怎么看?
  • @Steve Emmerson:我已经在上面回复了,但我没有看到你的KeyEventPostProcessor。知道哪个按钮是哪个按钮也有同样的问题。
猜你喜欢
  • 2020-04-09
  • 1970-01-01
  • 2021-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多