【问题标题】:Swing: how do I close a dialog when the ESC key is pressed?Swing:按下 ESC 键时如何关闭对话框?
【发布时间】:2010-10-13 04:15:25
【问题描述】:

使用 Swing 进行 GUI 开发。

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

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

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

有什么想法吗?

【问题讨论】:

    标签: java user-interface swing


    【解决方案1】:

    使用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 
        ); 
    }
    

    【讨论】:

    • @Tom 你好,感谢你的精彩帖子,如果我在对话框中有任何文本库组件,你能否告诉我最佳实践。因为如果焦点在他们身上就行不通了。
    【解决方案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); 
    

    【讨论】:

      【解决方案3】:

      如果您正在寻找使用 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);
        

        参考文献

        【讨论】:

        • 给别人的小记。我发现如果你不做escapeActionfinal,那么你会得到一个例外。我的 IDE 中没有显示它必须是 final。运行时出现异常。
        【解决方案5】:

        你可以使用下面的sn-p。这更好,因为 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) 以实际取消对话框。我试试看。
        猜你喜欢
        • 1970-01-01
        • 2020-05-05
        • 1970-01-01
        • 1970-01-01
        • 2012-08-18
        • 2015-01-08
        • 1970-01-01
        • 2011-11-22
        • 1970-01-01
        相关资源
        最近更新 更多