Swing:当按下ESC键时,我该如何关闭对话框?

66

使用Swing进行GUI开发。

我有一个用于在应用程序中选择要打开的文件的自定义对话框; 它的类扩展了javax.swing.JDialog,其中包含了一个JFileChooser,该组件可以切换显示或隐藏。

JFileChooser 组件已经通过自身处理 ESC 键:当文件选择器被显示时(嵌入在我的对话框中),并且我按下 ESC 键,文件选择器就会隐藏。

现在我希望我的对话框也能这样做:当我按下 ESC 键时,我希望对话框关闭。请注意,当嵌入式文件选择器被显示时,ESC 键仅应将其隐藏。

有任何想法吗?

5个回答

74
您可以使用以下片段。这样做更好,因为rootPane将获取对话框中任何组件的事件。如果需要,您可以将setVisible(false)替换为dispose()。
public static void addEscapeListener(final JDialog dialog) {
    ActionListener escListener = new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            dialog.setVisible(false);
        }
    };

    dialog.getRootPane().registerKeyboardAction(escListener,
            KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
            JComponent.WHEN_IN_FOCUSED_WINDOW);

}

听起来不错。我只是会用一些代码来实际取消对话框,而不是使用dialog.setVisible(false)。我会试一试的。 - Leonel

66

使用InputMapActionMap处理Swing中的键动作。为了干净地关闭对话框,请向其发送窗口关闭事件。

来自我现在已经停止运行的网络日志:

private static final KeyStroke escapeStroke = 
    KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); 
public static final String dispatchWindowClosingActionMapKey = 
    "com.spodding.tackline.dispatch:WINDOW_CLOSING"; 
public static void installEscapeCloseOperation(final JDialog dialog) { 
    Action dispatchClosing = new AbstractAction() { 
        public void actionPerformed(ActionEvent event) { 
            dialog.dispatchEvent(new WindowEvent( 
                dialog, WindowEvent.WINDOW_CLOSING 
            )); 
        } 
    }; 
    JRootPane root = dialog.getRootPane(); 
    root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 
        escapeStroke, dispatchWindowClosingActionMapKey 
    ); 
    root.getActionMap().put( dispatchWindowClosingActionMapKey, dispatchClosing 
    ); 
}

3
@Tom 你好,感谢您的精彩文章。请问一下,如果对话框中有任何基于文本的组件,您能告诉我最佳实践是什么吗?因为如果焦点在它们上面,它们将无法起作用。请翻译。 - pratikabu

17
如果您正在寻找一种使用Java 8新特性的技术,请尝试使用Lambda表达式:
dialog.getRootPane().registerKeyboardAction(e -> {
    window.dispose();
}, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);

或者
KeyStroke k = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
int w = JComponent.WHEN_IN_FOCUSED_WINDOW;
dialog.getRootPane().registerKeyboardAction(e -> window.dispose(), k, w);

4

我在实现前两个答案时遇到了问题。以下是一种相当紧凑的版本,使用 AbstractAction 自动实现大多数 Action 方法,在基于文本的字段中有效(根据 @pratikabu 的要求):

final AbstractAction escapeAction = new AbstractAction() {
    private static final long serialVersionUID = 1L;

    @Override
    public void actionPerformed(ActionEvent ae) {
        dispose();
    }
};

getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
        .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE_KEY");
getRootPane().getActionMap().put("ESCAPE_KEY", escapeAction);

参考文献


(注:本文为IT技术相关内容,以上为参考文献)

1
给其他人的小提示。我发现如果你不将escapeAction设置为final,就会出现异常。我的IDE没有显示它必须是final。异常在运行时显示。 - kevto

2

这是我的设置,我也将 CtrlW 设置为结束快捷键。

    Action closeAction = new AbstractAction(){
        public void actionPerformed(ActionEvent e){
            dispose();
        }
    };

    KeyStroke esc = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(esc, "closex");
    getRootPane().getActionMap().put("closex", closeAction);

    KeyStroke ctrlW = KeyStroke.getKeyStroke("control W");
    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ctrlW, "close");
    getRootPane().getActionMap().put("close", closeAction); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接