如何在Swing中的两个按钮上添加“默认按钮”功能?

时间:2011-09-15 12:19:10

标签: java swing awt

在每个窗口/面板中,我将Enter键映射为defaultButton(意味着即使按下的按钮未对焦,按Enter也会触发按钮按下)。我需要做的是将Escape键映射到另一个按钮,该按钮也会触发第二个按钮,无论焦点如何。输入键的代码是:

// We get the button
IButton iButton = (IButton)actionToolbar.getComponent(actionToolbar.getComponentCount() - 1);
// We get the window
Window window = SwingUtilities.getWindowAncestor(this);
// Only these two types of windows should have this behaviour
if (window instanceof JFrame) {
    ((JFrame)window).getRootPane().setDefaultButton(iButton);
}
else if (window instanceof JDialog) {
    ((JDialog)window).getRootPane().setDefaultButton(iButton);
}

现在我需要的是基本相同的代码,但是改变了Enter with Escape,或者添加了一个监听器....我不确定是什么。

编辑:我必须在Java 1.4中执行此操作,我知道如果我立即说出来会很棒。

4 个答案:

答案 0 :(得分:4)

JXRootPane(SwingX项目)默认情况下,您可以执行类似

的操作
private void installKeyboardActions() {
    Action escAction = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent evt) {
            JButton cancelButton = getCancelButton();
            if (cancelButton != null) {
                cancelButton.doClick(20);
            }
        }

        /**
         * Overridden to hack around #566-swing: 
         * JXRootPane eats escape keystrokes from datepicker popup.
         * Disable action if there is no cancel button.<p>
         * 
         * That's basically what RootPaneUI does - only not in 
         * the parameterless isEnabled, but in the one that passes
         * in the sender (available in UIAction only). We can't test 
         * nor compare against core behaviour, UIAction has
         * sun package scope. <p>
         * 
         * Cont'd (Issue #1358-swingx: popup menus not closed)
         * The extended hack is inspired by Rob Camick's
         * <a href="http://tips4java.wordpress.com/2010/10/17/escape-key-and-dialog/"> Blog </a>
         * and consists in checking if the the rootpane has a popup's actionMap "inserted". 
         * NOTE: this does not work if the popup or any of its children is focusOwner.
         */
        @Override
        public boolean isEnabled() {
            Component component = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
            if (component instanceof JComponent) {
                Action cancelPopup = ((JComponent)component).getActionMap().get("cancel");
                if (cancelPopup != null) return false;
            }
            return (cancelButton != null) && (cancelButton.isEnabled());
        }
    };
    getActionMap().put("esc-action", escAction);
    InputMap im = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
    im.put(key, "esc-action");
}


/**
 * Sets the <code>cancelButton</code> property,
 * which determines the current default cancel button for this <code>JRootPane</code>.
 * The cancel button is the button which will be activated 
 * when a UI-defined activation event (typically the <b>ESC</b> key) 
 * occurs in the root pane regardless of whether or not the button 
 * has keyboard focus (unless there is another component within 
 * the root pane which consumes the activation event,
 * such as a <code>JTextPane</code>).
 * For default activation to work, the button must be an enabled
 * descendant of the root pane when activation occurs.
 * To remove a cancel button from this root pane, set this
 * property to <code>null</code>.
 *
 * @param cancelButton the <code>JButton</code> which is to be the cancel button
 * @see #getCancelButton() 
 *
 * @beaninfo
 *  description: The button activated by default for cancel actions in this root pane
 */
public void setCancelButton(JButton cancelButton) { 
    JButton old = this.cancelButton;

    if (old != cancelButton) {
        this.cancelButton = cancelButton;

        if (old != null) {
            old.repaint();
        }
        if (cancelButton != null) {
            cancelButton.repaint();
        } 
    }

    firePropertyChange("cancelButton", old, cancelButton);        
}

/**
 * Returns the value of the <code>cancelButton</code> property. 
 * @return the <code>JButton</code> which is currently the default cancel button
 * @see #setCancelButton
 */
public JButton getCancelButton() { 
    return cancelButton;
}

答案 1 :(得分:1)

或另一种非常简单的方法

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class ExampleKeyStrokes {

    private JFrame frame = new JFrame();
    private JButton button;

    public ExampleKeyStrokes() {
        button = new JButton(new AbstractAction(" push ENTER ") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        button.setText(" Please push ENTER ");
        //button.setPreferredSize(new Dimension(200, 50));
        frame.add(button);
        frame.getRootPane().setDefaultButton(button);
        frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F2"), "clickButton");
        frame.getRootPane().getActionMap().put("clickButton", new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                button.doClick();
            }
        });
        frame.setLocation(150, 150);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        setFocusButton();
    }

    private void setFocusButton() {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                button.grabFocus();
                button.requestFocus();
                button.requestFocusInWindow();
            }
        });
    }

    static public void main(String[] s) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ExampleKeyStrokes eKS = new ExampleKeyStrokes();
            }
        });
    }
}

答案 2 :(得分:1)

我设法通过向打开的面板添加一个键监听器来解决这个问题,比如

InputMap iMap = theTaskWindow.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
     iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
     ActionMap aMap = theTaskWindow.getRootPane().getActionMap();
     aMap.put("escape", new AbstractAction() {
      private static final long serialVersionUID = 1L;
      public void actionPerformed(ActionEvent e){
        doCancel();
      }
     });

答案 3 :(得分:-1)

这样做:

window.getContentPane().registerKeyboardAction(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            onCancel();
        }
    }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

你的第二个JButton也应该在点击时调用onCancel()。因此,无论是按下逃生还是点击这两个都会做同样的事情。